李sir_Blog

博客园 首页 联系 订阅 管理

 1,解码CERT_INFO结构
   给定一个证书,第一步是调用函数CertCreateCertificateContext解码证书BLOB。当这个函数被调用,那么产生一个编码证书的复制品,创建一个CERT_CONETXT类型的结构和一个CERT_INFO类型的结构。一个certificate_context包含一个原始证书BLOB,一个CERT_CONETXT类型的结构以及一个CERT_INFO类型的结构。下面我们具体看看CERT_CONETXT以及CERT_INFO的结构(wincrypt.h):
  typedef struct _CERT_CONTEXT {
   DWORD dwCertEncodingType;
   BYTE *pbCertEncoded;
   DWORD cbCertEncoded;
   PCERT_INFO pCertInfo;
   HCERTSTORE hCertStore;
  } CERT_CONTEXT, *PCERT_CONTEXT;
  typedef const CERT_CONTEXT *PCCERT_CONTEXT;
  typedef struct _CERT_INFO {
   DWORD dwVersion;
   CRYPT_INTEGER_BLOB SerialNumber;
   CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
   CERT_NAME_BLOB Issuer;
   FILETIME NotBefore;
   FILETIME NotAfter;
   CERT_NAME_BLOB Subject;
   CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo;
   CRYPT_BIT_BLOB IssuerUniqueId;
   CRYPT_BIT_BLOB SubjectUniqueId;
   DWORD cExtension;
   PCERT_EXTENSION rgExtension;
  } CERT_INFO, *PCERT_INFO;
  typedef struct _CERT_EXTENSIONS {
   DWORD cExtension;
   PCERT_EXTENSION rgExtension;
  } CERT_EXTENSIONS, *PCERT_EXTENSIONS;
  由上面的三个结构可以明显的看出证书的存储过程。(具体参数意思可以由参数名看出来)
   2,编码一个CERT_INFO结构
   编码过程和解码过程是相反的,下面事例如何增加签发者到CERT_INFO结构中。
   1,创建一个包含签发者名字的字符串。
   2,创建一个CERT_RDN_ATTR结构的数组,它初始化后能够包含刚刚创建的字符串。
   3,创建一个CERT_RDN结构的数组,它包含刚刚初始化的CERT_RDN_ATTR结构的数组
   4,创建一个CERT_NAME_INFO结构指向刚刚创建的CERT_RDN结构的数组的指针
   5,调用CryptEncodeObject函数来获取输出编码后BLOB的长度。
   6,为BLOB分配内存空间
   7,再次调用CryptEncodeObject函数,将有关编码信息写入
   8,设置CERT_INFO结构中的Issuer.cbData为第5步得到的长度,设置Issuer.pbData为第6步得到的地址,那么现在签发者就存在于CERT_INFO结构中了。
   添加一个编码后的扩展信息到CERT_INFO结构中
   1,初始化一个扩展信息结构。
   2,调用CryptEncodeObject,来获取所需空间大小。
   3,分配空间
   4,再次调用CryptEncodeObject来获取编码后的信息。
   5,创建一个CERT_EXTENSION结构数组
   6,初始化CERT_EXTENSION,并且在CERT_EXTENSION中添加刚刚编码后的信息。
   7,初始化CERT_INFO结构的rgExtension,并且把他指向CERT_EXTENSION结构数组(

 

接上:

1.CERT_RDN_ATTR 结构体

typedef struct _CERT_RDN_ATTR {
LPSTR
pszObjId;
DWORD
dwValueType;
CERT_RDN_VALUE_BLOB
Value; } CERT_RDN_ATTR,
*PCERT_RDN_ATTR;
pszObjId:对象标识符,用于标识证书属性,具体可以查看MSDN中的解析,也可以查看wincrypt.h文件查看相应的定义。譬如szOID_STATE_OR_PROVINCE_NAME,表示省名。
dwValueType:对成员Value的解析,取值查看MSDN,当主要是初始化证书属性时,Value的值主要是一些字符串时,该值可以为CERT_RDN_PRINTABLE_STRING,表示可以打印的字符串。
Value:一个结构体,在这里初始化证书属性。
typedef struct _CRYPTOAPI_BLOB {
DWORD
cbData;
BYTE*
pbData; } ,其中cbData表示大小,pbData指向一个内存空间。
 
2.CERT_RDN 结构体:The CERT_RDN structure contains a relative distinguished name (RDN) consisting of an array of CERT_RDN_ATTR structures.
typedef struct _CERT_RDN {
DWORD
cRDNAttr;
PCERT_RDN_ATTR
rgRDNAttr; } CERT_RDN,
*PCERT_RDN;
参数:cRDNAttr:rgRDNAttr数组元素的个数;rgRDNAttr:指向CERT_RDN_ATTR结构元素的数组地址。
3.CERT_NAME_INFO 结构体:The CERT_NAME_INFO structure contains subject or issuer names.The information is represented as an array of CERT_RDN structures.
typedef struct _CERT_NAME_INFO {
DWORD
cRDN;
PCERT_RDN
rgRDN; } CERT_NAME_INFO,
*PCERT_NAME_INFO;
参数:同上差不多。
4.CERT_REQUEST_INFO 证书请求结构体:这个结构体包含证书请求的主体,主体公钥,属性块等信息,这些信息都是经过编码的。
typedef struct _CERT_REQUEST_INFO {
DWORD
dwVersion;
CERT_NAME_BLOB
Subject;
CERT_PUBLIC_KEY_INFO
SubjectPublicKeyInfo;
DWORD
cAttribute;
PCRYPT_ATTRIBUTE
rgAttribute; } CERT_REQUEST_INFO,
*PCERT_REQUEST_INFO;
 
参数:dwVersion:证书版本号,可以为CERT_V1等,根据属性扩展情况,符合不同版本证书;Subject:证书主题;SubjectPublicKeyInfo:证书主题中的公钥信息;cAttribute:rgAttribute数组元素个数,可以为0;rgAttribute:属性参数数组,可以为NULL;
以上信息都是要经过编码后的信息来填充的。
5.CryptSignAndEncodeCertificate函数,用来创建自签名证书
BOOL WINAPI CryptSignAndEncodeCertificate(
  __in          HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProvOrNCryptKey,
  __in          DWORD dwKeySpec,
  __in          DWORD dwCertEncodingType,
  __in          LPCSTR lpszStructType,
  __in          const void* pvStructInfo,
  __in          PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
  __in          const void* pvHashAuxInfo,
  __out         PBYTE pbEncoded,
  __in_out      DWORD* pcbEncoded
);
参数:1,CSP句柄;2,指明公钥是来自签名公钥还是交换公钥,可以为AT_KEYEXCHANGE或者AT_SIGNATURE之一;3,指明编码类型,可以为X509_ASN_ENCODING;4,结构体类型,和第5个参数配合起来使用,可以为X509_CERT_CRL_TO_BE_SIGNED或者X509_CERT_REQUEST_TO_BE_SIGNED或者X509_CERT_TO_BE_SIGNED或者X509_KEYGEN_REQUEST_TO_BE_SIGNED,意思可以查看MSDN。
6,签名算法结构体,指明签名算法,算法标识可以为szOID_RSA_MD5RSA 或者szOID_RSA_SHA1RSA 或者szOID_X957_SHA1DSA ;7,可以不用,设为NULL;8,签名后数据的长度,当设为NULL时,可以用来求数据的长度;9,用于存放数据的内存空间。
posted on 2010-10-04 18:11  李sir  阅读(699)  评论(0编辑  收藏  举报