无法解析OID友好名时,如何读取X.500相对辨别名?
处理X.500 RDN中的非通用标识符(俄文/英文INN、OGRN等)的跨平台解析问题
问题描述
我在处理数字签名时需要读取X.500相对辨别名(RDN),但主体名称包含俄罗斯特有的非通用标识符——比如俄文的ИНН、ОГРН、СНИЛС,或对应的英文INN、OGRN、SNILS等,遇到了以下解析问题:
- 从CAdES容器通过
SignedCms读取X500DistinguishedName对象时,直接对比自定义OID常量就能正常处理,没有问题 - 但如果是单独提供的友好名字符串,用
X500DistinguishedName(string)构造函数解析时,会出现跨环境兼容性问题:- 俄文名称在Windows本地能解析,但Linux容器等生产环境会抛出
System.Security.Cryptography.CryptographicException: No OID value matches this name.异常 - 英文名称因系统区域设置差异,本地机器也无法解析
- 部分环境中部分OID没有对应的友好名,无论俄文还是英文名称都无法匹配OID,导致解析失败
- 俄文名称在Windows本地能解析,但Linux容器等生产环境会抛出
我想知道:
- 是否存在可以跳过自动OID查找、以非严格方式读取X.500 RDN的API?要求能正确解析格式(分号、引号、换行等),同时不受OID匹配限制
- 有没有其他解决方案,比如添加多语言OID查找源?
我考虑过手动解析字符串,但担心自己写的解析逻辑有格式错误;也试过在传入构造函数前把友好名替换成OID.<identifier>,但怕误替换RDN的值。
示例
CAdES容器PEM格式
MIIHmAYJKoZIhvcNAQcCoIIHiTCCB4UCAQExDjAMBggqhQMHAQECAgUAMB8GCSqG SIb3DQEHAaASJIAEDEhlbGxvIGd1eXMNCgAAoIIE9zCCBPMwggSgoAMCAQICExIA ZO+nLuft0G9PuJwAAgBk76cwCgYIKoUDBwEBAwIwfzEjMCEGCSqGSIb3DQEJARYU c3VwcG9ydEBjcnlwdG9wcm8ucnUxCzAJBgNVBAYTAlJVMQ8wDQYDVQQHEwZNb3Nj b3cxFzAVBgNVBAoTDkNSWVBUTy1QUk8gTExDMSEwHwYDVQQDExhDUllQVE8tUFJP IFRlc3QgQ2VudGVyIDIwHhcNMjQwODI3MDczODM1WhcNMjQxMDI3MDc0ODM1WjCC AekxFTATBgUqhQNkBBIKMDkwNjIwOTQ5OTEWMBQGBSqFA2QDEgs2OTQ2Mzg3NDU2 OTEYMBYGBSqFA2QBEg01MDQ1MjIyNjUzMDg2MRowGAYIKoUDA4EDAQESDDg5NTAx NzQ4NDc1MDEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTELMAkGA1UE BhMCUlUxHDAaBgNVBAgMEzc3INCzLiDQnNC+0YHQutCy0LAxHDAaBgNVBAcME9Ch 0LDQvdC60YIt0KLQtdGB0YIxMzAxBgNVBAoMKtCe0J7QniAi0KLQtdGB0YLQvtCy 0LDRjyDQutC+0LzQv9Cw0L3QuNGPIjEtMCsGA1UECQwk0J3QsNCxLiDQotC10YHR gtC+0LLRgdC60LDRjywg0LQuIDI5MTIwMAYDVQQMDCnQotC10YHRgtC+0LLRi9C5 INGA0YPQutC+0LLQvtC00LjRgtC10LvRjDE0MDIGA1UEKgwr0JDQstGA0LXQu9C4 0Lkg0JrQvtC90YHRgtCw0L3RgtC40L3QvtCy0LjRhzEVMBMGA1UEBAwM0KLQtdGB 0YLQvtCyMTMwMQYDVQQDDCrQntCe0J4gItCi0LXRgdGC0L7QstCw0Y8g0LrQvtC8 0L/QsNC90LjRjyIwZjAfBggqhQMHAQEBATATBgcqhQMCAiMBBggqhQMHAQECAgND AARAJ5Tnn5/Y9VIaUPVExWxKWwLQiUg+EmRs1qzeCyAgNu1QiM1LZ9xDWnTNX7x7 dL0pihdqn7lRwQD6qQ7jnRYSoaOCAYAwggF8MA4GA1UdDwEB/wQEAwIE8DAdBgNV HSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwHQYDVR0OBBYEFOCaVoLHoz3yK5JH vJ9Q/dChqvJ5MB8GA1UdIwQYMBaAFBPuDprx4ItKrhkW78vExS2pGTcdMFwGA1Ud HwRVMFMwUaBPoE2GS2h0dHA6Ly90ZXN0Y2EuY3J5cHRvcHJvLnJ1L0NlcnRFbnJv bGwvQ1JZUFRPLVBSTyUyMFRlc3QlMjBDZW50ZXIlMjAyKDIpLmNybDCBrAYIKwYB BQUHAQEEgZ8wgZwwZAYIKwYBBQUHMAKGWGh0dHA6Ly90ZXN0Y2EuY3J5cHRvcHJv LnJ1L0NlcnRFbnJvbGwvdGVzdC1jYS0yMDE0X0NSWVBUTy1QUk8lMjBUZXN0JTIw Q2VudGVyJTIwMigyKS5jcnQwNAYIKwYBBQUHMAGGKGh0dHA6Ly90ZXN0Y2EuY3J5 cHRvcHJvLnJ1L29jc3Avb2NzcC5zcmYwCgYIKoUDBwEBAwIDQQBDe8OvSTVPAO5d t05bBTb/8496udYLS60cuC3Teq5Vr+zj77fx8+TRjpvxO7K2n5cJEvw5owSXYq2+ vH4qP5VIMYICUjCCAk4CAQEwgZYwfzEjMCEGCSqGSIb3DQEJARYUc3VwcG9ydEBj cnlwdG9wcm8ucnUxCzAJBgNVBAYTAlJVMQ8wDQYDVQQHEwZNb3Njb3cxFzAVBgNV BAoTDkNSWVBUTy1QUk8gTExDMSEwHwYDVQQDExhDUllQVE8tUFJPIFRlc3QgQ2Vu dGVyIDICExIAZO+nLuft0G9PuJwAAgBk76cwDAYIKoUDBwEBAgIFAKCCAVIwGAYJ KoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMjQwODI3MDc1 MTMxWjAvBgkqhkiG9w0BCQQxIgQgv3iAK5O+y+rh2rJDoPstHwMYFPL/HfQ2LqxR rm49WNYwgeYGCyqGSIb3DQEJEAIvMYHWMIHTMIHQMIHNMAoGCCqFAwcBAQICBCCN uZ99TEIPpysfzEgjaW0/vTrWmR5lHCn/gv42o6BOQjCBnDCBhKSBgTB/MSMwIQYJ KoZIhvcNAQkBFhRzdXBwb3J0QGNyeXB0b3Byby5ydTELMAkGA1UEBhMCUlUxDzAN BgNVBAcTBk1vc2NvdzEXMBUGA1UEChMOQ1JZUFRPLVBSTyBMTEMxITAfBgNVBAMT GENSWVBUTy1QUk8gVGVzdCBDZW50ZXIgMgITEgBk76cu5+3Qb0+4nAACAGTvpzAK BggqhQMHAQEBAQRAueXJ91COJM0XPnR5ZUmyj0Qsf+ltTswNGf2ZGXYL5Lw/AEVR kc1R7TnjhVBxKCGfw16WVZ6v2r+08AE4N3fybw==
俄文主体名称字符串
CN="ООО ""Тестовая компания""", SN=Тестов, G=Аврелий Константинович, Т=Тестовый руководитель, STREET="Наб. Тестовская, д. 29", O="ООО ""Тестовая компания""", L=Санкт-Тест, S=77 г. Москва, C=RU, E=test@example.com, ИНН=895017484750, ОГРН=5045222653086, СНИЛС=69463874569, ИНН ЮЛ=0906209499
英文主体名称字符串
CN="ООО ""Тестовая компания""", SN=Тестов, G=Аврелий Константинович, Т=Тестовый руководитель, STREET="Наб. Тестовская, д. 29", O="ООО ""Тестовая компания""", L=Санкт-Тест, S=77 г. Москва, C=RU, E=test@example.com, INN=895017484750, OGRN=5045222653086, SNILS=69463874569, INNLE=0906209499
解决方案
方案1:自定义OID映射,扩展系统OID解析表
.NET允许通过Oid.RegisterCustomOid方法注册自定义OID与友好名的映射,让系统直接识别俄文/英文的非通用标识符,无需修改原始字符串。
俄罗斯常用标识符的标准OID如下:
- ИНН/INN/ИНН ЮЛ/INNLE:
1.2.643.100.1(法人INN靠值的长度区分) - ОГРН/OGRN:
1.2.643.100.2 - СНИЛС/SNILS:
1.2.643.100.3
在应用启动时注册映射:
// 注册俄文友好名 Oid.RegisterCustomOid(new Oid("1.2.643.100.1", "ИНН")); Oid.RegisterCustomOid(new Oid("1.2.643.100.2", "ОГРН")); Oid.RegisterCustomOid(new Oid("1.2.643.100.3", "СНИЛС")); Oid.RegisterCustomOid(new Oid("1.2.643.100.1", "ИНН ЮЛ")); // 注册英文友好名 Oid.RegisterCustomOid(new Oid("1.2.643.100.1", "INN")); Oid.RegisterCustomOid(new Oid("1.2.643.100.2", "OGRN")); Oid.RegisterCustomOid(new Oid("1.2.643.100.3", "SNILS")); Oid.RegisterCustomOid(new Oid("1.2.643.100.1", "INNLE"));
注册后,X500DistinguishedName(string)构造函数就能在跨环境下正确解析这些标识符。
方案2:使用非严格解析的第三方库
如果不想依赖系统OID映射,可以用专注于ASN.1解析的第三方库SysadminsLV.Asn1Parser,它支持非严格模式读取DN,不强制OID匹配,直接解析结构。
使用示例:
using SysadminsLV.Asn1Parser; using SysadminsLV.PKI.Cryptography.X509Certificates; var dnString = "CN=\"ООО \"\"Тестовая компания\"\"\", ИНН=895017484750, ОГРН=5045222653086"; var dn = new X500DistinguishedName(dnString); // 遍历所有RDN条目 foreach (var rdn in dn.RawData.DecodeX500Rdn()) { foreach (var attr in rdn.Attributes) { Console.WriteLine($"{attr.Oid.FriendlyName ?? attr.Oid.Value}: {attr.Value}"); } }
即使OID没有友好名,库也会保留OID值和属性值,不会抛出异常。
方案3:安全替换友好名为OID字符串(避免误替换)
如果必须使用系统的X500DistinguishedName构造函数,可以用正则表达式仅替换RDN的属性名部分,避免误修改属性值:
using System.Text.RegularExpressions; string ReplaceFriendlyNamesWithOids(string dnString) { var replacements = new Dictionary<string, string> { {"ИНН", "1.2.643.100.1"}, {"ОГРН", "1.2.643.100.2"}, {"СНИЛС", "1.2.643.100.3"}, {"ИНН ЮЛ", "1.2.643.100.1"}, {"INN", "1.2.643.100.1"}, {"OGRN", "1.2.643.100.2"}, {"SNILS", "1.2.643.100.3"}, {"INNLE", "1.2.643.100.1"} }; foreach (var kvp in replacements) { // 仅匹配开头或逗号后的属性名,确保只替换属性名部分 dnString = Regex.Replace(dnString, $@"(^|, ){Regex.Escape(kvp.Key)}=", $"$1{kvp.Value}="); } return dnString; } // 使用示例 var originalDn = "CN=\"ООО \"\"Тестовая компания\"\"\", ИНН=895017484750"; var modifiedDn = ReplaceFriendlyNamesWithOids(originalDn); var x500Dn = new X500DistinguishedName(modifiedDn);
内容的提问来源于stack exchange,提问作者Dmitry Frolov
相关产品推荐
相关产品推荐

