crypt32: Add tests for getting hash message params.
[wine] / dlls / crypt32 / tests / msg.c
1 /*
2  * Unit test suite for crypt32.dll's CryptMsg functions
3  *
4  * Copyright 2007 Juan Lang
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <windef.h>
24 #include <winbase.h>
25 #include <winerror.h>
26 #include <wincrypt.h>
27
28 #include "wine/test.h"
29
30 static void test_msg_open_to_encode(void)
31 {
32     HCRYPTMSG msg;
33
34     /* Crash
35     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_ENVELOPED, NULL,
36      NULL, NULL);
37     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, NULL, NULL,
38      NULL);
39     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, NULL, NULL,
40      NULL);
41      */
42
43     /* Bad encodings */
44     SetLastError(0xdeadbeef);
45     msg = CryptMsgOpenToEncode(0, 0, 0, NULL, NULL, NULL);
46     ok(!msg && GetLastError() == E_INVALIDARG,
47      "Expected E_INVALIDARG, got %x\n", GetLastError());
48     SetLastError(0xdeadbeef);
49     msg = CryptMsgOpenToEncode(X509_ASN_ENCODING, 0, 0, NULL, NULL, NULL);
50     ok(!msg && GetLastError() == E_INVALIDARG,
51      "Expected E_INVALIDARG, got %x\n", GetLastError());
52
53     /* Bad message types */
54     SetLastError(0xdeadbeef);
55     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, 0, NULL, NULL, NULL);
56     ok(!msg && GetLastError() == CRYPT_E_INVALID_MSG_TYPE,
57      "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
58     SetLastError(0xdeadbeef);
59     msg = CryptMsgOpenToEncode(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, 0,
60      NULL, NULL, NULL);
61     ok(!msg && GetLastError() == CRYPT_E_INVALID_MSG_TYPE,
62      "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
63     SetLastError(0xdeadbeef);
64     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0,
65      CMSG_SIGNED_AND_ENVELOPED, NULL, NULL, NULL);
66     ok(!msg && GetLastError() == CRYPT_E_INVALID_MSG_TYPE,
67      "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
68     SetLastError(0xdeadbeef);
69     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_ENCRYPTED, NULL,
70      NULL, NULL);
71     ok(!msg && GetLastError() == CRYPT_E_INVALID_MSG_TYPE,
72      "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
73 }
74
75 static void test_msg_open_to_decode(void)
76 {
77     HCRYPTMSG msg;
78     CMSG_STREAM_INFO streamInfo = { 0 };
79
80     SetLastError(0xdeadbeef);
81     msg = CryptMsgOpenToDecode(0, 0, 0, 0, NULL, NULL);
82     ok(!msg && GetLastError() == E_INVALIDARG,
83      "Expected E_INVALIDARG, got %x\n", GetLastError());
84
85     /* Bad encodings */
86     SetLastError(0xdeadbeef);
87     msg = CryptMsgOpenToDecode(X509_ASN_ENCODING, 0, 0, 0, NULL, NULL);
88     ok(!msg && GetLastError() == E_INVALIDARG,
89      "Expected E_INVALIDARG, got %x\n", GetLastError());
90     SetLastError(0xdeadbeef);
91     msg = CryptMsgOpenToDecode(X509_ASN_ENCODING, 0, CMSG_DATA, 0, NULL, NULL);
92     ok(!msg && GetLastError() == E_INVALIDARG,
93      "Expected E_INVALIDARG, got %x\n", GetLastError());
94
95     /* The message type can be explicit... */
96     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, 0, NULL,
97      NULL);
98     ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
99     CryptMsgClose(msg);
100     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_ENVELOPED, 0, NULL,
101      NULL);
102     ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
103     CryptMsgClose(msg);
104     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL,
105      NULL);
106     ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
107     CryptMsgClose(msg);
108     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, 0, NULL,
109      NULL);
110     ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
111     CryptMsgClose(msg);
112     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0,
113      CMSG_SIGNED_AND_ENVELOPED, 0, NULL, NULL);
114     ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
115     CryptMsgClose(msg);
116     /* or implicit.. */
117     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
118     ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
119     CryptMsgClose(msg);
120     /* or even invalid. */
121     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_ENCRYPTED, 0, NULL,
122      NULL);
123     ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
124     CryptMsgClose(msg);
125     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 1000, 0, NULL, NULL);
126     ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
127     CryptMsgClose(msg);
128
129     /* And even though the stream info parameter "must be set to NULL" for
130      * CMSG_HASHED, it's still accepted.
131      */
132     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL,
133      &streamInfo);
134     ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
135     CryptMsgClose(msg);
136 }
137
138 static void test_msg_get_param(void)
139 {
140     BOOL ret;
141     HCRYPTMSG msg;
142     DWORD size, i, value;
143     CMSG_SIGNED_ENCODE_INFO signInfo = { sizeof(signInfo), 0 };
144     CMSG_SIGNER_ENCODE_INFO signer = { sizeof(signer), 0 };
145
146     /* Crash
147     ret = CryptMsgGetParam(NULL, 0, 0, NULL, NULL);
148     ret = CryptMsgGetParam(NULL, 0, 0, NULL, &size);
149     ret = CryptMsgGetParam(msg, 0, 0, NULL, NULL);
150      */
151
152     /* Decoded messages */
153     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
154     ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
155     /* For decoded messages, the type is always available */
156     size = 0;
157     ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, NULL, &size);
158     ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError());
159     size = sizeof(value);
160     ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, (LPBYTE)&value, &size);
161     ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError());
162     /* For this (empty) message, the type isn't set */
163     ok(value == 0, "Expected type 0, got %d\n", value);
164     CryptMsgClose(msg);
165
166     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, 0, NULL,
167      NULL);
168     ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
169     /* For explicitly typed messages, the type is known. */
170     size = sizeof(value);
171     ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, (LPBYTE)&value, &size);
172     ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError());
173     ok(value == CMSG_DATA, "Expected CMSG_DATA, got %d\n", value);
174     for (i = CMSG_CONTENT_PARAM; i <= CMSG_CMS_SIGNER_INFO_PARAM; i++)
175     {
176         size = 0;
177         ret = CryptMsgGetParam(msg, i, 0, NULL, &size);
178         ok(!ret, "Parameter %d: expected failure\n", i);
179     }
180     CryptMsgClose(msg);
181
182     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_ENVELOPED, 0, NULL,
183      NULL);
184     ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
185     size = sizeof(value);
186     ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, (LPBYTE)&value, &size);
187     ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError());
188     ok(value == CMSG_ENVELOPED, "Expected CMSG_ENVELOPED, got %d\n", value);
189     for (i = CMSG_CONTENT_PARAM; i <= CMSG_CMS_SIGNER_INFO_PARAM; i++)
190     {
191         size = 0;
192         ret = CryptMsgGetParam(msg, i, 0, NULL, &size);
193         ok(!ret, "Parameter %d: expected failure\n", i);
194     }
195     CryptMsgClose(msg);
196
197     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL,
198      NULL);
199     ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
200     size = sizeof(value);
201     ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, (LPBYTE)&value, &size);
202     ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError());
203     ok(value == CMSG_HASHED, "Expected CMSG_HASHED, got %d\n", value);
204     for (i = CMSG_CONTENT_PARAM; i <= CMSG_CMS_SIGNER_INFO_PARAM; i++)
205     {
206         size = 0;
207         ret = CryptMsgGetParam(msg, i, 0, NULL, &size);
208         ok(!ret, "Parameter %d: expected failure\n", i);
209     }
210     CryptMsgClose(msg);
211
212     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, 0, NULL,
213      NULL);
214     ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
215     size = sizeof(value);
216     ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, (LPBYTE)&value, &size);
217     ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError());
218     ok(value == CMSG_SIGNED, "Expected CMSG_SIGNED, got %d\n", value);
219     for (i = CMSG_CONTENT_PARAM; i <= CMSG_CMS_SIGNER_INFO_PARAM; i++)
220     {
221         size = 0;
222         ret = CryptMsgGetParam(msg, i, 0, NULL, &size);
223         ok(!ret, "Parameter %d: expected failure\n", i);
224     }
225     CryptMsgClose(msg);
226
227     /* Explicitly typed messages get their types set, even if they're invalid */
228     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_ENCRYPTED, 0, NULL,
229      NULL);
230     ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
231     size = sizeof(value);
232     ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, (LPBYTE)&value, &size);
233     ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError());
234     ok(value == CMSG_ENCRYPTED, "Expected CMSG_ENCRYPTED, got %d\n", value);
235     CryptMsgClose(msg);
236
237     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 1000, 0, NULL, NULL);
238     ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
239     size = sizeof(value);
240     ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, (LPBYTE)&value, &size);
241     ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError());
242     ok(value == 1000, "Expected 1000, got %d\n", value);
243     CryptMsgClose(msg);
244 }
245
246 static void test_msg_close(void)
247 {
248     BOOL ret;
249     HCRYPTMSG msg;
250
251     /* NULL succeeds.. */
252     ret = CryptMsgClose(NULL);
253     ok(ret, "CryptMsgClose failed: %x\n", GetLastError());
254     /* but an arbitrary pointer crashes. */
255     if (0)
256         ret = CryptMsgClose((HCRYPTMSG)1);
257     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
258      NULL);
259     ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
260     ret = CryptMsgClose(msg);
261     ok(ret, "CryptMsgClose failed: %x\n", GetLastError());
262 }
263
264 static void check_param(LPCSTR test, HCRYPTMSG msg, DWORD param,
265  const BYTE *expected, DWORD expectedSize)
266 {
267     DWORD size;
268     LPBYTE buf;
269     BOOL ret;
270
271     size = 0;
272     ret = CryptMsgGetParam(msg, param, 0, NULL, &size);
273     ok(ret, "%s: CryptMsgGetParam failed: %08x\n", test, GetLastError());
274     buf = HeapAlloc(GetProcessHeap(), 0, size);
275     ret = CryptMsgGetParam(msg, param, 0, buf, &size);
276     ok(ret, "%s: CryptMsgGetParam failed: %08x\n", test, GetLastError());
277     ok(size == expectedSize, "%s: expected size %d, got %d\n", test,
278      expectedSize, size);
279     if (size)
280         ok(!memcmp(buf, expected, size), "%s: unexpected data\n", test);
281     HeapFree(GetProcessHeap(), 0, buf);
282 }
283
284 static void test_data_msg_open(void)
285 {
286     HCRYPTMSG msg;
287     CMSG_HASHED_ENCODE_INFO hashInfo = { 0 };
288     CMSG_STREAM_INFO streamInfo = { 0 };
289     char oid[] = "1.2.3";
290
291     /* The data message type takes no additional info */
292     SetLastError(0xdeadbeef);
293     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, &hashInfo,
294      NULL, NULL);
295     ok(!msg && GetLastError() == E_INVALIDARG,
296      "Expected E_INVALIDARG, got %x\n", GetLastError());
297     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
298      NULL);
299     ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
300     CryptMsgClose(msg);
301
302     /* An empty stream info is allowed. */
303     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
304      &streamInfo);
305     ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
306     CryptMsgClose(msg);
307
308     /* Passing a bogus inner OID succeeds for a non-streamed message.. */
309     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, oid,
310      NULL);
311     ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
312     CryptMsgClose(msg);
313     /* and still succeeds when CMSG_DETACHED_FLAG is passed.. */
314     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG,
315      CMSG_DATA, NULL, oid, NULL);
316     ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
317     CryptMsgClose(msg);
318     /* and when a stream info is given, even though you're not supposed to be
319      * able to use anything but szOID_RSA_data when streaming is being used.
320      */
321     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG,
322      CMSG_DATA, NULL, oid, &streamInfo);
323     ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
324     CryptMsgClose(msg);
325 }
326
327 static const BYTE msgData[] = { 1, 2, 3, 4 };
328
329 static BOOL WINAPI nop_stream_output(const void *pvArg, BYTE *pb, DWORD cb,
330  BOOL final)
331 {
332     return TRUE;
333 }
334
335 static void test_data_msg_update(void)
336 {
337     HCRYPTMSG msg;
338     BOOL ret;
339     CMSG_STREAM_INFO streamInfo = { 0 };
340
341     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
342      NULL);
343     /* Can't update a message that wasn't opened detached with final = FALSE */
344     SetLastError(0xdeadbeef);
345     ret = CryptMsgUpdate(msg, NULL, 0, FALSE);
346     ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
347      "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
348     /* Updating it with final = TRUE succeeds */
349     ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
350     ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
351     /* Any subsequent update will fail, as the last was final */
352     SetLastError(0xdeadbeef);
353     ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
354     ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
355      "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
356     CryptMsgClose(msg);
357
358     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
359      NULL);
360     /* Can't update a message with no data */
361     SetLastError(0xdeadbeef);
362     ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
363     ok(!ret && GetLastError() == E_INVALIDARG,
364      "Expected E_INVALIDARG, got %x\n", GetLastError());
365     /* Curiously, a valid update will now fail as well, presumably because of
366      * the last (invalid, but final) update.
367      */
368     ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
369     ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
370      "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
371     CryptMsgClose(msg);
372
373     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG,
374      CMSG_DATA, NULL, NULL, NULL);
375     /* Doesn't appear to be able to update CMSG-DATA with non-final updates */
376     SetLastError(0xdeadbeef);
377     ret = CryptMsgUpdate(msg, NULL, 0, FALSE);
378     ok(!ret && GetLastError() == E_INVALIDARG,
379      "Expected E_INVALIDARG, got %x\n", GetLastError());
380     SetLastError(0xdeadbeef);
381     ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
382     ok(!ret && GetLastError() == E_INVALIDARG,
383      "Expected E_INVALIDARG, got %x\n", GetLastError());
384     ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
385     ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
386     CryptMsgClose(msg);
387
388     /* Calling update after opening with an empty stream info (with a bogus
389      * output function) yields an error:
390      */
391     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
392      &streamInfo);
393     SetLastError(0xdeadbeef);
394     ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
395     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
396      "Expected STATUS_ACCESS_VIOLATION, got %x\n", GetLastError());
397     CryptMsgClose(msg);
398     /* Calling update with a valid output function succeeds, even if the data
399      * exceeds the size specified in the stream info.
400      */
401     streamInfo.pfnStreamOutput = nop_stream_output;
402     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
403      &streamInfo);
404     ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
405     ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
406     ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
407     ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
408     CryptMsgClose(msg);
409 }
410
411 static void test_data_msg_get_param(void)
412 {
413     HCRYPTMSG msg;
414     DWORD size;
415     BOOL ret;
416     CMSG_STREAM_INFO streamInfo = { 0, nop_stream_output, NULL };
417
418     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
419      NULL);
420
421     /* Content and bare content are always gettable when not streaming */
422     size = 0;
423     ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &size);
424     ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
425     size = 0;
426     ret = CryptMsgGetParam(msg, CMSG_BARE_CONTENT_PARAM, 0, NULL, &size);
427     ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
428     /* But for this type of message, the signer and hash aren't applicable,
429      * and the type isn't available.
430      */
431     size = 0;
432     SetLastError(0xdeadbeef);
433     ret = CryptMsgGetParam(msg, CMSG_ENCODED_SIGNER, 0, NULL, &size);
434     ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE,
435      "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
436     SetLastError(0xdeadbeef);
437     ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &size);
438     ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE,
439      "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
440     ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, NULL, &size);
441     ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE,
442      "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
443     CryptMsgClose(msg);
444
445     /* Can't get content or bare content when streaming */
446     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL,
447      NULL, &streamInfo);
448     SetLastError(0xdeadbeef);
449     ret = CryptMsgGetParam(msg, CMSG_BARE_CONTENT_PARAM, 0, NULL, &size);
450     ok(!ret && GetLastError() == E_INVALIDARG,
451      "Expected E_INVALIDARG, got %x\n", GetLastError());
452     SetLastError(0xdeadbeef);
453     ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &size);
454     ok(!ret && GetLastError() == E_INVALIDARG,
455      "Expected E_INVALIDARG, got %x\n", GetLastError());
456     CryptMsgClose(msg);
457 }
458
459 static const BYTE dataEmptyBareContent[] = { 0x04,0x00 };
460 static const BYTE dataEmptyContent[] = {
461 0x30,0x0f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x02,
462 0x04,0x00 };
463 static const BYTE dataBareContent[] = { 0x04,0x04,0x01,0x02,0x03,0x04 };
464 static const BYTE dataContent[] = {
465 0x30,0x13,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x06,
466 0x04,0x04,0x01,0x02,0x03,0x04 };
467
468 struct update_accum
469 {
470     DWORD cUpdates;
471     CRYPT_DATA_BLOB *updates;
472 };
473
474 static BOOL WINAPI accumulating_stream_output(const void *pvArg, BYTE *pb,
475  DWORD cb, BOOL final)
476 {
477     struct update_accum *accum = (struct update_accum *)pvArg;
478     BOOL ret = FALSE;
479
480     if (accum->cUpdates)
481         accum->updates = CryptMemRealloc(accum->updates,
482          (accum->cUpdates + 1) * sizeof(CRYPT_DATA_BLOB));
483     else
484         accum->updates = CryptMemAlloc(sizeof(CRYPT_DATA_BLOB));
485     if (accum->updates)
486     {
487         CRYPT_DATA_BLOB *blob = &accum->updates[accum->cUpdates];
488
489         blob->pbData = CryptMemAlloc(cb);
490         if (blob->pbData)
491         {
492             memcpy(blob->pbData, pb, cb);
493             blob->cbData = cb;
494             ret = TRUE;
495         }
496         accum->cUpdates++;
497     }
498     return ret;
499 }
500
501 /* The updates of a (bogus) definite-length encoded message */
502 static BYTE u1[] = { 0x30,0x0f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
503  0x07,0x01,0xa0,0x02,0x04,0x00 };
504 static BYTE u2[] = { 0x01,0x02,0x03,0x04 };
505 static CRYPT_DATA_BLOB b1[] = {
506     { sizeof(u1), u1 },
507     { sizeof(u2), u2 },
508     { sizeof(u2), u2 },
509 };
510 static const struct update_accum a1 = { sizeof(b1) / sizeof(b1[0]), b1 };
511 /* The updates of a definite-length encoded message */
512 static BYTE u3[] = { 0x30,0x13,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
513  0x07,0x01,0xa0,0x06,0x04,0x04 };
514 static CRYPT_DATA_BLOB b2[] = {
515     { sizeof(u3), u3 },
516     { sizeof(u2), u2 },
517 };
518 static const struct update_accum a2 = { sizeof(b2) / sizeof(b2[0]), b2 };
519 /* The updates of an indefinite-length encoded message */
520 static BYTE u4[] = { 0x30,0x80,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
521  0x07,0x01,0xa0,0x80,0x24,0x80 };
522 static BYTE u5[] = { 0x04,0x04 };
523 static BYTE u6[] = { 0x00,0x00,0x00,0x00,0x00,0x00 };
524 static CRYPT_DATA_BLOB b3[] = {
525     { sizeof(u4), u4 },
526     { sizeof(u5), u5 },
527     { sizeof(u2), u2 },
528     { sizeof(u5), u5 },
529     { sizeof(u2), u2 },
530     { sizeof(u6), u6 },
531 };
532 static const struct update_accum a3 = { sizeof(b3) / sizeof(b3[0]), b3 };
533
534 static void check_updates(LPCSTR header, const struct update_accum *expected,
535  const struct update_accum *got)
536 {
537     DWORD i;
538
539     ok(expected->cUpdates == got->cUpdates,
540      "%s: expected %d updates, got %d\n", header, expected->cUpdates,
541      got->cUpdates);
542     if (expected->cUpdates == got->cUpdates)
543         for (i = 0; i < min(expected->cUpdates, got->cUpdates); i++)
544         {
545             ok(expected->updates[i].cbData == got->updates[i].cbData,
546              "%s, update %d: expected %d bytes, got %d\n", header, i,
547              expected->updates[i].cbData, got->updates[i].cbData);
548             if (expected->updates[i].cbData && expected->updates[i].cbData ==
549              got->updates[i].cbData)
550                 ok(!memcmp(expected->updates[i].pbData, got->updates[i].pbData,
551                  got->updates[i].cbData), "%s, update %d: unexpected value\n",
552                  header, i);
553         }
554 }
555
556 /* Frees the updates stored in accum */
557 static void free_updates(struct update_accum *accum)
558 {
559     DWORD i;
560
561     for (i = 0; i < accum->cUpdates; i++)
562         CryptMemFree(accum->updates[i].pbData);
563     CryptMemFree(accum->updates);
564     accum->updates = NULL;
565     accum->cUpdates = 0;
566 }
567
568 static void test_data_msg_encoding(void)
569 {
570     HCRYPTMSG msg;
571     BOOL ret;
572     static char oid[] = "1.2.3";
573     struct update_accum accum = { 0, NULL };
574     CMSG_STREAM_INFO streamInfo = { 0, accumulating_stream_output, &accum };
575
576     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
577      NULL);
578     check_param("data empty bare content", msg, CMSG_BARE_CONTENT_PARAM,
579      dataEmptyBareContent, sizeof(dataEmptyBareContent));
580     check_param("data empty content", msg, CMSG_CONTENT_PARAM, dataEmptyContent,
581      sizeof(dataEmptyContent));
582     ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
583     ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
584     check_param("data bare content", msg, CMSG_BARE_CONTENT_PARAM,
585      dataBareContent, sizeof(dataBareContent));
586     check_param("data content", msg, CMSG_CONTENT_PARAM, dataContent,
587      sizeof(dataContent));
588     CryptMsgClose(msg);
589     /* Same test, but with CMSG_BARE_CONTENT_FLAG set */
590     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_BARE_CONTENT_FLAG,
591      CMSG_DATA, NULL, NULL, NULL);
592     check_param("data empty bare content", msg, CMSG_BARE_CONTENT_PARAM,
593      dataEmptyBareContent, sizeof(dataEmptyBareContent));
594     check_param("data empty content", msg, CMSG_CONTENT_PARAM, dataEmptyContent,
595      sizeof(dataEmptyContent));
596     ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
597     ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
598     check_param("data bare content", msg, CMSG_BARE_CONTENT_PARAM,
599      dataBareContent, sizeof(dataBareContent));
600     check_param("data content", msg, CMSG_CONTENT_PARAM, dataContent,
601      sizeof(dataContent));
602     CryptMsgClose(msg);
603     /* The inner OID is apparently ignored */
604     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, oid,
605      NULL);
606     check_param("data bogus oid bare content", msg, CMSG_BARE_CONTENT_PARAM,
607      dataEmptyBareContent, sizeof(dataEmptyBareContent));
608     check_param("data bogus oid content", msg, CMSG_CONTENT_PARAM,
609      dataEmptyContent, sizeof(dataEmptyContent));
610     ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
611     ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
612     check_param("data bare content", msg, CMSG_BARE_CONTENT_PARAM,
613      dataBareContent, sizeof(dataBareContent));
614     check_param("data content", msg, CMSG_CONTENT_PARAM, dataContent,
615      sizeof(dataContent));
616     CryptMsgClose(msg);
617     /* A streaming message is DER encoded if the length is not 0xffffffff, but
618      * curiously, updates aren't validated to make sure they don't exceed the
619      * stated length.  (The resulting output will of course fail to decode.)
620      */
621     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL,
622      NULL, &streamInfo);
623     CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
624     CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
625     CryptMsgClose(msg);
626     check_updates("bogus data message with definite length", &a1, &accum);
627     free_updates(&accum);
628     /* A valid definite-length encoding: */
629     streamInfo.cbContent = sizeof(msgData);
630     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL,
631      NULL, &streamInfo);
632     CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
633     CryptMsgClose(msg);
634     check_updates("data message with definite length", &a2, &accum);
635     free_updates(&accum);
636     /* An indefinite-length encoding: */
637     streamInfo.cbContent = 0xffffffff;
638     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL,
639      NULL, &streamInfo);
640     CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
641     CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
642     CryptMsgClose(msg);
643     todo_wine
644     check_updates("data message with indefinite length", &a3, &accum);
645     free_updates(&accum);
646 }
647
648 static void test_data_msg(void)
649 {
650     test_data_msg_open();
651     test_data_msg_update();
652     test_data_msg_get_param();
653     test_data_msg_encoding();
654 }
655
656 static void test_hash_msg_open(void)
657 {
658     HCRYPTMSG msg;
659     CMSG_HASHED_ENCODE_INFO hashInfo = { 0 };
660     static char oid_rsa_md5[] = szOID_RSA_MD5;
661     CMSG_STREAM_INFO streamInfo = { 0, nop_stream_output, NULL };
662
663     SetLastError(0xdeadbeef);
664     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
665      NULL, NULL);
666     ok(!msg && GetLastError() == E_INVALIDARG,
667      "Expected E_INVALIDARG, got %x\n", GetLastError());
668     hashInfo.cbSize = sizeof(hashInfo);
669     SetLastError(0xdeadbeef);
670     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
671      NULL, NULL);
672     ok(!msg && GetLastError() == CRYPT_E_UNKNOWN_ALGO,
673      "Expected CRYPT_E_UNKNOWN_ALGO, got %x\n", GetLastError());
674     hashInfo.HashAlgorithm.pszObjId = oid_rsa_md5;
675     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
676      NULL, NULL);
677     ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
678     CryptMsgClose(msg);
679     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG,
680      CMSG_HASHED, &hashInfo, NULL, NULL);
681     ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
682     CryptMsgClose(msg);
683     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG,
684      CMSG_HASHED, &hashInfo, NULL, &streamInfo);
685     ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
686     CryptMsgClose(msg);
687 }
688
689 static void test_hash_msg_update(void)
690 {
691     HCRYPTMSG msg;
692     BOOL ret;
693     static char oid_rsa_md5[] = szOID_RSA_MD5;
694     CMSG_HASHED_ENCODE_INFO hashInfo = { sizeof(hashInfo), 0,
695      { oid_rsa_md5, { 0, NULL } }, NULL };
696     CMSG_STREAM_INFO streamInfo = { 0, nop_stream_output, NULL };
697
698     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG,
699      CMSG_HASHED, &hashInfo, NULL, NULL);
700     /* Detached hashed messages opened in non-streaming mode allow non-final
701      * updates..
702      */
703     ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
704     todo_wine
705     ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
706     /* including non-final updates with no data.. */
707     ret = CryptMsgUpdate(msg, NULL, 0, FALSE);
708     todo_wine
709     ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
710     /* and final updates with no data. */
711     ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
712     todo_wine
713     ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
714     /* But no updates are allowed after the final update. */
715     SetLastError(0xdeadbeef);
716     ret = CryptMsgUpdate(msg, NULL, 0, FALSE);
717     todo_wine
718     ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
719      "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
720     SetLastError(0xdeadbeef);
721     ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
722     todo_wine
723     ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
724      "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
725     CryptMsgClose(msg);
726     /* Non-detached messages, in contrast, don't allow non-final updates in
727      * non-streaming mode.
728      */
729     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
730      NULL, NULL);
731     SetLastError(0xdeadbeef);
732     ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
733     todo_wine
734     ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
735      "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
736     /* Final updates (including empty ones) are allowed. */
737     ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
738     todo_wine
739     ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
740     CryptMsgClose(msg);
741     /* And, of course, streaming mode allows non-final updates */
742     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
743      NULL, &streamInfo);
744     ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
745     todo_wine
746     ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
747     CryptMsgClose(msg);
748 }
749
750 static const BYTE emptyHashParam[] = {
751 0xd4,0x1d,0x8c,0xd9,0x8f,0x00,0xb2,0x04,0xe9,0x80,0x09,0x98,0xec,0xf8,0x42,
752 0x7e };
753
754 static void test_hash_msg_get_param(void)
755 {
756     HCRYPTMSG msg;
757     BOOL ret;
758     static char oid_rsa_md5[] = szOID_RSA_MD5;
759     CMSG_HASHED_ENCODE_INFO hashInfo = { sizeof(hashInfo), 0,
760      { oid_rsa_md5, { 0, NULL } }, NULL };
761     DWORD size, value;
762     CMSG_STREAM_INFO streamInfo = { 0, nop_stream_output, NULL };
763     BYTE buf[16];
764
765     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
766      NULL, NULL);
767     /* Content and bare content are always gettable for non-streamed messages */
768     size = 0;
769     ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &size);
770     todo_wine {
771     ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
772     size = 0;
773     ret = CryptMsgGetParam(msg, CMSG_BARE_CONTENT_PARAM, 0, NULL, &size);
774     ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
775     }
776     /* The hash is also available. */
777     size = 0;
778     ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &size);
779     todo_wine {
780     ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
781     ok(size == sizeof(buf), "Unexpected size %d\n", size);
782     ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, buf, &size);
783     }
784     if (size == sizeof(buf))
785         ok(!memcmp(buf, emptyHashParam, size), "Unexpected value\n");
786
787     CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
788     size = 0;
789     ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &size);
790     todo_wine {
791     ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
792     ok(size == sizeof(buf), "Unexpected size %d\n", size);
793     ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, buf, &size);
794     ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
795     }
796     /* Oddly, the hash doesn't seem to change even after an update */
797     ok(!memcmp(buf, emptyHashParam, size), "Unexpected value\n");
798     /* So is the version. */
799     size = 0;
800     ret = CryptMsgGetParam(msg, CMSG_VERSION_PARAM, 0, NULL, &size);
801     todo_wine
802     ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
803     size = sizeof(value);
804     ret = CryptMsgGetParam(msg, CMSG_VERSION_PARAM, 0, (LPBYTE)&value, &size);
805     todo_wine {
806     ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
807     ok(value == 0, "Expected version 0, got %d\n", value);
808     }
809     /* As usual, the type isn't available. */
810     ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, NULL, &size);
811     todo_wine
812     ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE,
813      "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
814     CryptMsgClose(msg);
815
816     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
817      NULL, &streamInfo);
818     /* Streamed messages don't allow you to get the content or bare content. */
819     SetLastError(0xdeadbeef);
820     ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &size);
821     todo_wine {
822     ok(!ret && GetLastError() == E_INVALIDARG,
823      "Expected E_INVALIDARG, got %x\n", GetLastError());
824     SetLastError(0xdeadbeef);
825     ret = CryptMsgGetParam(msg, CMSG_BARE_CONTENT_PARAM, 0, NULL, &size);
826     ok(!ret && GetLastError() == E_INVALIDARG,
827      "Expected E_INVALIDARG, got %x\n", GetLastError());
828     }
829     /* The hash is still available. */
830     size = 0;
831     ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &size);
832     todo_wine {
833     ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
834     ok(size == sizeof(buf), "Unexpected size %d\n", size);
835     ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, buf, &size);
836     ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
837     }
838     if (size == sizeof(buf))
839         ok(!memcmp(buf, emptyHashParam, size), "Unexpected value\n");
840     /* An empty update has no effect on the hash */
841     CryptMsgUpdate(msg, NULL, 0, FALSE);
842     size = 0;
843     ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &size);
844     todo_wine {
845     ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
846     ok(size == sizeof(buf), "Unexpected size %d\n", size);
847     ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, buf, &size);
848     ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
849     }
850     if (size == sizeof(buf))
851         ok(!memcmp(buf, emptyHashParam, size), "Unexpected value\n");
852     /* A non-empty update doesn't appear to either? */
853     CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
854     size = 0;
855     ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &size);
856     todo_wine {
857     ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
858     ok(size == sizeof(buf), "Unexpected size %d\n", size);
859     ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, buf, &size);
860     ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
861     }
862     if (size == sizeof(buf))
863         ok(!memcmp(buf, emptyHashParam, size), "Unexpected value\n");
864     CryptMsgClose(msg);
865     /* A detached message similarly has a non-updating hash */
866     msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG,
867      CMSG_HASHED, &hashInfo, NULL, NULL);
868     size = 0;
869     ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &size);
870     todo_wine {
871     ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
872     ok(size == sizeof(buf), "Unexpected size %d\n", size);
873     ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, buf, &size);
874     ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
875     }
876     if (size == sizeof(buf))
877         ok(!memcmp(buf, emptyHashParam, size), "Unexpected value\n");
878     CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
879     size = 0;
880     ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &size);
881     todo_wine {
882     ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
883     ok(size == sizeof(buf), "Unexpected size %d\n", size);
884     ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, buf, &size);
885     ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
886     }
887     if (size == sizeof(buf))
888         ok(!memcmp(buf, emptyHashParam, size), "Unexpected value\n");
889     CryptMsgClose(msg);
890 }
891
892 static void test_hash_msg(void)
893 {
894     test_hash_msg_open();
895     test_hash_msg_update();
896     test_hash_msg_get_param();
897 }
898
899 static CRYPT_DATA_BLOB b4 = { 0, NULL };
900 static const struct update_accum a4 = { 1, &b4 };
901
902 static const BYTE bogusOIDContent[] = {
903 0x30,0x0f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x07,0xa0,0x02,
904 0x04,0x00 };
905
906 static void test_decode_msg_update(void)
907 {
908     HCRYPTMSG msg;
909     BOOL ret;
910     CMSG_STREAM_INFO streamInfo = { 0 };
911     DWORD i;
912     struct update_accum accum = { 0, NULL };
913
914     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
915     /* Update with a full message in a final update */
916     ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent), TRUE);
917     todo_wine
918     ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
919     /* Can't update after a final update */
920     SetLastError(0xdeadbeef);
921     ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent), TRUE);
922     todo_wine
923     ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
924      "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
925     CryptMsgClose(msg);
926
927     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
928     /* Can't send a non-final update without streaming */
929     SetLastError(0xdeadbeef);
930     ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent),
931      FALSE);
932     todo_wine
933     ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
934      "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
935     /* A subsequent final update succeeds */
936     ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent), TRUE);
937     todo_wine
938     ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
939     CryptMsgClose(msg);
940
941     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, &streamInfo);
942     /* Updating a message that has a NULL stream callback fails */
943     SetLastError(0xdeadbeef);
944     ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent),
945      FALSE);
946     todo_wine
947     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
948      "Expected STATUS_ACCESS_VIOLATION, got %x\n", GetLastError());
949     /* Changing the callback pointer after the fact yields the same error (so
950      * the message must copy the stream info, not just store a pointer to it)
951      */
952     streamInfo.pfnStreamOutput = nop_stream_output;
953     SetLastError(0xdeadbeef);
954     ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent),
955      FALSE);
956     todo_wine
957     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
958      "Expected STATUS_ACCESS_VIOLATION, got %x\n", GetLastError());
959     CryptMsgClose(msg);
960
961     /* Empty non-final updates are allowed when streaming.. */
962     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, &streamInfo);
963     ret = CryptMsgUpdate(msg, NULL, 0, FALSE);
964     todo_wine
965     ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
966     /* but final updates aren't when not enough data has been received. */
967     SetLastError(0xdeadbeef);
968     ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
969     todo_wine
970     ok(!ret && GetLastError() == CRYPT_E_STREAM_INSUFFICIENT_DATA,
971      "Expected CRYPT_E_STREAM_INSUFFICIENT_DATA, got %x\n", GetLastError());
972     CryptMsgClose(msg);
973
974     /* Updating the message byte by byte is legal */
975     streamInfo.pfnStreamOutput = accumulating_stream_output;
976     streamInfo.pvArg = &accum;
977     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, &streamInfo);
978     for (i = 0, ret = TRUE; ret && i < sizeof(dataEmptyContent); i++)
979         ret = CryptMsgUpdate(msg, &dataEmptyContent[i], 1, FALSE);
980     todo_wine {
981     ok(ret, "CryptMsgUpdate failed on byte %d: %x\n", i, GetLastError());
982     ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
983     ok(ret, "CryptMsgUpdate failed on byte %d: %x\n", i, GetLastError());
984     }
985     CryptMsgClose(msg);
986     todo_wine
987     check_updates("byte-by-byte empty content", &a4, &accum);
988     free_updates(&accum);
989
990     /* Decoding bogus content fails in non-streaming mode.. */
991     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
992     SetLastError(0xdeadbeef);
993     ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
994     todo_wine
995     ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
996      "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
997     CryptMsgClose(msg);
998     /* and as the final update in streaming mode.. */
999     streamInfo.pfnStreamOutput = nop_stream_output;
1000     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, &streamInfo);
1001     SetLastError(0xdeadbeef);
1002     ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
1003     todo_wine
1004     ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1005      "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
1006     CryptMsgClose(msg);
1007     /* and even as a non-final update in streaming mode. */
1008     streamInfo.pfnStreamOutput = nop_stream_output;
1009     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, &streamInfo);
1010     SetLastError(0xdeadbeef);
1011     ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
1012     todo_wine
1013     ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1014      "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
1015     CryptMsgClose(msg);
1016
1017     /* An empty message can be opened with indetermined type.. */
1018     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1019     ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent),
1020      TRUE);
1021     todo_wine
1022     ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1023     /* but decoding it as an explicitly typed message fails. */
1024     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, 0, NULL,
1025      NULL);
1026     SetLastError(0xdeadbeef);
1027     ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent),
1028      TRUE);
1029     todo_wine
1030     ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1031      "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
1032     CryptMsgClose(msg);
1033     /* On the other hand, decoding the bare content of an empty message fails
1034      * with unspecified type..
1035      */
1036     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1037     SetLastError(0xdeadbeef);
1038     ret = CryptMsgUpdate(msg, dataEmptyBareContent,
1039      sizeof(dataEmptyBareContent), TRUE);
1040     todo_wine
1041     ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1042      "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
1043     CryptMsgClose(msg);
1044     /* but succeeds with explicit type. */
1045     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, 0, NULL,
1046      NULL);
1047     ret = CryptMsgUpdate(msg, dataEmptyBareContent,
1048      sizeof(dataEmptyBareContent), TRUE);
1049     todo_wine
1050     ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1051     CryptMsgClose(msg);
1052
1053     /* Decoding valid content with an unsupported OID fails */
1054     msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1055     SetLastError(0xdeadbeef);
1056     ret = CryptMsgUpdate(msg, bogusOIDContent, sizeof(bogusOIDContent), TRUE);
1057     todo_wine
1058     ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE,
1059      "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
1060     CryptMsgClose(msg);
1061 }
1062
1063 static void test_decode_msg(void)
1064 {
1065     test_decode_msg_update();
1066 }
1067
1068 START_TEST(msg)
1069 {
1070     /* Basic parameter checking tests */
1071     test_msg_open_to_encode();
1072     test_msg_open_to_decode();
1073     test_msg_get_param();
1074     test_msg_close();
1075
1076     /* Message-type specific tests */
1077     test_data_msg();
1078     test_hash_msg();
1079     test_decode_msg();
1080 }