| ||||
| ||||
Расскажите пожалуйста технологию добавления detached подписи к уже существующей? Буду очень признателен. | ||||
Ответы: | ||||
| ||||
RFC 3369 5. Signed-data Content Type The signed-data content type consists of a content of any type and zero or more signature values. Any number of signers in parallel can sign any type of content. The typical application of the signed-data content type represents one signer's digital signature on content of the data content type. Another typical application disseminates certificates and certificate revocation lists (CRLs). The process by which signed-data is constructed involves the following steps: 1. For each signer, a message digest, or hash value, is computed on the content with a signer-specific message-digest algorithm. If the signer is signing any information other than the content, the message digest of the content and the other information are digested with the signer's message digest algorithm (see Section 5.4), and the result becomes the "message digest." 2. For each signer, the message digest is digitally signed using the signer's private key. 3. For each signer, the signature value and other signer-specific information are collected into a SignerInfo value, as defined in Section 5.3. Certificates and CRLs for each signer, and those not corresponding to any signer, are collected in this step. 4. The message digest algorithms for all the signers and the SignerInfo values for all the signers are collected together with the content into a SignedData value, as defined in Section 5.1. A recipient independently computes the message digest. This message digest and the signer's public key are used to verify the signature value. The signer's public key is referenced either by an issuer distinguished name along with an issuer-specific serial number or by a subject key identifier that uniquely identifies the certificate containing the public key. The signer's certificate can be included in the SignedData certificates field. Housley Standards Track [Page 6] RFC 3369 Cryptographic Message Syntax August 2002 This section is divided into six parts. The first part describes the top-level type SignedData, the second part describes EncapsulatedContentInfo, the third part describes the per-signer information type SignerInfo, and the fourth, fifth, and sixth parts describe the message digest calculation, signature generation, and signature verification processes, respectively. 5.1 SignedData Type The following object identifier identifies the signed-data content type: id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 } The signed-data content type shall have ASN.1 type SignedData: SignedData ::= SEQUENCE { version CMSVersion, digestAlgorithms DigestAlgorithmIdentifiers, encapContentInfo EncapsulatedContentInfo, certificates [0] IMPLICIT CertificateSet OPTIONAL, crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, signerInfos SignerInfos } DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier SignerInfos ::= SET OF SignerInfo The fields of type SignedData have the following meanings: version is the syntax version number. The appropriate value depends on certificates, eContentType, and SignerInfo. The version MUST be assigned as follows: IF (certificates is present) AND (any version 2 attribute certificates are present) THEN version MUST be 4 ELSE IF ((certificates is present) AND (any version 1 attribute certificates are present)) OR (encapContentInfo eContentType is other than id-data) OR (any SignerInfo structures are version 3) THEN version MUST be 3 ELSE version MUST be 1 Housley Standards Track [Page 7] RFC 3369 Cryptographic Message Syntax August 2002 digestAlgorithms is a collection of message digest algorithm identifiers. There MAY be any number of elements in the collection, including zero. Each element identifies the message digest algorithm, along with any associated parameters, used by one or more signer. The collection is intended to list the message digest algorithms employed by all of the signers, in any order, to facilitate one-pass signature verification. Implementations MAY fail to validate signatures that use a digest algorithm that is not included in this set. The message digesting process is described in Section 5.4. encapContentInfo is the signed content, consisting of a content type identifier and the content itself. Details of the EncapsulatedContentInfo type are discussed in section 5.2. certificates is a collection of certificates. It is intended that the set of certificates be sufficient to contain chains from a recognized "root" or "top-level certification authority" to all of the signers in the signerInfos field. There may be more certificates than necessary, and there may be certificates sufficient to contain chains from two or more independent top- level certification authorities. There may also be fewer certificates than necessary, if it is expected that recipients have an alternate means of obtaining necessary certificates (e.g., from a previous set of certificates). The signer's certificate MAY be included. The use of version 1 attribute certificates is strongly discouraged. crls is a collection of certificate revocation lists (CRLs). It is intended that the set contain information sufficient to determine whether or not the certificates in the certificates field are valid, but such correspondence is not necessary. There MAY be more CRLs than necessary, and there MAY also be fewer CRLs than necessary. signerInfos is a collection of per-signer information. There MAY be any number of elements in the collection, including zero. The details of the SignerInfo type are discussed in section 5.3. Since each signer can employ a digital signature technique and future specifications could update the syntax, all implementations MUST gracefully handle unimplemented versions of SignerInfo. Further, since all implementations will not support every possible signature algorithm, all implementations MUST gracefully handle unimplemented signature algorithms when they are encountered. 5.4 Message Digest Calculation Process The message digest calculation process computes a message digest on either the content being signed or the content together with the signed attributes. In either case, the initial input to the message digest calculation process is the "value" of the encapsulated content being signed. Specifically, the initial input is the encapContentInfo eContent OCTET STRING to which the signing process is applied. Only the octets comprising the value of the eContent OCTET STRING are input to the message digest algorithm, not the tag or the length octets. The result of the message digest calculation process depends on whether the signedAttrs field is present. When the field is absent, the result is just the message digest of the content as described above. When the field is present, however, the result is the message digest of the complete DER encoding of the SignedAttrs value contained in the signedAttrs field. Since the SignedAttrs value, when present, must contain the content-type and the message-digest attributes, those values are indirectly included in the result. The content-type attribute MUST NOT be included in a countersignature unsigned attribute as defined in section 11.4. A separate encoding of the signedAttrs field is performed for message digest calculation. The IMPLICIT [0] tag in the signedAttrs is not used for the DER encoding, rather an EXPLICIT SET OF tag is used. That is, the DER encoding of the EXPLICIT SET OF tag, rather than of the IMPLICIT [0] tag, MUST be included in the message digest calculation along with the length and content octets of the SignedAttributes value. When the signedAttrs field is absent, only the octets comprising the value of the signedData encapContentInfo eContent OCTET STRING (e.g., the contents of a file) are input to the message digest calculation. This has the advantage that the length of the content being signed need not be known in advance of the signature generation process. Housley Standards Track [Page 13] RFC 3369 Cryptographic Message Syntax August 2002 Although the encapContentInfo eContent OCTET STRING tag and length octets are not included in the message digest calculation, they are protected by other means. The length octets are protected by the nature of the message digest algorithm since it is computationally infeasible to find any two distinct message contents of any length that have the same message digest. 5.5 Signature Generation Process The input to the signature generation process includes the result of the message digest calculation process and the signer's private key. The details of the signature generation depend on the signature algorithm employed. The object identifier, along with any parameters, that specifies the signature algorithm employed by the signer is carried in the signatureAlgorithm field. The signature value generated by the signer MUST be encoded as an OCTET STRING and carried in the signature field. 5.6 Signature Verification Process The input to the signature verification process includes the result of the message digest calculation process and the signer's public key. The recipient MAY obtain the correct public key for the signer by any means, but the preferred method is from a certificate obtained from the SignedData certificates field. The selection and validation of the signer's public key MAY be based on certification path validation (see [PROFILE]) as well as other external context, but is beyond the scope of this document. The details of the signature verification depend on the signature algorithm employed. The recipient MUST NOT rely on any message digest values computed by the originator. If the SignedData signerInfo includes signedAttributes, then the content message digest MUST be calculated as described in section 5.4. For the signature to be valid, the message digest value calculated by the recipient MUST be the same as the value of the messageDigest attribute included in the signedAttributes of the SignedData signerInfo. If the SignedData signerInfo includes signedAttributes, then the content-type attribute value MUST match the SignedData encapContentInfo eContentType value. | ||||
| ||||
Боюсь показаться глупым, но прочитав ничего не понял, нельзя ли мне описать этот процесс по русски в кратце и с указанием используемых функций? | ||||
| ||||
А вы в исходники примеров, которые на сайте лежат, посмотрите. Там и функции есть и комментарии. | ||||
| ||||
Тогда попробую конкретизировать проблему. Задача следующая организовать множественную подпись файлов. Как с добавлением данных в сообщение так и без этого. Если я подписал файл atached подписью, то добавляю подпись следующим образом hMsg = CryptMsgOpenToDecode( MY_ENCODING_TYPE, 0, 0, 0, 0, 0); if(!hMsg) { MessageBox(NULL,"CryptMsgOpenToDecode() failed","Îøèáêà",MB_OK|MB_ICONERROR); return; } if (!CryptMsgUpdate( hMsg, mem_signature, //áóôåð ñ ïðî÷èòàííîé ïîäïèñüþ signature_len, //äëèííà ïðî÷èòàííîé ïîäïèñè true)) { MessageBox(NULL,"Error CryptMsgUpdate","Îøèáêà",MB_OK|MB_ICONERROR); return; } CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm; memset(&HashAlgorithm, 0, sizeof(CRYPT_ALGORITHM_IDENTIFIER)); HashAlgorithm.pszObjId = szOID_CP_GOST_R3411; CMSG_SIGNER_ENCODE_INFO signerInfo; memset(&signerInfo, 0, sizeof(CMSG_SIGNER_ENCODE_INFO)); signerInfo.cbSize = sizeof(CMSG_SIGNER_ENCODE_INFO); signerInfo.pCertInfo = pSignerCert->pCertInfo; signerInfo.hCryptProv = hCryptProvCheck; signerInfo.cAuthAttr = 0; signerInfo.cUnauthAttr = 0; signerInfo.dwKeySpec = dwKeySpecCheck; signerInfo.HashAlgorithm = HashAlgorithm; signerInfo.pvHashAuxInfo = NULL; signerInfo.rgAuthAttr = NULL; signerInfo.rgUnauthAttr = NULL; if (!CryptMsgControl( hMsg, 0, CMSG_CTRL_ADD_SIGNER, &signerInfo)) { MessageBox(NULL,"Error CryptMsgControl1","Îøèáêà",MB_OK|MB_ICONERROR); return; } И Подпись нормально проверяется как первая так и вторая. В функции CryptMsgOpenToDecode вторым параметром можно указать atached или detached подпись, устанавливаю его т.е. открываю соощение следующим образом: CryptMsgOpenToDecode( MY_ENCODING_TYPE, CMSG_DETACHED_FLAG, 0, 0, 0, 0); и добавляю подпись, но добавленная подпись не проверяетсяо! Почему так? Буду признателен за помощь. | ||||
| ||||
Вроде все в MSDN написано: -------------------------- CryptMsgUpdate The CryptMsgUpdate function adds contents to a cryptographic message. The use of this function allows messages to be constructed piece by piece through repetitive calls of CryptMsgUpdate. The added message content is either encoded or decoded depending on whether the message was opened with CryptMsgOpenToEncode or CryptMsgOpenToDecode. BOOL WINAPI CryptMsgUpdate( HCRYPTMSG hCryptMsg, const BYTE* pbData, DWORD cbData, BOOL fFinal ); Parameters hCryptMsg [in] Cryptographic message handle of the message to be updated. pbData [in] Pointer to the buffer holding the data to be encoded or decoded. cbData [in] Number of bytes of data in the pbData buffer. fFinal [in] Indicates that the last block of data for encoding or decoding is being processed. Correct usage of this flag is dependent upon whether the message being processed has detached data. The inclusion of detached data in a message is indicated by setting dwFlags to CMSG_DETACHED_FLAG in the call to the function that opened the message. If CMSG_DETACHED_FLAG was not set and the message was opened using either CryptMsgOpenToDecode or CryptMsgOpenToEncode, fFinal is set to TRUE, and CryptMsgUpdate is only called once. If the CMSG_DETACHED_FLAG flag was set and a message is opened using CryptMsgOpenToEncode, fFinal is set to TRUE only on the last call to CryptMsgUpdate. If the CMSG_DETACHED_FLAG flag was set and a message is opened using CryptMsgOpenToDecode, fFinal is set to TRUE when the header is processed by a single call to CryptMsgUpdate. It is set to FALSE while processing the detached data in subsequent calls to CryptMsgUpdate until the last detached data block is to be processed. On the last call to CryptMsgUpdate, it is set to TRUE. When detached data is decoded, the header and the content of a message are contained in different BLOBs. Each BLOB requires that fFinal be set to TRUE when the last call to the function is made for that BLOB. | ||||
| ||||
Юрий я и это пытался читать, не понимаю что я делаю не так. Есть возможность мне ответить? | ||||
| ||||
Что означает "добавленая подпись не проверяется"? Каким образом ее проверяют? | ||||
| ||||
Дабы конкретизировать вопрос - делается ли все так, как описано ниже: 1) CryptMsgOpenToDecode(..., CMSG_DETACHED_FLAG, ... ) 2) CryptMsgUpdate( ..., TRUE) - загрузка значения подписи 3) CryptMsgUpdate( ..., FALSE) ... CryptMsgUpdate( ..., TRUE) - зарузка значений данных, на которых подпись будут проверять 4) CryptMsgControl( ..., CMSG_CTRL_VERIFY_SIGNATURE (EX), ...) - проверка подписи для заданого подписчика | ||||
| ||||
Подпись проверяю следующим образом: DWORD dwSignerIndex = 0; MessageArray[0] = mem_tbs; MessageSizeArray[0] = mem_len; ret = CryptVerifyDetachedMessageSignature( ¶m, dwSignerIndex, (const BYTE*) mem_signature, signature_len, 1, MessageArray, MessageSizeArray, &pUserCertTemp); Первая подпись проверяется с индексом 1, а вот вторая с индексом 2 не проверяется ошибка NTE_BAD_SIGNATURE. | ||||
| ||||
А что насчет индекса "0" для первой подписи и "1" для второй? | ||||
| ||||
Не знаю подписываю первый раз сертификатом №1 и когда ставлю индекс 1 то выводиться именно информация из сертификата №1, если делаю множественную atached подпись то наибольший индекс соответствует первой подписи. | ||||
| ||||
Попробуйте :) Вообще-то индекс подписчиков всегда начинается с 0. Например при получении массива всех подписчиков с помощью CryptMsgGetParam(..., CMSG_SIGNER_INFO_PARAM, ...) | ||||
| ||||
Дабы конкретизировать вопрос - делается ли все так, как описано ниже: 1) CryptMsgOpenToDecode(..., CMSG_DETACHED_FLAG, ... ) 2) CryptMsgUpdate( ..., TRUE) - загрузка значения подписи 3) CryptMsgUpdate( ..., FALSE) ... CryptMsgUpdate( ..., TRUE) - зарузка значений данных, на которых подпись будут проверять 4) CryptMsgControl( ..., CMSG_CTRL_VERIFY_SIGNATURE (EX), ...) - проверка подписи для заданого подписчика А в третьем пункте в первом вызове CryptMsgUpdate что передавать этой функции? | ||||
| ||||
В третьем пункте загружаются открытые данные, для которых и будет проверятся подпись (данные, на которых эту подпись создавали). Первый (и последующие) вызов CryptMsgUpdate(..., FALSE) соответствует загрузке НЕ последнего блока данных. Последний блок загружается как CryptMsgUpdate(..., TRUE) | ||||
| ||||
Ваши объяснения наводят на мысль, что вы пытаетесь добавить detached-подпись к уже существующему CMS-сообщению типа SignedData с одной присоединённой подписью. Получаемая таким образом detached-подпись относится не к исходному содержимому, а ко всему CMS-сообещнию, т.е. как бы одно CMS-сообщение вкладывается в другое. По исходным данным такая подпись не проверится. | ||||
| ||||
Юрий большое спасибо!!! | ||||
| ||||
Приятно делать хорошие дела :) | ||||
| ||||
К Смирнову Павлу: Смотря как сформировать добавляемую подпись. То, к чему относится добавляемая подпись, полностью относится к способу ее создания. Можно создать новую подпись для уже подписаного сообщения (исходные данные - кодированое CMS), либо создать новую подпись для открытых (начальных) данных и добавить ее в существующее CMS. Никаких ограничений нет. | ||||