X.509使用DN(Distinct Name)来唯一标识一个实体,其功能类似我们平常使用的ID,不过不同的是,DN不再是类似 123456 这样得数字标识,而是采用多个字段来标识一个实体,例如”CN=老所,C=CN”,这样做的好处在于方便匹配到诸如LDAP一样的目录服务中。那么,DN的字段是否可以随意增加呢?比如我能否在”CN=老所,O=测试公司”这样一个DN上再增加一个ID属性,变成”CN=老所,O=测试公司,ID=123456″呢?

动手测试。首先采用微软的 XEnroll 组件来进行测试。XEnroll 是微软平台下的 ActiveX 控件,提供证书的加入服务,比如创建 PKCS#10 证书请求。我们可以用 Javascript 来调用这个 ActiveX 控件:

var sOID = '';
var sDN = 'CN="老所",O="测试公司",ID="123456"';
alert(sDN);
var sPKCS10 = oXEnroll.createPKCS10(sDN, sOID);

其中,createPKCS10 函数接受两个参数,第一个是字符串类型的DN,第二个是用以标识该证书请求的用途的OID,这里,我们不在乎该证书的用途,所以就设为空好了。通过 IE 运行该段代码后,我得到了 object Error,看来,不能这样简单地添加DN字段。

于是开始搜索关于 X.509 DN 的信息。原来,X.509 证书里的 DN 属性,都是一些基于 ASN1 编码的对象,也就是说,对于我们熟知的 CN 属性,或者说 commonName 属性,程序是无法从证书里获得的,证书里是不会写诸如 CN=xxx 这样的信息的。所有字段都被表示为该字段类型的 OID 。OID 则是 ASN1 对象的统一表示方法,这种方法采用树状结构,由国际组织统一管理。一个公司如果要增加一个字段类型,并希望被广泛采用,它必须像管理 OID 的组织提出申请,就像我们常用的域名申请一样。

在 www.oid-info.com 这个网站,我们可以查询所有注册过的 OID 信息。这个网站提供两种方式的查询:按树状结构展开各级 OID,或者直接填写诸如”2.3.4″这样的 OID 来进行查询。

假如我们展开 2.5.4 这层 OID,我们就会发现很多我们常用的 DN 字段:

  • 2.5.4.3 - commonName
  • 2.5.4.4 - surname
  • 2.5.4.13 - description
  • 2.5.4.10 - organizationName
  • ……

既然如此,那我们就采用 OID 形式来添加属性类型吧,比如我使用 OID=2.5.4.888,这是一个未被注册的 OID,可以用来测试:

var sOID = '';
var sDN = 'CN="老所",O="测试公司",2.5.4.888="123456"';
alert(sDN);
var sPKCS10 = oXEnroll.createPKCS10(sDN, sOID);

运行该脚步,成功了,我们从机器里的证书申请库里找到该证书申请,查看其属性:

可以看出,虽然用 OID 添加属性成功了,但这个 OID 并不能被翻译成方便我们阅读的形式,就像我们只能使用 IP 而无法使用域名一样。要让该证书显示 ID= 而不是 2.5.4.888=,我们必须要:

  • 向标准组织注册 2.5.4.888 为 ID;
  • 通知微软,修改其 Windows 程序,将该 OID 翻译为 ID

显然,这非常不现实,呵呵。

接下来,我们再用 openssl 来测试一下。我选用的是 pyOpenSSL,一个 openssl 的 Python 包装库:

>>> from OpenSSL import crypto
>>> req = crypto.X509Req()
>>> subject = req.get_subject()
>>> setattr(subject, 'CN', 'soloman')
>>> setattr(subject, 'ID', '123456')
Traceback (most recent call last):
File "", line 1, in
AttributeError: No such attribute
>>>

看来,pyOpenSSL也只认识 CN,不认识 ID。查询了一下 pyopenssl 的源代码:

static int
crypto_X509Name_setattr(crypto_X509NameObj *self, char *name, PyObject *value)
{
int nid;
int result;
char *buffer;
if ((nid = OBJ_txt2nid(name)) == NID_undef)
{
PyErr_SetString(PyExc_AttributeError, "No such attribute");
return -1;
}
......

可以看出,pyOpenSSL 在设置 DN 的时候,首先调用 openssl 的 OBJ_txt2nid()函数来将方便我们记忆的对象名字翻译成 OID, 然后再翻译成 openssl 程序里自己的 NID。

那么继续查询 openssl 的源代码,在 objects.h 文件里我们找到了所有 DN 字段的定义:

......
#define SN_commonName           "CN"
#define LN_commonName           "commonName"
#define NID_commonName          13
#define OBJ_commonName          OBJ_X509,3L
#define SN_countryName          "C"
#define LN_countryName          "countryName"
#define NID_countryName         14
#define OBJ_countryName         OBJ_X509,6L
#define SN_localityName         "L"
#define LN_localityName         "localityName"
#define NID_localityName        15
#define OBJ_localityName        OBJ_X509,7L
......

这里,openssl 为每个常用的 DN 属性定义了4个内容:SN, LN, NID, OBJ。其中 SN 表示 Short Name, LN 表示 Long Name,都是一个 OID 方便我们阅读的名称的两个形式,而 OBJ 则定义了其 OID 信息。

在 openssl/crypto/asn1/a_strnid.c 这个文件里,绑定了 openssl 能够支持并翻译的 DN 字段:

static ASN1_STRING_TABLE tbl_standard[] = {
{NID_commonName,        1, ub_common_name, DIRSTRING_TYPE, 0},
{NID_countryName,       2, 2, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
{NID_localityName,      1, ub_locality_name, DIRSTRING_TYPE, 0},
{NID_stateOrProvinceName,   1, ub_state_name, DIRSTRING_TYPE, 0},
{NID_organizationName,      1, ub_organization_name, DIRSTRING_TYPE, 0},
{NID_organizationalUnitName,    1, ub_organization_unit_name, DIRSTRING_TYPE, 0},
{NID_pkcs9_emailAddress,    1, ub_email_address, B_ASN1_IA5STRING, STABLE_NO_MASK},
{NID_pkcs9_unstructuredName,    1, -1, PKCS9STRING_TYPE, 0},
{NID_pkcs9_challengePassword,   1, -1, PKCS9STRING_TYPE, 0},
{NID_pkcs9_unstructuredAddress, 1, -1, DIRSTRING_TYPE, 0},
{NID_givenName,         1, ub_name, DIRSTRING_TYPE, 0},
{NID_surname,           1, ub_name, DIRSTRING_TYPE, 0},
{NID_initials,          1, ub_name, DIRSTRING_TYPE, 0},
{NID_serialNumber,      1, ub_serial_number, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
{NID_friendlyName,      -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK},
{NID_name,          1, ub_name, DIRSTRING_TYPE, 0},
{NID_dnQualifier,       -1, -1, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
{NID_domainComponent,       1, -1, B_ASN1_IA5STRING, STABLE_NO_MASK},
{NID_ms_csp_name,       -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK}
};

可以看出,如果要让我们的基于 openssl 的程序支持一个我们自定义的属性,我们得修改 openssl 源代码,添加我们的新字段的”名称-OID” 绑定(可以只有Long Name),然后重新编译 openssl 和我们的程序,使其能使用新的属性。

我们回过头来想想,为什么标准化组织没有为我们提供一个类似 ID 这样的属性呢?这是因为,DN本来就是作为 ID 来使用的,它把一些属性绑定起来,来标识一个实体,如果再有一个通用的 ID 属性,逻辑上就冲突了。当然针对具体的应用,你可以注册一个特殊的 ID 属性,比如 openID ,但这需要实力雄厚的公司来进行注册和推广。

然而实际应用中,当我们想将证书系统与某个特别的应用中的某个 ID 进行绑定,而又不具备向国际组织进行 OID 注册和推广的能力时,我们完全可以利用现有的属性来进行实现,比如,针对这个需求,我可以设计出两个方案:

  • 方案一:CN=老所@123456
  • 方案二:CN=123456, surname=老, givenName=所
  • 方案三:CN=123456, name=老所
  • 方案四:CN=老所, description=123456

方案一,通过一定的方式,将用户的姓名和ID组合到CN里,然后在应用中解析出ID,这个方法不是很便于用户书写,用户在填写证书申请资料的时候必须注意符合该规范。

方案二与三的概念就是用CN来记录ID,毕竟,Common Name 嘛,随你如何定义。而用户的姓名由 surname + givenName 或者 name 来指定。该方法通过了 openssl 测试:

>>> req = crypto.X509Req()
>>> subject = req.get_subject()
>>> setattr(subject, 'surname', 'Lao')
>>> setattr(subject, 'givenName', 'Suo')
>>> setattr(subject, 'name', 'Lao Suo')

但是,XEnroll 仿佛不支持 surname + givenName 或者 name 属性,其文档上说明是支持 X.500 规范,而不是 X.509 规范。

方案四,则利用了 description 属性来记录和具体应用相关的讯息,比如我们的 ID,该方法通过了 openssll 的测试:

>>> req = crypto.X509Req()
>>> subject = req.get_subject()
>>> setattr(subject, 'CN', 'Lao Suo')
>>> setattr(subject, 'description', '123456')

和 XEnroll 的测试:

原文 http://blog.ipattern.org/archives/653

X.509证书DN之详解相关推荐

  1. ssh证书登录(实例详解)

    前言 本文基于实际Linux管理工作,实例讲解工作中使用ssh证书登录的实际流程,讲解ssh证书登录的配置原理,基于配置原理,解决实际工作中,windows下使用SecureCRT证书登录的各种问题, ...

  2. apns java 证书_APNS推送服务证书制作 图文详解教程(新)

    iOS消息推送的工作机制可以简单的用下图来概括: Provider是指某个iPhone软件的Push服务器,APNS是Apple Push Notification Service的缩写,是苹果的服务 ...

  3. 跨平台应用开发进阶(四十一)使用Xcode打包 iOS 应用 archive 时四种证书的区别详解

    文章目录 一.archive 四种模式 二.相同点 三.安装方式区别 四.iOS开发者账号(企业版)申请攻略 4.1 苹果开发者账号类型 4.2 企业版开发者账号的优势是什么? 4.3 企业版开发者账 ...

  4. Java面试详解(2020版):500+ 面试题和核心知识点详解

    与其在网上拼命的找面试题,不如加入我们畅快的阅读. 为了写好这些面试题,我先后拜访了一二十家互联网公司,与不同的面试官和面试者进行面对面探讨,深入了解了企业对于面试者的要求和常见的 Java 面试题型 ...

  5. iOS 开发 Certificate和Code Signing--证书与签名--详解

    iOS 开发 Certificate和Code Signing–证书与签名–详解 1.Certificate-证书 iOS 开发 证书–根证书/申请证书/开发(发布)证书–详解 2.Code Sign ...

  6. c语言 多线程 传话,code vs1506传话(塔尖)+tarjan图文详解

    1506 传话 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 白银 Silver 题目描述 Description 一个朋友网络,如果a认识b,那么如果a第一次收到某个消息,那么会 ...

  7. x.509数字证书编码详解

    转自:http://blog.sina.com.cn/s/blog_49b531af0102eahs.html x.509数字证书编码详解 一. X.509数字证书的编码 X.509证书的结构是用AS ...

  8. PKI详解与openssl实现私有CA证书签发

    加密解密技术基础 在看这篇文章之前,首先需要有加密解密的技术基础: 安全目标: 保密性:确保通信信息不被任何无关的人看到 完整性:实现通信双方的报文不丢失.数据完整性.系统完整性 可用性:通信任何一方 ...

  9. SSL之CA证书颁发机构安装图文详解

    上一节我们说到,在验证公钥安全性时,是在CA机构颁发的包含用户的公钥及其身份信息的数字证书,数字证书由权威机构--CA签发.这个CA权威机构可以是自己的服务器也可以是国际公认的CA权威机构.下面我就来 ...

最新文章

  1. CoreData的简单使用
  2. 深入理解神经网络之逻辑回归
  3. 【Linux系统编程应用】Linux音频编程接口
  4. 漫步者蓝牙驱动_2020年知乎最受欢迎的高性价比真无线蓝牙耳机推荐,轻松选择蓝牙耳机(9月最新)!...
  5. 洛谷——P1146 硬币翻转
  6. 【转】使用Boost Graph library(二)
  7. sas9.4安装教程
  8. 电磁兼容(EMC)标准结构的划分与分类
  9. 基于Java毕业设计新能源汽车租赁管理系统源码+系统+mysql+lw文档+部署软件
  10. 计算机辅助绘图包括,计算机辅助绘图实用教程
  11. Bootstrap登录页面带验证码
  12. oracle导入时 ora39166,expdp遭遇ORA-39166?
  13. 牛客练习赛43 回顾
  14. Naxx Central District 1 Ice dragon saffron
  15. 游戏建模你必须要掌握的六类软件
  16. 日期和时间函数DateAdd
  17. js实现人机猜拳游戏
  18. python公众号文章_python如何导出微信公众号文章
  19. CSS3 制作动态相册
  20. SAP那些事-理论篇-12-SAP五层体系介绍

热门文章

  1. 游戏设计的艺术:一本透镜的书——第二十五章 好的游戏是通过游戏测试做出来的
  2. Gank教学贴:Gank是一门艺术 不是固定的套路
  3. 【Python爬虫】 爬取京东商品图片并下载
  4. SpringMVC 的核心组件有哪些?
  5. 每日英语:As World's Kids Get Fatter, Doctors Turn To The Knife
  6. win10下装黑苹果双系统_电脑笔记本win10系统重装一体机W7苹果mac双系统远程维修8虚拟机...
  7. Linux各个发行版本代号整理
  8. 安全测试之SQL注入攻击
  9. Java学习_Day 02(学习内容:狂神说JAVA零基础P12-P17)
  10. 多径效应(时间色散、多普勒效应)及其他描述多径传播影响的参数(电平通过率、平均衰落时间)