2 * Copyright 2007 Juan Lang
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/debug.h"
25 #include "wine/exception.h"
26 #include "crypt32_private.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
30 /* Called when a message's ref count reaches zero. Free any message-specific
33 typedef void (*CryptMsgCloseFunc
)(HCRYPTMSG msg
);
35 typedef BOOL (*CryptMsgGetParamFunc
)(HCRYPTMSG hCryptMsg
, DWORD dwParamType
,
36 DWORD dwIndex
, void *pvData
, DWORD
*pcbData
);
38 typedef BOOL (*CryptMsgUpdateFunc
)(HCRYPTMSG hCryptMsg
, const BYTE
*pbData
,
39 DWORD cbData
, BOOL fFinal
);
41 typedef enum _CryptMsgState
{
47 typedef struct _CryptMsgBase
52 CMSG_STREAM_INFO stream_info
;
54 CryptMsgCloseFunc close
;
55 CryptMsgUpdateFunc update
;
56 CryptMsgGetParamFunc get_param
;
59 static inline void CryptMsgBase_Init(CryptMsgBase
*msg
, DWORD dwFlags
,
60 PCMSG_STREAM_INFO pStreamInfo
, CryptMsgCloseFunc close
,
61 CryptMsgGetParamFunc get_param
, CryptMsgUpdateFunc update
)
64 msg
->open_flags
= dwFlags
;
68 memcpy(&msg
->stream_info
, pStreamInfo
, sizeof(msg
->stream_info
));
72 msg
->streamed
= FALSE
;
73 memset(&msg
->stream_info
, 0, sizeof(msg
->stream_info
));
76 msg
->get_param
= get_param
;
78 msg
->state
= MsgStateInit
;
81 typedef struct _CDataEncodeMsg
84 DWORD bare_content_len
;
88 static const BYTE empty_data_content
[] = { 0x04,0x00 };
90 static void CDataEncodeMsg_Close(HCRYPTMSG hCryptMsg
)
92 CDataEncodeMsg
*msg
= (CDataEncodeMsg
*)hCryptMsg
;
94 if (msg
->bare_content
!= empty_data_content
)
95 LocalFree(msg
->bare_content
);
98 static WINAPI BOOL
CRYPT_EncodeContentLength(DWORD dwCertEncodingType
,
99 LPCSTR lpszStructType
, const void *pvStructInfo
, DWORD dwFlags
,
100 PCRYPT_ENCODE_PARA pEncodePara
, BYTE
*pbEncoded
, DWORD
*pcbEncoded
)
102 const CDataEncodeMsg
*msg
= (const CDataEncodeMsg
*)pvStructInfo
;
106 /* Trick: report bytes needed based on total message length, even though
107 * the message isn't available yet. The caller will use the length
108 * reported here to encode its length.
110 CRYPT_EncodeLen(msg
->base
.stream_info
.cbContent
, NULL
, &lenBytes
);
112 *pcbEncoded
= 1 + lenBytes
+ msg
->base
.stream_info
.cbContent
;
115 if ((ret
= CRYPT_EncodeEnsureSpace(dwFlags
, pEncodePara
, pbEncoded
,
116 pcbEncoded
, 1 + lenBytes
)))
118 if (dwFlags
& CRYPT_ENCODE_ALLOC_FLAG
)
119 pbEncoded
= *(BYTE
**)pbEncoded
;
120 *pbEncoded
++ = ASN_OCTETSTRING
;
121 CRYPT_EncodeLen(msg
->base
.stream_info
.cbContent
, pbEncoded
,
128 static BOOL
CRYPT_EncodeDataContentInfoHeader(CDataEncodeMsg
*msg
,
129 CRYPT_DATA_BLOB
*header
)
133 if (msg
->base
.streamed
&& msg
->base
.stream_info
.cbContent
== 0xffffffff)
135 FIXME("unimplemented for indefinite-length encoding\n");
137 header
->pbData
= NULL
;
142 struct AsnConstructedItem constructed
= { 0, msg
,
143 CRYPT_EncodeContentLength
};
144 struct AsnEncodeSequenceItem items
[2] = {
145 { szOID_RSA_data
, CRYPT_AsnEncodeOid
, 0 },
146 { &constructed
, CRYPT_AsnEncodeConstructed
, 0 },
149 ret
= CRYPT_AsnEncodeSequence(X509_ASN_ENCODING
, items
,
150 sizeof(items
) / sizeof(items
[0]), CRYPT_ENCODE_ALLOC_FLAG
, NULL
,
151 (LPBYTE
)&header
->pbData
, &header
->cbData
);
154 /* Trick: subtract the content length from the reported length,
155 * as the actual content hasn't come yet.
157 header
->cbData
-= msg
->base
.stream_info
.cbContent
;
163 static BOOL
CDataEncodeMsg_Update(HCRYPTMSG hCryptMsg
, const BYTE
*pbData
,
164 DWORD cbData
, BOOL fFinal
)
166 CDataEncodeMsg
*msg
= (CDataEncodeMsg
*)hCryptMsg
;
169 if (msg
->base
.streamed
)
173 if (msg
->base
.state
!= MsgStateUpdated
)
175 CRYPT_DATA_BLOB header
;
177 ret
= CRYPT_EncodeDataContentInfoHeader(msg
, &header
);
180 ret
= msg
->base
.stream_info
.pfnStreamOutput(
181 msg
->base
.stream_info
.pvArg
, header
.pbData
, header
.cbData
,
183 LocalFree(header
.pbData
);
187 ret
= msg
->base
.stream_info
.pfnStreamOutput(
188 msg
->base
.stream_info
.pvArg
, (BYTE
*)pbData
, cbData
,
192 if (msg
->base
.stream_info
.cbContent
== 0xffffffff)
194 BYTE indefinite_trailer
[6] = { 0 };
196 ret
= msg
->base
.stream_info
.pfnStreamOutput(
197 msg
->base
.stream_info
.pvArg
, (BYTE
*)pbData
, cbData
,
200 ret
= msg
->base
.stream_info
.pfnStreamOutput(
201 msg
->base
.stream_info
.pvArg
, indefinite_trailer
,
202 sizeof(indefinite_trailer
), TRUE
);
205 ret
= msg
->base
.stream_info
.pfnStreamOutput(
206 msg
->base
.stream_info
.pvArg
, (BYTE
*)pbData
, cbData
, TRUE
);
211 SetLastError(STATUS_ACCESS_VIOLATION
);
219 if (msg
->base
.open_flags
& CMSG_DETACHED_FLAG
)
220 SetLastError(E_INVALIDARG
);
222 SetLastError(CRYPT_E_MSG_ERROR
);
227 SetLastError(E_INVALIDARG
);
230 CRYPT_DATA_BLOB blob
= { cbData
, (LPBYTE
)pbData
};
232 /* non-streamed data messages don't allow non-final updates,
233 * don't bother checking whether data already exist, they can't.
235 ret
= CryptEncodeObjectEx(X509_ASN_ENCODING
, X509_OCTET_STRING
,
236 &blob
, CRYPT_ENCODE_ALLOC_FLAG
, NULL
, &msg
->bare_content
,
237 &msg
->bare_content_len
);
244 static BOOL
CRYPT_CopyParam(void *pvData
, DWORD
*pcbData
, const BYTE
*src
,
251 else if (*pcbData
< len
)
254 SetLastError(ERROR_MORE_DATA
);
260 memcpy(pvData
, src
, len
);
265 static BOOL
CDataEncodeMsg_GetParam(HCRYPTMSG hCryptMsg
, DWORD dwParamType
,
266 DWORD dwIndex
, void *pvData
, DWORD
*pcbData
)
268 CDataEncodeMsg
*msg
= (CDataEncodeMsg
*)hCryptMsg
;
273 case CMSG_CONTENT_PARAM
:
274 if (msg
->base
.streamed
)
275 SetLastError(E_INVALIDARG
);
278 CRYPT_CONTENT_INFO info
;
279 char rsa_data
[] = "1.2.840.113549.1.7.1";
281 info
.pszObjId
= rsa_data
;
282 info
.Content
.cbData
= msg
->bare_content_len
;
283 info
.Content
.pbData
= msg
->bare_content
;
284 ret
= CryptEncodeObject(X509_ASN_ENCODING
, PKCS_CONTENT_INFO
, &info
,
288 case CMSG_BARE_CONTENT_PARAM
:
289 if (msg
->base
.streamed
)
290 SetLastError(E_INVALIDARG
);
292 ret
= CRYPT_CopyParam(pvData
, pcbData
, msg
->bare_content
,
293 msg
->bare_content_len
);
296 SetLastError(CRYPT_E_INVALID_MSG_TYPE
);
301 static HCRYPTMSG
CDataEncodeMsg_Open(DWORD dwFlags
, const void *pvMsgEncodeInfo
,
302 LPSTR pszInnerContentObjID
, PCMSG_STREAM_INFO pStreamInfo
)
308 SetLastError(E_INVALIDARG
);
311 msg
= CryptMemAlloc(sizeof(CDataEncodeMsg
));
314 CryptMsgBase_Init((CryptMsgBase
*)msg
, dwFlags
, pStreamInfo
,
315 CDataEncodeMsg_Close
, CDataEncodeMsg_GetParam
, CDataEncodeMsg_Update
);
316 msg
->bare_content_len
= sizeof(empty_data_content
);
317 msg
->bare_content
= (LPBYTE
)empty_data_content
;
319 return (HCRYPTMSG
)msg
;
322 typedef struct _CHashEncodeMsg
327 CRYPT_DATA_BLOB data
;
330 static void CHashEncodeMsg_Close(HCRYPTMSG hCryptMsg
)
332 CHashEncodeMsg
*msg
= (CHashEncodeMsg
*)hCryptMsg
;
334 CryptMemFree(msg
->data
.pbData
);
335 CryptDestroyHash(msg
->hash
);
336 if (msg
->base
.open_flags
& CMSG_CRYPT_RELEASE_CONTEXT_FLAG
)
337 CryptReleaseContext(msg
->prov
, 0);
340 static BOOL
CRYPT_EncodePKCSDigestedData(CHashEncodeMsg
*msg
, void *pvData
,
345 DWORD size
= sizeof(algID
);
347 ret
= CryptGetHashParam(msg
->hash
, HP_ALGID
, (BYTE
*)&algID
, &size
, 0);
350 CRYPT_DIGESTED_DATA digestedData
= { 0 };
351 char oid_rsa_data
[] = szOID_RSA_data
;
353 digestedData
.version
= CMSG_HASHED_DATA_PKCS_1_5_VERSION
;
354 digestedData
.DigestAlgorithm
.pszObjId
= (LPSTR
)CertAlgIdToOID(algID
);
355 /* FIXME: what about digestedData.DigestAlgorithm.Parameters? */
356 /* Quirk: OID is only encoded messages if an update has happened */
357 if (msg
->base
.state
!= MsgStateInit
)
358 digestedData
.ContentInfo
.pszObjId
= oid_rsa_data
;
359 if (!(msg
->base
.open_flags
& CMSG_DETACHED_FLAG
) && msg
->data
.cbData
)
361 ret
= CRYPT_AsnEncodeOctets(0, NULL
, &msg
->data
,
362 CRYPT_ENCODE_ALLOC_FLAG
, NULL
,
363 (LPBYTE
)&digestedData
.ContentInfo
.Content
.pbData
,
364 &digestedData
.ContentInfo
.Content
.cbData
);
366 if (msg
->base
.state
== MsgStateFinalized
)
368 size
= sizeof(DWORD
);
369 ret
= CryptGetHashParam(msg
->hash
, HP_HASHSIZE
,
370 (LPBYTE
)&digestedData
.hash
.cbData
, &size
, 0);
373 digestedData
.hash
.pbData
= CryptMemAlloc(
374 digestedData
.hash
.cbData
);
375 ret
= CryptGetHashParam(msg
->hash
, HP_HASHVAL
,
376 digestedData
.hash
.pbData
, &digestedData
.hash
.cbData
, 0);
380 ret
= CRYPT_AsnEncodePKCSDigestedData(&digestedData
, pvData
,
382 CryptMemFree(digestedData
.hash
.pbData
);
383 LocalFree(digestedData
.ContentInfo
.Content
.pbData
);
388 static BOOL
CHashEncodeMsg_GetParam(HCRYPTMSG hCryptMsg
, DWORD dwParamType
,
389 DWORD dwIndex
, void *pvData
, DWORD
*pcbData
)
391 CHashEncodeMsg
*msg
= (CHashEncodeMsg
*)hCryptMsg
;
394 TRACE("(%p, %d, %d, %p, %p)\n", hCryptMsg
, dwParamType
, dwIndex
,
399 case CMSG_BARE_CONTENT_PARAM
:
400 if (msg
->base
.streamed
)
401 SetLastError(E_INVALIDARG
);
403 ret
= CRYPT_EncodePKCSDigestedData(msg
, pvData
, pcbData
);
405 case CMSG_CONTENT_PARAM
:
407 CRYPT_CONTENT_INFO info
;
409 ret
= CryptMsgGetParam(hCryptMsg
, CMSG_BARE_CONTENT_PARAM
, 0, NULL
,
410 &info
.Content
.cbData
);
413 info
.Content
.pbData
= CryptMemAlloc(info
.Content
.cbData
);
414 if (info
.Content
.pbData
)
416 ret
= CryptMsgGetParam(hCryptMsg
, CMSG_BARE_CONTENT_PARAM
, 0,
417 info
.Content
.pbData
, &info
.Content
.cbData
);
420 char oid_rsa_hashed
[] = szOID_RSA_hashedData
;
422 info
.pszObjId
= oid_rsa_hashed
;
423 ret
= CryptEncodeObjectEx(X509_ASN_ENCODING
,
424 PKCS_CONTENT_INFO
, &info
, 0, NULL
, pvData
, pcbData
);
426 CryptMemFree(info
.Content
.pbData
);
433 case CMSG_COMPUTED_HASH_PARAM
:
434 ret
= CryptGetHashParam(msg
->hash
, HP_HASHVAL
, (BYTE
*)pvData
, pcbData
,
437 case CMSG_VERSION_PARAM
:
438 if (msg
->base
.state
!= MsgStateFinalized
)
439 SetLastError(CRYPT_E_MSG_ERROR
);
442 DWORD version
= CMSG_HASHED_DATA_PKCS_1_5_VERSION
;
444 /* Since the data are always encoded as octets, the version is
445 * always 0 (see rfc3852, section 7)
447 ret
= CRYPT_CopyParam(pvData
, pcbData
, (const BYTE
*)&version
,
457 static BOOL
CHashEncodeMsg_Update(HCRYPTMSG hCryptMsg
, const BYTE
*pbData
,
458 DWORD cbData
, BOOL fFinal
)
460 CHashEncodeMsg
*msg
= (CHashEncodeMsg
*)hCryptMsg
;
463 TRACE("(%p, %p, %d, %d)\n", hCryptMsg
, pbData
, cbData
, fFinal
);
465 if (msg
->base
.streamed
|| (msg
->base
.open_flags
& CMSG_DETACHED_FLAG
))
467 /* Doesn't do much, as stream output is never called, and you
468 * can't get the content.
470 ret
= CryptHashData(msg
->hash
, pbData
, cbData
, 0);
475 SetLastError(CRYPT_E_MSG_ERROR
);
478 ret
= CryptHashData(msg
->hash
, pbData
, cbData
, 0);
481 msg
->data
.pbData
= CryptMemAlloc(cbData
);
482 if (msg
->data
.pbData
)
484 memcpy(msg
->data
.pbData
+ msg
->data
.cbData
, pbData
, cbData
);
485 msg
->data
.cbData
+= cbData
;
495 static HCRYPTMSG
CHashEncodeMsg_Open(DWORD dwFlags
, const void *pvMsgEncodeInfo
,
496 LPSTR pszInnerContentObjID
, PCMSG_STREAM_INFO pStreamInfo
)
499 const CMSG_HASHED_ENCODE_INFO
*info
=
500 (const CMSG_HASHED_ENCODE_INFO
*)pvMsgEncodeInfo
;
504 if (info
->cbSize
!= sizeof(CMSG_HASHED_ENCODE_INFO
))
506 SetLastError(E_INVALIDARG
);
509 if (!(algID
= CertOIDToAlgId(info
->HashAlgorithm
.pszObjId
)))
511 SetLastError(CRYPT_E_UNKNOWN_ALGO
);
514 if (info
->hCryptProv
)
515 prov
= info
->hCryptProv
;
518 prov
= CRYPT_GetDefaultProvider();
519 dwFlags
&= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG
;
521 msg
= CryptMemAlloc(sizeof(CHashEncodeMsg
));
524 CryptMsgBase_Init((CryptMsgBase
*)msg
, dwFlags
, pStreamInfo
,
525 CHashEncodeMsg_Close
, CHashEncodeMsg_GetParam
, CHashEncodeMsg_Update
);
527 msg
->data
.cbData
= 0;
528 msg
->data
.pbData
= NULL
;
529 if (!CryptCreateHash(prov
, algID
, 0, 0, &msg
->hash
))
535 return (HCRYPTMSG
)msg
;
538 typedef struct _CMSG_SIGNER_ENCODE_INFO_WITH_CMS
541 PCERT_INFO pCertInfo
;
542 HCRYPTPROV hCryptProv
;
544 CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm
;
547 PCRYPT_ATTRIBUTE rgAuthAttr
;
549 PCRYPT_ATTRIBUTE rgUnauthAttr
;
551 CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm
;
552 void *pvHashEncryptionAuxInfo
;
553 } CMSG_SIGNER_ENCODE_INFO_WITH_CMS
, *PCMSG_SIGNER_ENCODE_INFO_WITH_CMS
;
555 typedef struct _CMSG_SIGNED_ENCODE_INFO_WITH_CMS
559 PCMSG_SIGNER_ENCODE_INFO_WITH_CMS rgSigners
;
561 PCERT_BLOB rgCertEncoded
;
563 PCRL_BLOB rgCrlEncoded
;
564 DWORD cAttrCertEncoded
;
565 PCERT_BLOB rgAttrCertEncoded
;
566 } CMSG_SIGNED_ENCODE_INFO_WITH_CMS
, *PCMSG_SIGNED_ENCODE_INFO_WITH_CMS
;
568 static BOOL
CRYPT_IsValidSigner(CMSG_SIGNER_ENCODE_INFO_WITH_CMS
*signer
)
570 if (signer
->cbSize
!= sizeof(CMSG_SIGNER_ENCODE_INFO
) &&
571 signer
->cbSize
!= sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS
))
573 SetLastError(E_INVALIDARG
);
576 if (signer
->cbSize
== sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS
))
578 FIXME("CMSG_SIGNER_ENCODE_INFO with CMS fields unsupported\n");
581 if (!signer
->pCertInfo
->SerialNumber
.cbData
)
583 SetLastError(E_INVALIDARG
);
586 if (!signer
->pCertInfo
->Issuer
.cbData
)
588 SetLastError(E_INVALIDARG
);
591 if (!signer
->hCryptProv
)
593 SetLastError(E_INVALIDARG
);
596 if (!CertOIDToAlgId(signer
->HashAlgorithm
.pszObjId
))
598 SetLastError(CRYPT_E_UNKNOWN_ALGO
);
604 typedef struct _CSignerHandles
607 HCRYPTHASH contentHash
;
608 HCRYPTHASH authAttrHash
;
612 static BOOL
CRYPT_CopyBlob(CRYPT_DATA_BLOB
*out
, const CRYPT_DATA_BLOB
*in
)
616 out
->cbData
= in
->cbData
;
619 out
->pbData
= CryptMemAlloc(out
->cbData
);
621 memcpy(out
->pbData
, in
->pbData
, out
->cbData
);
630 typedef struct _BlobArray
633 PCRYPT_DATA_BLOB blobs
;
636 static BOOL
CRYPT_CopyBlobArray(BlobArray
*out
, const BlobArray
*in
)
640 out
->cBlobs
= in
->cBlobs
;
643 out
->blobs
= CryptMemAlloc(out
->cBlobs
* sizeof(CRYPT_DATA_BLOB
));
648 memset(out
->blobs
, 0, out
->cBlobs
* sizeof(CRYPT_DATA_BLOB
));
649 for (i
= 0; ret
&& i
< out
->cBlobs
; i
++)
650 ret
= CRYPT_CopyBlob(&out
->blobs
[i
], &in
->blobs
[i
]);
658 static void CRYPT_FreeBlobArray(BlobArray
*array
)
662 for (i
= 0; i
< array
->cBlobs
; i
++)
663 CryptMemFree(array
->blobs
[i
].pbData
);
664 CryptMemFree(array
->blobs
);
667 static BOOL
CRYPT_CopyAttribute(CRYPT_ATTRIBUTE
*out
, const CRYPT_ATTRIBUTE
*in
)
671 out
->pszObjId
= CryptMemAlloc(strlen(in
->pszObjId
) + 1);
674 strcpy(out
->pszObjId
, in
->pszObjId
);
675 ret
= CRYPT_CopyBlobArray((BlobArray
*)&out
->cValue
,
676 (const BlobArray
*)&in
->cValue
);
683 static BOOL
CRYPT_CopyAttributes(CRYPT_ATTRIBUTES
*out
,
684 const CRYPT_ATTRIBUTES
*in
)
688 out
->cAttr
= in
->cAttr
;
691 out
->rgAttr
= CryptMemAlloc(out
->cAttr
* sizeof(CRYPT_ATTRIBUTE
));
696 memset(out
->rgAttr
, 0, out
->cAttr
* sizeof(CRYPT_ATTRIBUTE
));
697 for (i
= 0; ret
&& i
< out
->cAttr
; i
++)
698 ret
= CRYPT_CopyAttribute(&out
->rgAttr
[i
], &in
->rgAttr
[i
]);
708 /* Constructs both a CSignerHandles and a CMSG_SIGNER_INFO from a
709 * CMSG_SIGNER_ENCODE_INFO_WITH_CMS.
711 static BOOL
CSignerInfo_Construct(CSignerHandles
*handles
,
712 CMSG_SIGNER_INFO
*info
, CMSG_SIGNER_ENCODE_INFO_WITH_CMS
*in
, DWORD open_flags
)
717 handles
->prov
= in
->hCryptProv
;
718 if (!(open_flags
& CMSG_CRYPT_RELEASE_CONTEXT_FLAG
))
719 CryptContextAddRef(handles
->prov
, NULL
, 0);
720 algID
= CertOIDToAlgId(in
->HashAlgorithm
.pszObjId
);
721 ret
= CryptCreateHash(handles
->prov
, algID
, 0, 0, &handles
->contentHash
);
722 if (ret
&& in
->cAuthAttr
)
723 ret
= CryptCreateHash(handles
->prov
, algID
, 0, 0,
724 &handles
->authAttrHash
);
727 /* Note: needs to change if CMS fields are supported */
728 info
->dwVersion
= CMSG_SIGNER_INFO_V1
;
729 ret
= CRYPT_CopyBlob(&info
->Issuer
, &in
->pCertInfo
->Issuer
);
731 ret
= CRYPT_CopyBlob(&info
->SerialNumber
,
732 &in
->pCertInfo
->SerialNumber
);
733 /* Assumption: algorithm IDs will point to static strings, not
734 * stack-based ones, so copying the pointer values is safe.
736 info
->HashAlgorithm
.pszObjId
= in
->HashAlgorithm
.pszObjId
;
738 ret
= CRYPT_CopyBlob(&info
->HashAlgorithm
.Parameters
,
739 &in
->HashAlgorithm
.Parameters
);
740 memset(&info
->HashEncryptionAlgorithm
, 0,
741 sizeof(info
->HashEncryptionAlgorithm
));
743 ret
= CRYPT_CopyAttributes(&info
->AuthAttrs
,
744 (CRYPT_ATTRIBUTES
*)&in
->cAuthAttr
);
746 ret
= CRYPT_CopyAttributes(&info
->UnauthAttrs
,
747 (CRYPT_ATTRIBUTES
*)&in
->cUnauthAttr
);
752 static void CSignerInfo_Free(CMSG_SIGNER_INFO
*info
)
756 CryptMemFree(info
->Issuer
.pbData
);
757 CryptMemFree(info
->SerialNumber
.pbData
);
758 CryptMemFree(info
->HashAlgorithm
.Parameters
.pbData
);
759 CryptMemFree(info
->EncryptedHash
.pbData
);
760 for (i
= 0; i
< info
->AuthAttrs
.cAttr
; i
++)
762 for (j
= 0; j
< info
->AuthAttrs
.rgAttr
[i
].cValue
; j
++)
763 CryptMemFree(info
->AuthAttrs
.rgAttr
[i
].rgValue
[j
].pbData
);
764 CryptMemFree(info
->AuthAttrs
.rgAttr
[i
].rgValue
);
765 CryptMemFree(info
->AuthAttrs
.rgAttr
[i
].pszObjId
);
767 CryptMemFree(info
->AuthAttrs
.rgAttr
);
768 for (i
= 0; i
< info
->UnauthAttrs
.cAttr
; i
++)
770 for (j
= 0; j
< info
->UnauthAttrs
.rgAttr
[i
].cValue
; j
++)
771 CryptMemFree(info
->UnauthAttrs
.rgAttr
[i
].rgValue
[j
].pbData
);
772 CryptMemFree(info
->UnauthAttrs
.rgAttr
[i
].rgValue
);
773 CryptMemFree(info
->UnauthAttrs
.rgAttr
[i
].pszObjId
);
775 CryptMemFree(info
->UnauthAttrs
.rgAttr
);
778 typedef struct _CSignedEncodeMsg
781 CRYPT_DATA_BLOB data
;
782 CRYPT_SIGNED_INFO info
;
783 CSignerHandles
*signerHandles
;
786 static void CSignedEncodeMsg_Close(HCRYPTMSG hCryptMsg
)
788 CSignedEncodeMsg
*msg
= (CSignedEncodeMsg
*)hCryptMsg
;
791 CryptMemFree(msg
->data
.pbData
);
792 CRYPT_FreeBlobArray((BlobArray
*)&msg
->info
.cCertEncoded
);
793 CRYPT_FreeBlobArray((BlobArray
*)&msg
->info
.cCrlEncoded
);
794 for (i
= 0; i
< msg
->info
.cSignerInfo
; i
++)
796 CSignerInfo_Free(&msg
->info
.rgSignerInfo
[i
]);
797 CryptDestroyKey(msg
->signerHandles
[i
].key
);
798 CryptDestroyHash(msg
->signerHandles
[i
].contentHash
);
799 CryptDestroyHash(msg
->signerHandles
[i
].authAttrHash
);
800 CryptReleaseContext(msg
->signerHandles
[i
].prov
, 0);
802 CryptMemFree(msg
->signerHandles
);
803 CryptMemFree(msg
->info
.rgSignerInfo
);
806 static BOOL
CSignedEncodeMsg_GetParam(HCRYPTMSG hCryptMsg
, DWORD dwParamType
,
807 DWORD dwIndex
, void *pvData
, DWORD
*pcbData
)
809 CSignedEncodeMsg
*msg
= (CSignedEncodeMsg
*)hCryptMsg
;
814 case CMSG_CONTENT_PARAM
:
816 CRYPT_CONTENT_INFO info
;
818 ret
= CryptMsgGetParam(hCryptMsg
, CMSG_BARE_CONTENT_PARAM
, 0, NULL
,
819 &info
.Content
.cbData
);
822 info
.Content
.pbData
= CryptMemAlloc(info
.Content
.cbData
);
823 if (info
.Content
.pbData
)
825 ret
= CryptMsgGetParam(hCryptMsg
, CMSG_BARE_CONTENT_PARAM
, 0,
826 info
.Content
.pbData
, &info
.Content
.cbData
);
829 char oid_rsa_signed
[] = szOID_RSA_signedData
;
831 info
.pszObjId
= oid_rsa_signed
;
832 ret
= CryptEncodeObjectEx(X509_ASN_ENCODING
,
833 PKCS_CONTENT_INFO
, &info
, 0, NULL
, pvData
, pcbData
);
835 CryptMemFree(info
.Content
.pbData
);
842 case CMSG_BARE_CONTENT_PARAM
:
844 CRYPT_SIGNED_INFO info
;
845 char oid_rsa_data
[] = szOID_RSA_data
;
847 memcpy(&info
, &msg
->info
, sizeof(info
));
848 /* Quirk: OID is only encoded messages if an update has happened */
849 if (msg
->base
.state
!= MsgStateInit
)
850 info
.content
.pszObjId
= oid_rsa_data
;
852 info
.content
.pszObjId
= NULL
;
853 if (msg
->data
.cbData
)
855 CRYPT_DATA_BLOB blob
= { msg
->data
.cbData
, msg
->data
.pbData
};
857 ret
= CryptEncodeObjectEx(X509_ASN_ENCODING
, X509_OCTET_STRING
,
858 &blob
, CRYPT_ENCODE_ALLOC_FLAG
, NULL
,
859 &info
.content
.Content
.pbData
, &info
.content
.Content
.cbData
);
863 info
.content
.Content
.cbData
= 0;
864 info
.content
.Content
.pbData
= NULL
;
869 ret
= CRYPT_AsnEncodePKCSSignedInfo(&info
, pvData
, pcbData
);
870 LocalFree(info
.content
.Content
.pbData
);
874 case CMSG_COMPUTED_HASH_PARAM
:
875 if (dwIndex
>= msg
->info
.cSignerInfo
)
876 SetLastError(CRYPT_E_INVALID_INDEX
);
878 ret
= CryptGetHashParam(msg
->signerHandles
[dwIndex
].contentHash
,
879 HP_HASHVAL
, pvData
, pcbData
, 0);
881 case CMSG_ENCODED_SIGNER
:
882 if (dwIndex
>= msg
->info
.cSignerInfo
)
883 SetLastError(CRYPT_E_INVALID_INDEX
);
885 ret
= CryptEncodeObjectEx(X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
,
886 PKCS7_SIGNER_INFO
, &msg
->info
.rgSignerInfo
[dwIndex
], 0, NULL
,
889 case CMSG_VERSION_PARAM
:
890 ret
= CRYPT_CopyParam(pvData
, pcbData
, (const BYTE
*)&msg
->info
.version
,
891 sizeof(msg
->info
.version
));
894 SetLastError(CRYPT_E_INVALID_MSG_TYPE
);
899 static BOOL
CSignedEncodeMsg_UpdateHash(CSignedEncodeMsg
*msg
,
900 const BYTE
*pbData
, DWORD cbData
)
905 TRACE("(%p, %p, %d)\n", msg
, pbData
, cbData
);
907 for (i
= 0; ret
&& i
< msg
->info
.cSignerInfo
; i
++)
908 ret
= CryptHashData(msg
->signerHandles
[i
].contentHash
, pbData
, cbData
,
913 static BOOL
CRYPT_AppendAttribute(CRYPT_ATTRIBUTES
*out
,
914 const CRYPT_ATTRIBUTE
*in
)
918 out
->rgAttr
= CryptMemRealloc(out
->rgAttr
,
919 (out
->cAttr
+ 1) * sizeof(CRYPT_ATTRIBUTE
));
922 ret
= CRYPT_CopyAttribute(&out
->rgAttr
[out
->cAttr
], in
);
929 static BOOL
CSignedEncodeMsg_AppendMessageDigestAttribute(CSignedEncodeMsg
*msg
,
934 CRYPT_HASH_BLOB hash
= { 0, NULL
}, encodedHash
= { 0, NULL
};
935 char messageDigest
[] = szOID_RSA_messageDigest
;
936 CRYPT_ATTRIBUTE messageDigestAttr
= { messageDigest
, 1, &encodedHash
};
938 size
= sizeof(DWORD
);
939 ret
= CryptGetHashParam(msg
->signerHandles
[signerIndex
].contentHash
,
940 HP_HASHSIZE
, (LPBYTE
)&hash
.cbData
, &size
, 0);
943 hash
.pbData
= CryptMemAlloc(hash
.cbData
);
944 ret
= CryptGetHashParam(msg
->signerHandles
[signerIndex
].contentHash
,
945 HP_HASHVAL
, hash
.pbData
, &hash
.cbData
, 0);
948 ret
= CRYPT_AsnEncodeOctets(0, NULL
, &hash
, CRYPT_ENCODE_ALLOC_FLAG
,
949 NULL
, (LPBYTE
)&encodedHash
.pbData
, &encodedHash
.cbData
);
952 ret
= CRYPT_AppendAttribute(
953 &msg
->info
.rgSignerInfo
[signerIndex
].AuthAttrs
,
955 LocalFree(encodedHash
.pbData
);
958 CryptMemFree(hash
.pbData
);
963 static BOOL
CSignedEncodeMsg_UpdateAuthenticatedAttributes(
964 CSignedEncodeMsg
*msg
)
969 TRACE("(%p)\n", msg
);
971 for (i
= 0; ret
&& i
< msg
->info
.cSignerInfo
; i
++)
973 if (msg
->info
.rgSignerInfo
[i
].AuthAttrs
.cAttr
)
975 BYTE oid_rsa_data_encoded
[] = { 0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,
976 0x0d,0x01,0x07,0x01 };
977 CRYPT_DATA_BLOB content
= { sizeof(oid_rsa_data_encoded
),
978 oid_rsa_data_encoded
};
979 char contentType
[] = szOID_RSA_contentType
;
980 CRYPT_ATTRIBUTE contentTypeAttr
= { contentType
, 1, &content
};
982 /* FIXME: does this depend on inner OID? */
983 ret
= CRYPT_AppendAttribute(&msg
->info
.rgSignerInfo
[i
].AuthAttrs
,
986 ret
= CSignedEncodeMsg_AppendMessageDigestAttribute(msg
, i
);
992 ret
= CryptEncodeObjectEx(X509_ASN_ENCODING
, PKCS_ATTRIBUTES
,
993 &msg
->info
.rgSignerInfo
[i
].AuthAttrs
, CRYPT_ENCODE_ALLOC_FLAG
,
994 NULL
, (LPBYTE
)&encodedAttrs
, &size
);
997 ret
= CryptHashData(msg
->signerHandles
[i
].authAttrHash
,
998 encodedAttrs
, size
, 0);
999 LocalFree(encodedAttrs
);
1004 TRACE("returning %d\n", ret
);
1008 static void CRYPT_ReverseBytes(CRYPT_HASH_BLOB
*hash
)
1013 for (i
= 0; i
< hash
->cbData
/ 2; i
++)
1015 tmp
= hash
->pbData
[hash
->cbData
- i
- 1];
1016 hash
->pbData
[hash
->cbData
- i
- 1] = hash
->pbData
[i
];
1017 hash
->pbData
[i
] = tmp
;
1021 static BOOL
CSignedEncodeMsg_Sign(CSignedEncodeMsg
*msg
)
1026 TRACE("(%p)\n", msg
);
1028 for (i
= 0; ret
&& i
< msg
->info
.cSignerInfo
; i
++)
1032 if (msg
->info
.rgSignerInfo
[i
].AuthAttrs
.cAttr
)
1033 hash
= msg
->signerHandles
[i
].authAttrHash
;
1035 hash
= msg
->signerHandles
[i
].contentHash
;
1036 ret
= CryptSignHashW(hash
, AT_SIGNATURE
, NULL
, 0, NULL
,
1037 &msg
->info
.rgSignerInfo
[i
].EncryptedHash
.cbData
);
1040 msg
->info
.rgSignerInfo
[i
].EncryptedHash
.pbData
=
1041 CryptMemAlloc(msg
->info
.rgSignerInfo
[i
].EncryptedHash
.cbData
);
1042 if (msg
->info
.rgSignerInfo
[i
].EncryptedHash
.pbData
)
1044 ret
= CryptSignHashW(hash
, AT_SIGNATURE
, NULL
, 0,
1045 msg
->info
.rgSignerInfo
[i
].EncryptedHash
.pbData
,
1046 &msg
->info
.rgSignerInfo
[i
].EncryptedHash
.cbData
);
1048 CRYPT_ReverseBytes(&msg
->info
.rgSignerInfo
[i
].EncryptedHash
);
1057 static BOOL
CSignedEncodeMsg_Update(HCRYPTMSG hCryptMsg
, const BYTE
*pbData
,
1058 DWORD cbData
, BOOL fFinal
)
1060 CSignedEncodeMsg
*msg
= (CSignedEncodeMsg
*)hCryptMsg
;
1063 if (msg
->base
.streamed
|| (msg
->base
.open_flags
& CMSG_DETACHED_FLAG
))
1065 ret
= CSignedEncodeMsg_UpdateHash(msg
, pbData
, cbData
);
1068 ret
= CSignedEncodeMsg_UpdateAuthenticatedAttributes(msg
);
1070 ret
= CSignedEncodeMsg_Sign(msg
);
1072 if (msg
->base
.streamed
)
1073 FIXME("streamed partial stub\n");
1078 SetLastError(CRYPT_E_MSG_ERROR
);
1083 msg
->data
.pbData
= CryptMemAlloc(cbData
);
1084 if (msg
->data
.pbData
)
1086 memcpy(msg
->data
.pbData
, pbData
, cbData
);
1087 msg
->data
.cbData
= cbData
;
1094 ret
= CSignedEncodeMsg_UpdateHash(msg
, pbData
, cbData
);
1096 ret
= CSignedEncodeMsg_UpdateAuthenticatedAttributes(msg
);
1098 ret
= CSignedEncodeMsg_Sign(msg
);
1104 static HCRYPTMSG
CSignedEncodeMsg_Open(DWORD dwFlags
,
1105 const void *pvMsgEncodeInfo
, LPSTR pszInnerContentObjID
,
1106 PCMSG_STREAM_INFO pStreamInfo
)
1108 const CMSG_SIGNED_ENCODE_INFO_WITH_CMS
*info
=
1109 (const CMSG_SIGNED_ENCODE_INFO_WITH_CMS
*)pvMsgEncodeInfo
;
1111 CSignedEncodeMsg
*msg
;
1113 if (info
->cbSize
!= sizeof(CMSG_SIGNED_ENCODE_INFO
) &&
1114 info
->cbSize
!= sizeof(CMSG_SIGNED_ENCODE_INFO_WITH_CMS
))
1116 SetLastError(E_INVALIDARG
);
1119 if (info
->cbSize
== sizeof(CMSG_SIGNED_ENCODE_INFO_WITH_CMS
))
1121 FIXME("CMSG_SIGNED_ENCODE_INFO with CMS fields unsupported\n");
1124 for (i
= 0; i
< info
->cSigners
; i
++)
1125 if (!CRYPT_IsValidSigner(&info
->rgSigners
[i
]))
1127 msg
= CryptMemAlloc(sizeof(CSignedEncodeMsg
));
1132 CryptMsgBase_Init((CryptMsgBase
*)msg
, dwFlags
, pStreamInfo
,
1133 CSignedEncodeMsg_Close
, CSignedEncodeMsg_GetParam
,
1134 CSignedEncodeMsg_Update
);
1135 msg
->data
.cbData
= 0;
1136 msg
->data
.pbData
= NULL
;
1137 memset(&msg
->info
, 0, sizeof(msg
->info
));
1138 msg
->info
.version
= CMSG_SIGNED_DATA_V1
;
1141 msg
->signerHandles
=
1142 CryptMemAlloc(info
->cSigners
* sizeof(CSignerHandles
));
1143 if (msg
->signerHandles
)
1144 msg
->info
.rgSignerInfo
=
1145 CryptMemAlloc(info
->cSigners
* sizeof(CMSG_SIGNER_INFO
));
1149 msg
->info
.rgSignerInfo
= NULL
;
1151 if (msg
->info
.rgSignerInfo
)
1153 msg
->info
.cSignerInfo
= info
->cSigners
;
1154 memset(msg
->signerHandles
, 0,
1155 msg
->info
.cSignerInfo
* sizeof(CSignerHandles
));
1156 memset(msg
->info
.rgSignerInfo
, 0,
1157 msg
->info
.cSignerInfo
* sizeof(CMSG_SIGNER_INFO
));
1158 for (i
= 0; ret
&& i
< msg
->info
.cSignerInfo
; i
++)
1159 ret
= CSignerInfo_Construct(&msg
->signerHandles
[i
],
1160 &msg
->info
.rgSignerInfo
[i
], &info
->rgSigners
[i
], dwFlags
);
1166 ret
= CRYPT_CopyBlobArray((BlobArray
*)&msg
->info
.cCertEncoded
,
1167 (const BlobArray
*)&info
->cCertEncoded
);
1169 ret
= CRYPT_CopyBlobArray((BlobArray
*)&msg
->info
.cCrlEncoded
,
1170 (const BlobArray
*)&info
->cCrlEncoded
);
1173 CSignedEncodeMsg_Close(msg
);
1180 static inline const char *MSG_TYPE_STR(DWORD type
)
1184 #define _x(x) case (x): return #x
1188 _x(CMSG_SIGNED_AND_ENVELOPED
);
1193 return wine_dbg_sprintf("unknown (%d)", type
);
1197 HCRYPTMSG WINAPI
CryptMsgOpenToEncode(DWORD dwMsgEncodingType
, DWORD dwFlags
,
1198 DWORD dwMsgType
, const void *pvMsgEncodeInfo
, LPSTR pszInnerContentObjID
,
1199 PCMSG_STREAM_INFO pStreamInfo
)
1201 HCRYPTMSG msg
= NULL
;
1203 TRACE("(%08x, %08x, %08x, %p, %s, %p)\n", dwMsgEncodingType
, dwFlags
,
1204 dwMsgType
, pvMsgEncodeInfo
, debugstr_a(pszInnerContentObjID
), pStreamInfo
);
1206 if (GET_CMSG_ENCODING_TYPE(dwMsgEncodingType
) != PKCS_7_ASN_ENCODING
)
1208 SetLastError(E_INVALIDARG
);
1214 msg
= CDataEncodeMsg_Open(dwFlags
, pvMsgEncodeInfo
,
1215 pszInnerContentObjID
, pStreamInfo
);
1218 msg
= CHashEncodeMsg_Open(dwFlags
, pvMsgEncodeInfo
,
1219 pszInnerContentObjID
, pStreamInfo
);
1222 msg
= CSignedEncodeMsg_Open(dwFlags
, pvMsgEncodeInfo
,
1223 pszInnerContentObjID
, pStreamInfo
);
1225 case CMSG_ENVELOPED
:
1226 FIXME("unimplemented for type %s\n", MSG_TYPE_STR(dwMsgType
));
1228 case CMSG_SIGNED_AND_ENVELOPED
:
1229 case CMSG_ENCRYPTED
:
1230 /* defined but invalid, fall through */
1232 SetLastError(CRYPT_E_INVALID_MSG_TYPE
);
1237 typedef struct _CDecodeMsg
1241 HCRYPTPROV crypt_prov
;
1243 CRYPT_DATA_BLOB msg_data
;
1244 PCONTEXT_PROPERTY_LIST properties
;
1247 static void CDecodeMsg_Close(HCRYPTMSG hCryptMsg
)
1249 CDecodeMsg
*msg
= (CDecodeMsg
*)hCryptMsg
;
1251 if (msg
->base
.open_flags
& CMSG_CRYPT_RELEASE_CONTEXT_FLAG
)
1252 CryptReleaseContext(msg
->crypt_prov
, 0);
1253 CryptDestroyHash(msg
->hash
);
1254 CryptMemFree(msg
->msg_data
.pbData
);
1255 ContextPropertyList_Free(msg
->properties
);
1258 static BOOL
CDecodeMsg_CopyData(CDecodeMsg
*msg
, const BYTE
*pbData
,
1265 if (msg
->msg_data
.cbData
)
1266 msg
->msg_data
.pbData
= CryptMemRealloc(msg
->msg_data
.pbData
,
1267 msg
->msg_data
.cbData
+ cbData
);
1269 msg
->msg_data
.pbData
= CryptMemAlloc(cbData
);
1270 if (msg
->msg_data
.pbData
)
1272 memcpy(msg
->msg_data
.pbData
+ msg
->msg_data
.cbData
, pbData
, cbData
);
1273 msg
->msg_data
.cbData
+= cbData
;
1281 static BOOL
CDecodeMsg_DecodeDataContent(CDecodeMsg
*msg
, CRYPT_DER_BLOB
*blob
)
1284 CRYPT_DATA_BLOB
*data
;
1287 ret
= CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_OCTET_STRING
,
1288 blob
->pbData
, blob
->cbData
, CRYPT_DECODE_ALLOC_FLAG
, NULL
, (LPBYTE
)&data
,
1292 ret
= ContextPropertyList_SetProperty(msg
->properties
,
1293 CMSG_CONTENT_PARAM
, data
->pbData
, data
->cbData
);
1299 static void CDecodeMsg_SaveAlgorithmID(CDecodeMsg
*msg
, DWORD param
,
1300 const CRYPT_ALGORITHM_IDENTIFIER
*id
)
1302 static const BYTE nullParams
[] = { ASN_NULL
, 0 };
1303 CRYPT_ALGORITHM_IDENTIFIER
*copy
;
1304 DWORD len
= sizeof(CRYPT_ALGORITHM_IDENTIFIER
);
1306 /* Linearize algorithm id */
1307 len
+= strlen(id
->pszObjId
) + 1;
1308 len
+= id
->Parameters
.cbData
;
1309 copy
= CryptMemAlloc(len
);
1313 (LPSTR
)((BYTE
*)copy
+ sizeof(CRYPT_ALGORITHM_IDENTIFIER
));
1314 strcpy(copy
->pszObjId
, id
->pszObjId
);
1315 copy
->Parameters
.pbData
= (BYTE
*)copy
->pszObjId
+ strlen(id
->pszObjId
)
1317 /* Trick: omit NULL parameters */
1318 if (id
->Parameters
.cbData
== sizeof(nullParams
) &&
1319 !memcmp(id
->Parameters
.pbData
, nullParams
, sizeof(nullParams
)))
1321 copy
->Parameters
.cbData
= 0;
1322 len
-= sizeof(nullParams
);
1325 copy
->Parameters
.cbData
= id
->Parameters
.cbData
;
1326 if (copy
->Parameters
.cbData
)
1327 memcpy(copy
->Parameters
.pbData
, id
->Parameters
.pbData
,
1328 id
->Parameters
.cbData
);
1329 ContextPropertyList_SetProperty(msg
->properties
, param
, (BYTE
*)copy
,
1335 static inline void CRYPT_FixUpAlgorithmID(CRYPT_ALGORITHM_IDENTIFIER
*id
)
1337 id
->pszObjId
= (LPSTR
)((BYTE
*)id
+ sizeof(CRYPT_ALGORITHM_IDENTIFIER
));
1338 id
->Parameters
.pbData
= (BYTE
*)id
->pszObjId
+ strlen(id
->pszObjId
) + 1;
1341 static BOOL
CDecodeMsg_DecodeHashedContent(CDecodeMsg
*msg
,
1342 CRYPT_DER_BLOB
*blob
)
1345 CRYPT_DIGESTED_DATA
*digestedData
;
1348 ret
= CRYPT_AsnDecodePKCSDigestedData(blob
->pbData
, blob
->cbData
,
1349 CRYPT_DECODE_ALLOC_FLAG
, NULL
, (CRYPT_DIGESTED_DATA
*)&digestedData
,
1353 ContextPropertyList_SetProperty(msg
->properties
, CMSG_VERSION_PARAM
,
1354 (const BYTE
*)&digestedData
->version
, sizeof(digestedData
->version
));
1355 CDecodeMsg_SaveAlgorithmID(msg
, CMSG_HASH_ALGORITHM_PARAM
,
1356 &digestedData
->DigestAlgorithm
);
1357 ContextPropertyList_SetProperty(msg
->properties
,
1358 CMSG_INNER_CONTENT_TYPE_PARAM
,
1359 (const BYTE
*)digestedData
->ContentInfo
.pszObjId
,
1360 digestedData
->ContentInfo
.pszObjId
?
1361 strlen(digestedData
->ContentInfo
.pszObjId
) + 1 : 0);
1362 if (digestedData
->ContentInfo
.Content
.cbData
)
1363 CDecodeMsg_DecodeDataContent(msg
,
1364 &digestedData
->ContentInfo
.Content
);
1366 ContextPropertyList_SetProperty(msg
->properties
,
1367 CMSG_CONTENT_PARAM
, NULL
, 0);
1368 ContextPropertyList_SetProperty(msg
->properties
, CMSG_HASH_DATA_PARAM
,
1369 digestedData
->hash
.pbData
, digestedData
->hash
.cbData
);
1370 LocalFree(digestedData
);
1375 static BOOL
CDecodeMsg_DecodeSignedContent(CDecodeMsg
*msg
,
1376 CRYPT_DER_BLOB
*blob
)
1379 CRYPT_SIGNED_INFO
*signedInfo
;
1382 ret
= CRYPT_AsnDecodePKCSSignedInfo(blob
->pbData
, blob
->cbData
,
1383 CRYPT_DECODE_ALLOC_FLAG
, NULL
, (CRYPT_SIGNED_INFO
*)&signedInfo
,
1387 FIXME("store properties in message\n");
1388 LocalFree(signedInfo
);
1392 /* Decodes the content in blob as the type given, and updates the value
1393 * (type, parameters, etc.) of msg based on what blob contains.
1394 * It doesn't just use msg's type, to allow a recursive call from an implicitly
1395 * typed message once the outer content info has been decoded.
1397 static BOOL
CDecodeMsg_DecodeContent(CDecodeMsg
*msg
, CRYPT_DER_BLOB
*blob
,
1405 if ((ret
= CDecodeMsg_DecodeDataContent(msg
, blob
)))
1406 msg
->type
= CMSG_DATA
;
1409 if ((ret
= CDecodeMsg_DecodeHashedContent(msg
, blob
)))
1410 msg
->type
= CMSG_HASHED
;
1412 case CMSG_ENVELOPED
:
1413 FIXME("unimplemented for type %s\n", MSG_TYPE_STR(type
));
1417 if ((ret
= CDecodeMsg_DecodeSignedContent(msg
, blob
)))
1418 msg
->type
= CMSG_HASHED
;
1422 CRYPT_CONTENT_INFO
*info
;
1425 ret
= CryptDecodeObjectEx(X509_ASN_ENCODING
, PKCS_CONTENT_INFO
,
1426 msg
->msg_data
.pbData
, msg
->msg_data
.cbData
, CRYPT_DECODE_ALLOC_FLAG
,
1427 NULL
, (LPBYTE
)&info
, &size
);
1430 if (!strcmp(info
->pszObjId
, szOID_RSA_data
))
1431 ret
= CDecodeMsg_DecodeContent(msg
, &info
->Content
, CMSG_DATA
);
1432 else if (!strcmp(info
->pszObjId
, szOID_RSA_digestedData
))
1433 ret
= CDecodeMsg_DecodeContent(msg
, &info
->Content
,
1435 else if (!strcmp(info
->pszObjId
, szOID_RSA_envelopedData
))
1436 ret
= CDecodeMsg_DecodeContent(msg
, &info
->Content
,
1438 else if (!strcmp(info
->pszObjId
, szOID_RSA_signedData
))
1439 ret
= CDecodeMsg_DecodeContent(msg
, &info
->Content
,
1443 SetLastError(CRYPT_E_INVALID_MSG_TYPE
);
1453 static BOOL
CDecodeMsg_Update(HCRYPTMSG hCryptMsg
, const BYTE
*pbData
,
1454 DWORD cbData
, BOOL fFinal
)
1456 CDecodeMsg
*msg
= (CDecodeMsg
*)hCryptMsg
;
1459 TRACE("(%p, %p, %d, %d)\n", hCryptMsg
, pbData
, cbData
, fFinal
);
1461 if (msg
->base
.streamed
)
1463 ret
= CDecodeMsg_CopyData(msg
, pbData
, cbData
);
1464 FIXME("(%p, %p, %d, %d): streamed update stub\n", hCryptMsg
, pbData
,
1470 SetLastError(CRYPT_E_MSG_ERROR
);
1473 ret
= CDecodeMsg_CopyData(msg
, pbData
, cbData
);
1475 ret
= CDecodeMsg_DecodeContent(msg
, &msg
->msg_data
, msg
->type
);
1482 static BOOL
CDecodeMsg_GetParam(HCRYPTMSG hCryptMsg
, DWORD dwParamType
,
1483 DWORD dwIndex
, void *pvData
, DWORD
*pcbData
)
1485 CDecodeMsg
*msg
= (CDecodeMsg
*)hCryptMsg
;
1488 switch (dwParamType
)
1490 case CMSG_TYPE_PARAM
:
1491 ret
= CRYPT_CopyParam(pvData
, pcbData
, (const BYTE
*)&msg
->type
,
1494 case CMSG_HASH_ALGORITHM_PARAM
:
1496 CRYPT_DATA_BLOB blob
;
1498 ret
= ContextPropertyList_FindProperty(msg
->properties
, dwParamType
,
1502 ret
= CRYPT_CopyParam(pvData
, pcbData
, blob
.pbData
, blob
.cbData
);
1504 CRYPT_FixUpAlgorithmID((CRYPT_ALGORITHM_IDENTIFIER
*)pvData
);
1507 SetLastError(CRYPT_E_INVALID_MSG_TYPE
);
1510 case CMSG_COMPUTED_HASH_PARAM
:
1513 CRYPT_ALGORITHM_IDENTIFIER
*hashAlgoID
= NULL
;
1517 CryptMsgGetParam(msg
, CMSG_HASH_ALGORITHM_PARAM
, 0, NULL
, &size
);
1518 hashAlgoID
= CryptMemAlloc(size
);
1519 ret
= CryptMsgGetParam(msg
, CMSG_HASH_ALGORITHM_PARAM
, 0,
1522 algID
= CertOIDToAlgId(hashAlgoID
->pszObjId
);
1523 ret
= CryptCreateHash(msg
->crypt_prov
, algID
, 0, 0, &msg
->hash
);
1526 CRYPT_DATA_BLOB content
;
1528 ret
= ContextPropertyList_FindProperty(msg
->properties
,
1529 CMSG_CONTENT_PARAM
, &content
);
1531 ret
= CryptHashData(msg
->hash
, content
.pbData
,
1534 CryptMemFree(hashAlgoID
);
1539 ret
= CryptGetHashParam(msg
->hash
, HP_HASHVAL
, pvData
, pcbData
, 0);
1543 CRYPT_DATA_BLOB blob
;
1545 ret
= ContextPropertyList_FindProperty(msg
->properties
, dwParamType
,
1548 ret
= CRYPT_CopyParam(pvData
, pcbData
, blob
.pbData
, blob
.cbData
);
1550 SetLastError(CRYPT_E_INVALID_MSG_TYPE
);
1556 HCRYPTMSG WINAPI
CryptMsgOpenToDecode(DWORD dwMsgEncodingType
, DWORD dwFlags
,
1557 DWORD dwMsgType
, HCRYPTPROV hCryptProv
, PCERT_INFO pRecipientInfo
,
1558 PCMSG_STREAM_INFO pStreamInfo
)
1562 TRACE("(%08x, %08x, %08x, %08lx, %p, %p)\n", dwMsgEncodingType
,
1563 dwFlags
, dwMsgType
, hCryptProv
, pRecipientInfo
, pStreamInfo
);
1565 if (GET_CMSG_ENCODING_TYPE(dwMsgEncodingType
) != PKCS_7_ASN_ENCODING
)
1567 SetLastError(E_INVALIDARG
);
1570 msg
= CryptMemAlloc(sizeof(CDecodeMsg
));
1573 CryptMsgBase_Init((CryptMsgBase
*)msg
, dwFlags
, pStreamInfo
,
1574 CDecodeMsg_Close
, CDecodeMsg_GetParam
, CDecodeMsg_Update
);
1575 msg
->type
= dwMsgType
;
1577 msg
->crypt_prov
= hCryptProv
;
1580 msg
->crypt_prov
= CRYPT_GetDefaultProvider();
1581 msg
->base
.open_flags
&= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG
;
1584 msg
->msg_data
.cbData
= 0;
1585 msg
->msg_data
.pbData
= NULL
;
1586 msg
->properties
= ContextPropertyList_Create();
1591 HCRYPTMSG WINAPI
CryptMsgDuplicate(HCRYPTMSG hCryptMsg
)
1593 TRACE("(%p)\n", hCryptMsg
);
1597 CryptMsgBase
*msg
= (CryptMsgBase
*)hCryptMsg
;
1599 InterlockedIncrement(&msg
->ref
);
1604 BOOL WINAPI
CryptMsgClose(HCRYPTMSG hCryptMsg
)
1606 TRACE("(%p)\n", hCryptMsg
);
1610 CryptMsgBase
*msg
= (CryptMsgBase
*)hCryptMsg
;
1612 if (InterlockedDecrement(&msg
->ref
) == 0)
1614 TRACE("freeing %p\n", msg
);
1623 BOOL WINAPI
CryptMsgUpdate(HCRYPTMSG hCryptMsg
, const BYTE
*pbData
,
1624 DWORD cbData
, BOOL fFinal
)
1626 CryptMsgBase
*msg
= (CryptMsgBase
*)hCryptMsg
;
1629 TRACE("(%p, %p, %d, %d)\n", hCryptMsg
, pbData
, cbData
, fFinal
);
1631 if (msg
->state
== MsgStateFinalized
)
1632 SetLastError(CRYPT_E_MSG_ERROR
);
1635 ret
= msg
->update(hCryptMsg
, pbData
, cbData
, fFinal
);
1636 msg
->state
= MsgStateUpdated
;
1638 msg
->state
= MsgStateFinalized
;
1643 BOOL WINAPI
CryptMsgGetParam(HCRYPTMSG hCryptMsg
, DWORD dwParamType
,
1644 DWORD dwIndex
, void *pvData
, DWORD
*pcbData
)
1646 CryptMsgBase
*msg
= (CryptMsgBase
*)hCryptMsg
;
1648 TRACE("(%p, %d, %d, %p, %p)\n", hCryptMsg
, dwParamType
, dwIndex
,
1650 return msg
->get_param(hCryptMsg
, dwParamType
, dwIndex
, pvData
, pcbData
);