如何构造PKCS 7签名(二)

  1. signerInfos
    signerInfos是每个签名者信息的集合。它是最复杂也是最重要的部分,其定义如下:

SignerInfos:=Set of SignerInfo
Set of SignerInfo
SignerInfo::= SEQUENCE {
version Version,
issuerAndSerialNumber IssuerAndSerialNumber,
digestAlgorithm DigestAlgorithmIdentifier,
authenticatedAttributes[0] IMPLICIT Attributes OPTIONAL,
digestEncryptionAlgorithmDigestEncryptionAlgorithmIdentifier,
encryptedDigestEncryptedDigest,
unauthenticatedAttributes[1] IMPLICIT Attributes OPTIONAL
}

示例代码如下,先创建集合signerinfos

CInnerObject signerinfos; //签名者信息

hr=signerinfos.CreateInstance();

hr=signerinfos->put_Tag(TAG_SET);

_handle_result2();

hr=sdata->AddItem(signerinfos,&datasize);

_handle_result2();

CInnerObject signerdata;

hr=signerdata.CreateInstance();

_handle_result2();

hr=signerdata->put_Tag(TAG_SEQUENCE);

hr=signerinfos->AddItem(signerdata,&datasize); //单用户签名,signerinfos //只有一个元素signerdata

_handle_result2();

接下来为SignerInfo类型元素设置每个属性。

CInnerObject signerprop;

6.1 version

首先是版本号属性,也是固定为1.

hr=signerprop.CreateInstance(); //5.1 版本

hr=signerdata->AddItem(signerprop,&datasize);

_handle_result2();

hr=ver.Create(1); //设置为1

hr=signerprop->SetInteger(ver);

_handle_result2();

6.2 issuerAndSerialNumber

接下来是签名证书的签发者标识及序列号,定义如下。

IssuerAndSerialNumber::= SEQUENCE {
issuer Name,
serialNumber CertificateSerialNumber
}

示例代码

hr=signerprop.CreateInstance(); //签名证书的签发者标识及序列号

hr=signerprop->put_Tag(TAG_SEQUENCE);

hr=signerdata->AddItem(signerprop,&datasize);

_handle_result2();

CInnerObject propdata;

hr=propdata.CreateInstance();

LONG len=pCertContext->pCertInfo->Issuer.cbData;

if (!ml.Allocat(len))

return E_OUTOFMEMORY;

::memcpy(ml.GetBuffer(),pCertContext->pCertInfo->Issuer.pbData,len);//签发者标识

hr=ml.get_IStream(&pStm);

hr=propdata->Load(pStm);

_handle_result2();

hr=signerprop->AddItem(propdata,&datasize);

_handle_result2();

hr=propdata.CreateInstance();

len=pCertContext->pCertInfo->SerialNumber.cbData;

eseals::CBigIntegerPtr sm;

hr=sm.Create(pCertContext->pCertInfo->SerialNumber.pbData,len,false,true);

hr=propdata->SetInteger(sm);

_handle_result2();

hr=signerprop->AddItem(propdata,&datasize);

_handle_result2();

6.3 digestAlgorithm

第三个属性是摘要算法标识,这里要与digestAlgorithms里的某一元素一致。

hr=signerprop.CreateInstance(); //摘要算法标识

hr=signerprop->put_Tag(TAG_SEQUENCE);

hr=signerdata->AddItem(signerprop,&datasize);

_handle_result2();

hr=propdata.CreateInstance();

//SM3算法

hr=propdata->put_ObjectIdentifier(CharToWchar(szOID_SM3_Hash_Algorithm));

_handle_result2();

hr=signerprop->AddItem(propdata,&datasize);

_handle_result2();

6.4 authenticatedAttributes

authenticatedAttributes可以被叫做用户认证属性集合元素,定义如下:

Attributes ::= SET OF Attribute
Attribute ::= SEQUENCE
{
type EncodedObjectID,
values AttributeSetValue
}
这个元素是可选的,但如果contentInfo的ContentType不是数据内容(PKCS7 DATA)类型时,这个元素必须有。如果这个元素存在,它至少得有两个子元素:原文类型属性和原文摘要属性
。示例代码里设置了三个属性:原文类型属性、时间属性和原文摘要属性。

hr=signerprop.CreateInstance(); //用户认证属性

hr=signerprop->put_Tag(TAG_SET); //这时的signerprop对于要添加的属性数据来 //讲是集合,所以tag要先设置成TAG_SET

_handle_result2();

//------------------------------------------------------------------------

hr=propdata.CreateInstance(); //原文类型

hr=propdata->put_Tag(TAG_SEQUENCE);

hr=signerprop->AddItem(propdata,&datasize);

_handle_result2();

CInnerObject pdata;

hr=pdata.CreateInstance();

//属性标识为“原文类型”:“1.2.840.113549.1.9.3”

hr=pdata->put_ObjectIdentifier(CharToWchar(szOID_RSA_contentType));

hr=propdata->AddItem(pdata,&datasize);

CInnerObject set;

hr=set.CreateInstance();

hr=set->put_Tag(TAG_SET);

hr=propdata->AddItem(set,&datasize);

_handle_result2();

hr=pdata.CreateInstance();

hr=pdata->put_ObjectIdentifier(CharToWchar(szOID_PKCS_7_DATA)); //属性值PKCS7 DATA

_handle_result2();

hr=set->AddItem(pdata,&datasize);

_handle_result2();

//------------------------------------------------------------------------

hr=propdata.CreateInstance(); //签名时间

hr=propdata->put_Tag(TAG_SEQUENCE);

hr=signerprop->AddItem(propdata,&datasize);

_handle_result2();

hr=pdata.CreateInstance();

//属性标识为“签名时间”:“1.2.840.113549.1.9.5”

hr=pdata->put_ObjectIdentifier(CharToWchar(szOID_RSA_signingTime));

hr=propdata->AddItem(pdata,&datasize);

hr=set.CreateInstance();

hr=set->put_Tag(TAG_SET);

hr=propdata->AddItem(set,&datasize);

_handle_result2();

hr=pdata.CreateInstance();

SYSTEMTIME st;

::GetSystemTime(&st);

WCHAR time[MAX_PATH]=L"";

//ASN1_TIME格式

::_snwprintf(time,MAX_PATH,L"%02d%02d%02d%02d%02d%02d%s",(st.wYear%100),st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond,L"Z");

BSTR bstime = ::SysAllocString(time);

hr=pdata->put_Time(bstime); //时间值

_handle_result2();

hr=set->AddItem(pdata,&datasize);

_handle_result2();

//------------------------------------------------------------------------

hr=propdata.CreateInstance(); //原文摘要

hr=propdata->put_Tag(TAG_SEQUENCE);

hr=signerprop->AddItem(propdata,&datasize);

_handle_result2();

hr=pdata.CreateInstance();

//属性标识为“原文摘要”:“1.2.840.113549.1.9.4”

hr=pdata->put_ObjectIdentifier(CharToWchar(szOID_RSA_messageDigest));

hr=propdata->AddItem(pdata,&datasize);

hr=set.CreateInstance();

hr=set->put_Tag(TAG_SET);

hr=propdata->AddItem(set,&datasize);

_handle_result2();

hr=pdata.CreateInstance();

if (!ml.Allocat(ulDigestLen))

return E_OUTOFMEMORY;

::memcpy(ml.GetBuffer(),pbDigest,ulDigestLen); //原文摘要值,摘要值pbDigest //的计算过程没有列出

hr=ml.get_IStream(&pStm);

SAFEARRAY* parry;

hr=ml.get_SAFEARRAY(&parry);

hr=pdata->put_Tag(TAG_OCTETSTRING);

hr=pdata->put_Data(parry);

_handle_result2();

hr=set->AddItem(pdata,&datasize);

_handle_result2();

CMemoryLocator pbAuthedAttr; //将用户认证属性值保存到签名数据

hr=pbAuthedAttr.get_IStream(&pStm);

_handle_result2();

hr=signerprop->Save(pStm,FALSE);

_handle_result2();

hr=pbAuthedAttr.put_IStream(pStm);

_handle_result2();

hr=signerprop->put_Tag(TAG_OPT); //这时的signerprop对于要保存到SignerInfo //来讲是OPTIONAL,所以tag要设置成TAG_OPT

hr=signerdata->AddItem(signerprop,&datasize);

_handle_result2()

6.5 digestEncryptionAlgorithm

签名算法属性定义如下,与摘要算法一致。
DigestEncryptionAlgorithmIdentifier::= AlgorithmIdentifier

hr=signerprop.CreateInstance(); //签名算法

hr=signerprop->put_Tag(TAG_SEQUENCE);

hr=signerdata->AddItem(signerprop,&datasize);

_handle_result2();

hr=propdata.CreateInstance();

hr=propdata->put_ObjectIdentifier(_bstr_t(pCertContext->pCertInfo->SignatureAlgorithm.pszObjId)); //通过证书取得签名算法标识

_handle_result2();

hr=signerprop->AddItem(propdata,&datasize);

6.6 encryptedDigest

终于到了加密的摘要,也就是签名。定义如下

EncryptedDigest::= OCTET STRING
根据PKCS#7标准,如果没有authenticatedAttributes元素,这里的摘要指原文的摘要;否则就是authenticatedAttributes的摘要,这也是authenticatedAttributes名称的由来
。本示例包含代码属于后者。

CCryptoHandle hmHash(this->m_pDriverModule);

//摘要初始化

static const char*USER_ID=“1234567812345678”;

hr=skf::ParseErrorCode(this->m_pDriverModule->SKF_DigestInit(hDev,SGD_SM3,&eccPubKey,(BYTE*)USER_ID,strlen(USER_ID),&hmHash));

_handle_result2();

BYTE pbDigest2[32]={0};

//生成摘要

hr=skf::ParseErrorCode(this->m_pDriverModule->SKF_Digest(hmHash,pbAuthedAttr.GetBuffer(),pbAuthedAttr.GetSize(),pbDigest2,&ulDigestLen));

_handle_result2();

ECCSIGNATUREBLOB eccSignBlob;

//生成签名值

hr=skf::ParseErrorCode(this->m_pDriverModule->SKF_ECCSignData(hContainer,pbDigest2,ulDigestLen,&eccSignBlob));

_handle_result2();

这里的例子是用国密算法SKF库,所以如果对例子里的函数不了解没关系,只要知道过程即可。注意这里是对pbAuthedAttr计算摘要值。接下来根据国密标准将签名结果进行ASN.1编码。

hr=signerprop.CreateInstance(); //签名值ASN.1编码

//根据国密标准进行转换,具体过程略

hr=signerdata->AddItem(signerprop,&datasize);

_handle_result2();

代码执行到这里,一开始创建的sig对象已经包含了完整的数字签名。但根据标准,还有一个unauthenticatedAttributes元素。

6.7 unauthenticatedAttributes

这个元素的定义与authenticatedAttributes一致,区别在于它不参与签名。所以一般用的很少。不过要注意,如果构造这个元素,它在SignerInfo里的tag值应该是TAG_OPT+1。示例就不再添加这个元素了。

最后,生成的签名结构如下:
如何构造PKCS 7签名(二)_第1张图片

你可能感兴趣的:(pkcs)