04.12.2007 13:50:29Технология добавления detached подписи Ответов: 18
Волков
Расскажите пожалуйста технологию добавления detached подписи к уже существующей? Буду очень признателен.
 
Ответы:
05.12.2007 8:49:33info
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.
05.12.2007 9:42:37Волков
Боюсь показаться глупым, но прочитав ничего не понял, нельзя ли мне описать этот процесс по русски в кратце и с указанием используемых функций?
05.12.2007 9:50:22info
А вы в исходники примеров, которые на сайте лежат, посмотрите.
Там и функции есть и комментарии.
05.12.2007 10:29:49Волков
Тогда попробую конкретизировать проблему. Задача следующая организовать множественную подпись файлов. Как с добавлением данных в сообщение так и без этого. Если я подписал файл 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);
и добавляю подпись, но добавленная подпись не проверяетсяо! Почему так? Буду признателен за помощь.
05.12.2007 11:08:44Юрий
Вроде все в 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.

05.12.2007 12:14:30Волков
Юрий я и это пытался читать, не понимаю что я делаю не так. Есть возможность мне ответить?
05.12.2007 12:33:26Юрий
Что означает "добавленая подпись не проверяется"? Каким образом ее проверяют?
05.12.2007 12:55:38Юрий
Дабы конкретизировать вопрос - делается ли все так, как описано ниже:
1) CryptMsgOpenToDecode(..., CMSG_DETACHED_FLAG, ... )
2) CryptMsgUpdate( ..., TRUE) - загрузка значения подписи
3) CryptMsgUpdate( ..., FALSE) ... CryptMsgUpdate( ..., TRUE) - зарузка значений данных, на которых подпись будут проверять
4) CryptMsgControl( ..., CMSG_CTRL_VERIFY_SIGNATURE (EX), ...) - проверка подписи для заданого подписчика
05.12.2007 13:04:38Волков
Подпись проверяю следующим образом:
DWORD dwSignerIndex = 0;

MessageArray[0] = mem_tbs;
MessageSizeArray[0] = mem_len;

ret = CryptVerifyDetachedMessageSignature(
&param,
dwSignerIndex,
(const BYTE*) mem_signature,
signature_len,
1,
MessageArray,
MessageSizeArray,
&pUserCertTemp);
Первая подпись проверяется с индексом 1, а вот вторая с индексом 2 не проверяется ошибка NTE_BAD_SIGNATURE.
05.12.2007 13:12:36Юрий
А что насчет индекса "0" для первой подписи и "1" для второй?
05.12.2007 13:16:05Волков
Не знаю подписываю первый раз сертификатом №1 и когда ставлю индекс 1 то выводиться именно информация из сертификата №1, если делаю множественную atached подпись то наибольший индекс соответствует первой подписи.
05.12.2007 13:20:10Юрий
Попробуйте :)
Вообще-то индекс подписчиков всегда начинается с 0. Например при получении массива всех подписчиков с помощью CryptMsgGetParam(..., CMSG_SIGNER_INFO_PARAM, ...)
05.12.2007 13:24:38Волков
Дабы конкретизировать вопрос - делается ли все так, как описано ниже:
1) CryptMsgOpenToDecode(..., CMSG_DETACHED_FLAG, ... )
2) CryptMsgUpdate( ..., TRUE) - загрузка значения подписи
3) CryptMsgUpdate( ..., FALSE) ... CryptMsgUpdate( ..., TRUE) - зарузка значений данных, на которых подпись будут проверять
4) CryptMsgControl( ..., CMSG_CTRL_VERIFY_SIGNATURE (EX), ...) - проверка подписи для заданого подписчика

А в третьем пункте в первом вызове CryptMsgUpdate что передавать этой функции?
05.12.2007 13:30:25Юрий
В третьем пункте загружаются открытые данные, для которых и будет проверятся подпись (данные, на которых эту подпись создавали). Первый (и последующие) вызов CryptMsgUpdate(..., FALSE) соответствует загрузке НЕ последнего блока данных. Последний блок загружается как CryptMsgUpdate(..., TRUE)
05.12.2007 14:12:36Смирнов Павел
Ваши объяснения наводят на мысль, что вы пытаетесь добавить detached-подпись к уже существующему CMS-сообщению типа SignedData с одной присоединённой подписью. Получаемая таким образом detached-подпись относится не к исходному содержимому, а ко всему CMS-сообещнию, т.е. как бы одно CMS-сообщение вкладывается в другое. По исходным данным такая подпись не проверится.
05.12.2007 14:14:02Волков
Юрий большое спасибо!!!
05.12.2007 14:21:47Юрий
Приятно делать хорошие дела :)
05.12.2007 14:25:58Юрий
К Смирнову Павлу:

Смотря как сформировать добавляемую подпись. То, к чему относится добавляемая подпись, полностью относится к способу ее создания. Можно создать новую подпись для уже подписаного сообщения (исходные данные - кодированое CMS), либо создать новую подпись для открытых (начальных) данных и добавить ее в существующее CMS. Никаких ограничений нет.