OpenSSL中文手册之X509库详解(未完待续)

  版权声明本文根据DragonKing牛,E-Mail:[email protected]发布在https://openssl.126.com的系列文章整理修改而成(这个网站已经不能访问了),我自己所做的工作主要是针对新的1.0.2版本进行验证,修改错别字,和错误,重新排版,以及整理分类,配图。 未经作者允许,严禁用于商业出版,否则追究法律责任。网络转载请注明出处,这是对原创者的起码的尊重!!!


1 X509概述

  提到X509就不得不提到X500协议族。如下:

  • X.500 包括了DAP DSP DISP DOP, 是用于目录服务的一系列规范、协议,用于解决国际电话、电报互联互通、邮件发送时的人员查找、身份认证等问题。
  • X.501 定义X.500协议族的数据模型
  • X.509 现在广泛用于X.500目录服务之外,作为公钥证书的标准格式
  • X.520 定义X.500协议族数据模型的attributes
  • X.521定义X.500协议族数据模式的object class

  X.509是国际标准化组织CCITT建议作为X.500目录检索的一部分提供安全目录检索服务。一份X.509证书是一些标准字段的集合,这些字段包含有关用户或设备及其相应公钥的信息一种非常通用的证书格式,所有的证书都符合X.509 国际标准。目前X.509有不同的版本,例如 X.509 V2和x.509 v3都是目前比较新的版本,2000年还推出V4版本,但是都在原有版本基础上进行功能的扩充,其中每一版本必须包含下列信息:

  • Version ——X509的版本号
  • Serial Number——证书序列号
  • Signature algorithm ——签名所使用的算法,就是指的这个数字证书的对指纹进行签名时所使用的加密算法,这样就可以使用证书发布机构的证书里面的公钥,根据这个算法对签名进行解密。指纹(也叫hash值)摘要后再用私钥加密结果就是数字签名。
  • Signature hash algorithm——签名哈希算法
  • Issuer—— 证书的发布机构,指出是什么机构发布的这个证书,也就是指明这个证书是哪个公司创建的(只是创建证书,不是指证书的使用者)。
  • Valid from , Valid to——证书的有效期,也就是证书的有效时间,或者说证书的使用期限。 过了有效期限,证书就会作废,不能使用了。
  • Subject (主题)——这个证书是发布给谁的,或者说证书的所有者,一般是某个人或者某个公司名称、机构的名称、公司网站的网址等。
Country Name (2 letter code)[XX]:cn--------国家
State or Province Name (full name)[]:ning---------省份
Locality Name (eg, city) [DefaultCity]:ning--------------地区名字
Organization Name (eg, company)[Default Company Ltd]:ning------公司名
Organizational Unit Name (eg,section) []:ning-----部门
Common Name (eg, your name or yourserver's hostname) []:wukui----CA主机名
Email Address []:---------邮箱
Please enter the following 'extra'attributes
to be sent with your certificaterequest
A challenge password []:-----------证书请求密钥,CA读取证书的时候需要输入密码
An optional company name[]:-----------公司名称,CA读取证书的时候需要输入名称
  • Public key (公钥)——这个我们在前面介绍公钥密码体制时介绍过,公钥是用来对消息进行加密的。

  • Thumbprint, Thumbprint algorithm (指纹以及指纹算法)——这个是用来保证证书的完整性的,也就是说确保证书没有被修改过。 其原理就是在发布证书时,发布者根据摘要算法(一个hash算法)计算整个证书的hash值(也叫指纹)并用私钥加密后成为签名和证书放在一起,使用者在打开证书时,先用公钥解密签名,获得指纹,然后自己根据摘要算法计算一下证书的hash值(指纹),如果和附带的指纹对的上,就说明证书没有被修改过,因为证书的内容被修改后,根据证书的内容计算的出的hash值(指纹)是会变化的。

  X.509证书和PGP证书之间有许多不同,最明显的如下所述:

  • 用户可以创建自己的PGP证书,但是必须向CA请求才能得到一份X.509证书。
  • X.509证书天生只支持密钥拥有者的一个名字。
  • X.509证书只支持证明密钥合法性的一个数字签名。

  要获得一份X.509证书,必须请求CA发给你证书。用户提供自己的公钥,并提供有关自己的某些特定信息。然后在这些信息上用私钥做数字签名,并将整个数据包(称为证书请求)发给CA。CA做一些努力来验证用户提供的信息是正确的,然后就生成证书并返回给用户。

  OpenSSL对的主要工作就是对证书的操作,包括:

  • 证书请求管理
  • 证书生成
  • 证书吊销及CRL管理
  • X509名字管理
  • 属性管理
  • 扩展管理
  • 验证及信任管理

2 证书请求管理

2.1 基本数据结构

  证书请求用到了两个重要的数据结构:证书请求信息结构X509_REQ_INFO与证书请求结构X509_REQ,二者的定义如下:

typedef struct X509_req_info_st
{
    ASN1_ENCODING enc;
    ASN1_INTEGER *version;
    X509_NAME *subject;
    X509_PUBKEY *pubkey;
    /* d=2 hl=2 l= 0 cons: cont: 00 */
    STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */
} X509_REQ_INFO;

  其中version就是版本号、subject就是主题(常用的是dn)、pubkey是事先生成的公钥、attributes是一系列的属性,用于表达证书主题的额外信息,细节参见PKCS#10与PKCS#9。

typedef struct X509_req_st
{
    X509_REQ_INFO *req_info;
    X509_ALGOR *sig_alg;
    ASN1_BIT_STRING *signature;
    int references;
} X509_REQ;

  其中req_info就是上面所说的证书请求信息、sig_alg是签名使用的算法比如md5WithRSAEncryption、signature就是签名值了。

2.2基本操作函数

  这些基本的操作函数主要是对证书请求项进行设置与读取操作,它的的定义如下:其中的X509_REQ* req参数指的是要操作的X509_REQ对象,下面不再赘述。

int       X509_REQ_set_version(X509_REQ *x,long version);
int       X509_REQ_set_subject_name(X509_REQ *req,X509_NAME*name); 
int       X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey);
EVP_PKEY* X509_REQ_get_pubkey(X509_REQ *req);
          X509_REQ_extract_key(a)

int       X509_REQ_verify(X509_REQ *a, EVP_PKEY *r);
int       X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, constEVP_MD *md);

【X509_REQ_set_version】
   设置版本号, version就是版本号。

【X509_REQ_set_subject_name】

   该函数设置证书请求人的主题名,X509_NAME *name参数就是要设置的主题名。对于名字的操作到时会有一个专题来讲。

【X509_REQ_set_pubkey】
  设置公钥,EVP_PKEY *pkey参数就是生成好的公钥,可以通过RSA_generate_key()来生成。比如:

EVP_PKEY *pNewRsaKey;
int GenerateRSAKeyPair(char* szKeyLength)
{
  if(strlen(szKeyLength)==0) 
      return -1;
  int keylength=atoi(szKeyLength);
  if((pNewRsaKey=EVP_PKEY_new()) == NULL) 
      return CA_FAIL;
  int ret = EVP_PKEY_assign_RSA(pNewRsaKey,RSA_generate_key(keylength,0x10001,NULL,  NULL)); 
  if(ret!= 1) 
      return CA_FAIL;
  return CA_OK;
}

【X509_REQ_get_pubkey】
  读取X509_REQ中的公钥信息,返回的是一个EVP_PKEY对象,X509_REQ_extract_key()是它的一个宏定义,功能相同。

【X509_REQ_sign】
  对X509_REQ中X509_REQ_INFO结构用pkey与md进行签名,并用算法标识与签名值填充X509_REQ中的sig_alg与signature域。成功返回字节数,失败返回0.

【X509_REQ_verify】
  与签名相对应,对签名进行验证,所以将公钥pkey传入就可以了。

2.3 证书请求的IO函数

   这些函数有两类:一类是将X509_REQ信息在文件或BIO抽象层上输入输出,另一类是在控制台上将X509_REQ信息进行显示。它们的函数定义如下:

X509_REQ* d2i_X509_REQ_fp(FILE *fp,X509_REQ **req);
int       i2d_X509_REQ_fp(FILE *fp,X509_REQ *req);

X509_REQ* d2i_X509_REQ_bio(BIO *bp,X509_REQ **req);
int       i2d_X509_REQ_bio(BIO *bp,X509_REQ *req);

int       X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflag, unsigned longcflag);
int       X509_REQ_print(BIO *bp,X509_REQ *req);
int       X509_REQ_print_fp(FILE *fp, X509_REQ *x)

【d2i_X509_REQ_fp】
  将证书请求从文件中读入并转化成X509_REQ内部结构。

【i2d_X509_REQ_fp】
  将X509_REQ对象进行DER编码输出,并写入fp指定的文件中。

【d2i_X509_REQ_bio】
  功能与d2i_X509_REQ_fp相同,只是读的时候从BIO抽象层上读,你可以将它与文件相关联就可以了。

【i2d_X509_REQ_bio】
   功能与i2d_X509_REQ_fp相同,只是写的时候从BIO抽象层上写,你可以将它与文件或者内存BIO相关联就可以输出了。

【X509_REQ_print】
  将X509_REQ在BIO上输出,但输入是可以读的,比如Subject=XXX等。其实底层就是调用X509_REQ_print_ex来实现的。

【X509_REQ_print_ex】
  这个函数与X509_REQ_print的区别是可以用标志去控制输出,nmflags用于控制显示方式,cflag用于控制哪些不显示,可以按自己的需要进行定制。它们的定义在x509.h里。具体如下:

#define X509_FLAG_COMPAT 0
#define X509_FLAG_NO_HEADER 1L
#define X509_FLAG_NO_VERSION (1L << 1)
#define X509_FLAG_NO_SERIAL (1L << 2)
#define X509_FLAG_NO_SIGNAME (1L << 3)
#define X509_FLAG_NO_ISSUER (1L << 4)
#define X509_FLAG_NO_VALIDITY (1L << 5)
#define X509_FLAG_NO_SUBJECT (1L << 6)
#define X509_FLAG_NO_PUBKEY (1L << 7)
#define X509_FLAG_NO_EXTENSIONS (1L << 8)
#define X509_FLAG_NO_SIGDUMP (1L << 9)
#define X509_FLAG_NO_AUX (1L << 10)
#define X509_FLAG_NO_ATTRIBUTES (1L << 11)

【X509_REQ_print_fp】
  其实这个函数就是将可读的结果保存在文件里,内存就是生成一个BIO对象BIO_new(BIO_s_file(),然后再将文件句柄传给他BIO_set_fp(b,fp,BIO_NOCLOSE),再调用X509_REQ_print函数进行输出。这几个print函数,具体实现在crypto/asn1/t_req.c中。

2.4 证书请求的扩展项操作

  这些函数主要是对证书的请求的扩展项进行读取与设置操作,

    int   X509_REQ_extension_nid(int nid);
    int*  X509_REQ_get_extension_nids(void);
    void  X509_REQ_set_extension_nids(int *nids);

    STACK_OF(X509_EXTENSION)* X509_REQ_get_extensions(X509_REQ*req);

    int   X509_REQ_add_extensions_nid(X509_REQ *req,STACK_OF(X509_EXTENSION) *exts,int nid);
    int   X509_REQ_add_extensions(X509_REQ *req,STACK_OF(X509_EXTENSION) *exts);

【X509_REQ_extension_nid】
   判断nid是否已经在内部nid_list列表中定义了。未定义返回0,否则返回1。

【X509_REQ_get_extension_nids】
   返回已经定义的nid列表。

【X509_REQ_set_extension_nids】
   设置定义好的nid列表。

【X509_REQ_get_extensions】
   取出证书请求中的扩展项,过程是这样的,先从属性中将经过der编码的扩展项取出来,然后调用d2i_ASN1_SET_OF_X509_EXTENSION函数,将它转化成内部结构。

【X509_REQ_add_extensions】
   将定义好,且赋了值的X509_EXTENSION扩展项加入证书请求中(其实是加到属性中,这在以后讲)。

【X509_REQ_add_extensions_nid】
   功能与X509_REQ_add_extensions相同,只不过nid参数可以使用非标准的nid,其实X509_REQ_add_extensions就是通过调用这个函数是实现的,只不过使用了objects.h中定义的ExtensionRequest标准定义。

#define NID_ext_req 172

2.5 证书请求的其它相关操作

X509_REQ* X509_to_X509_REQ(X509 *x, EVP_PKEY *pkey, const EVP_MD *md);
X509 *    X509_REQ_to_X509(X509_REQ *r, int days,EVP_PKEY*pkey);

int   X509_REQ_digest(const X509_REQ *data,const EVP_MD*type,unsigned char *md, unsigned int *len);
X509_REQ* X509_REQ_dup(X509_REQ *req);

【X509_to_X509_REQ】
  用X509证书结构直接生成一个证书请求结构,其中x就是证书结构,pkey是公钥,md是散列算法,操作的过程就是将证书里的主题名与公钥填充到X509_REQ证书请求结构中,然后用指定的pkey与md进行签名,成功返回X509_REQ证书请求结构。

【X509_REQ_to_X509】
  从证书请求结构直接生成一个X509证书,其中的day就是证书的有效期(多少天),pkey就是用于签名的私钥。操作过程:从证书请求结构取出主题,将它填充到X509的主题与签发者中,取出公钥填充到X509公钥域里,有MD5与私钥进行签名,所以这样生成证书应用是一张自签名的证书。

【X509_REQ_digest】
  将X509_REQ用指定的散列算法type进行散列。结果在md中,len是结果的长度。

【X509_REQ_dup】
  复制一份X509_REQ结构。它是宏定义,实际上是由ASN1_dup函数来完成复制工作。


  版权声明本文根据DragonKing牛,E-Mail:[email protected]发布在https://openssl.126.com的系列文章整理修改而成(这个网站已经不能访问了),我自己所做的工作主要是针对新的1.0.2版本进行验证,修改错别字,和错误,重新排版,以及整理分类,配图。 未经作者允许,严禁用于商业出版,否则追究法律责任。网络转载请注明出处,这是对原创者的起码的尊重!!!


你可能感兴趣的:(OpenSSL中文手册)