crypt32: Add tests for updating signed encoded messages.
[wine/multimedia.git] / dlls / crypt32 / tests / msg.c
blob250ac9f9986e7d7472953187d70269e6713a1f18
1 /*
2 * Unit test suite for crypt32.dll's CryptMsg functions
4 * Copyright 2007 Juan Lang
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.
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.
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
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <windef.h>
24 #include <winbase.h>
25 #include <winerror.h>
26 #include <wincrypt.h>
28 #include "wine/test.h"
30 static void test_msg_open_to_encode(void)
32 HCRYPTMSG msg;
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);
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());
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());
75 static void test_msg_open_to_decode(void)
77 HCRYPTMSG msg;
78 CMSG_STREAM_INFO streamInfo = { 0 };
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());
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());
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);
129 /* And even though the stream info parameter "must be set to NULL" for
130 * CMSG_HASHED, it's still accepted.
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);
138 static void test_msg_get_param(void)
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 };
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);
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);
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++)
176 size = 0;
177 ret = CryptMsgGetParam(msg, i, 0, NULL, &size);
178 ok(!ret, "Parameter %d: expected failure\n", i);
180 CryptMsgClose(msg);
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++)
191 size = 0;
192 ret = CryptMsgGetParam(msg, i, 0, NULL, &size);
193 ok(!ret, "Parameter %d: expected failure\n", i);
195 CryptMsgClose(msg);
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++)
206 size = 0;
207 ret = CryptMsgGetParam(msg, i, 0, NULL, &size);
208 ok(!ret, "Parameter %d: expected failure\n", i);
210 CryptMsgClose(msg);
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++)
221 size = 0;
222 ret = CryptMsgGetParam(msg, i, 0, NULL, &size);
223 ok(!ret, "Parameter %d: expected failure\n", i);
225 CryptMsgClose(msg);
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);
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);
246 static void test_msg_close(void)
248 BOOL ret;
249 HCRYPTMSG msg;
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());
264 static void check_param(LPCSTR test, HCRYPTMSG msg, DWORD param,
265 const BYTE *expected, DWORD expectedSize)
267 DWORD size;
268 LPBYTE buf;
269 BOOL ret;
271 size = 0xdeadbeef;
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 == expectedSize && size)
280 ok(!memcmp(buf, expected, size), "%s: unexpected data\n", test);
281 HeapFree(GetProcessHeap(), 0, buf);
284 static void test_data_msg_open(void)
286 HCRYPTMSG msg;
287 CMSG_HASHED_ENCODE_INFO hashInfo = { 0 };
288 CMSG_STREAM_INFO streamInfo = { 0 };
289 char oid[] = "1.2.3";
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);
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);
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.
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);
327 static const BYTE msgData[] = { 1, 2, 3, 4 };
329 static BOOL WINAPI nop_stream_output(const void *pvArg, BYTE *pb, DWORD cb,
330 BOOL final)
332 return TRUE;
335 static void test_data_msg_update(void)
337 HCRYPTMSG msg;
338 BOOL ret;
339 CMSG_STREAM_INFO streamInfo = { 0 };
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);
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.
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);
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);
388 /* Calling update after opening with an empty stream info (with a bogus
389 * output function) yields an error:
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.
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);
411 static void test_data_msg_get_param(void)
413 HCRYPTMSG msg;
414 DWORD size;
415 BOOL ret;
416 CMSG_STREAM_INFO streamInfo = { 0, nop_stream_output, NULL };
418 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
419 NULL);
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.
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);
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);
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 };
468 struct update_accum
470 DWORD cUpdates;
471 CRYPT_DATA_BLOB *updates;
474 static BOOL WINAPI accumulating_stream_output(const void *pvArg, BYTE *pb,
475 DWORD cb, BOOL final)
477 struct update_accum *accum = (struct update_accum *)pvArg;
478 BOOL ret = FALSE;
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)
487 CRYPT_DATA_BLOB *blob = &accum->updates[accum->cUpdates];
489 blob->pbData = CryptMemAlloc(cb);
490 if (blob->pbData)
492 memcpy(blob->pbData, pb, cb);
493 blob->cbData = cb;
494 ret = TRUE;
496 accum->cUpdates++;
498 return ret;
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 },
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 },
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 },
532 static const struct update_accum a3 = { sizeof(b3) / sizeof(b3[0]), b3 };
534 static void check_updates(LPCSTR header, const struct update_accum *expected,
535 const struct update_accum *got)
537 DWORD i;
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++)
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);
556 /* Frees the updates stored in accum */
557 static void free_updates(struct update_accum *accum)
559 DWORD i;
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;
568 static void test_data_msg_encoding(void)
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 };
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.)
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);
648 static void test_data_msg(void)
650 test_data_msg_open();
651 test_data_msg_update();
652 test_data_msg_get_param();
653 test_data_msg_encoding();
656 static void test_hash_msg_open(void)
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 };
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);
689 static void test_hash_msg_update(void)
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 };
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..
703 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
704 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
705 /* including non-final updates with no data.. */
706 ret = CryptMsgUpdate(msg, NULL, 0, FALSE);
707 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
708 /* and final updates with no data. */
709 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
710 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
711 /* But no updates are allowed after the final update. */
712 SetLastError(0xdeadbeef);
713 ret = CryptMsgUpdate(msg, NULL, 0, FALSE);
714 ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
715 "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
716 SetLastError(0xdeadbeef);
717 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
718 ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
719 "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
720 CryptMsgClose(msg);
721 /* Non-detached messages, in contrast, don't allow non-final updates in
722 * non-streaming mode.
724 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
725 NULL, NULL);
726 SetLastError(0xdeadbeef);
727 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
728 ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
729 "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
730 /* Final updates (including empty ones) are allowed. */
731 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
732 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
733 CryptMsgClose(msg);
734 /* And, of course, streaming mode allows non-final updates */
735 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
736 NULL, &streamInfo);
737 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
738 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
739 CryptMsgClose(msg);
740 /* Setting pfnStreamOutput to NULL results in no error. (In what appears
741 * to be a bug, it isn't actually used - see encoding tests.)
743 streamInfo.pfnStreamOutput = NULL;
744 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
745 NULL, &streamInfo);
746 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
747 ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError());
748 CryptMsgClose(msg);
751 static const BYTE emptyHashParam[] = {
752 0xd4,0x1d,0x8c,0xd9,0x8f,0x00,0xb2,0x04,0xe9,0x80,0x09,0x98,0xec,0xf8,0x42,
753 0x7e };
755 static void test_hash_msg_get_param(void)
757 HCRYPTMSG msg;
758 BOOL ret;
759 static char oid_rsa_md5[] = szOID_RSA_MD5;
760 CMSG_HASHED_ENCODE_INFO hashInfo = { sizeof(hashInfo), 0,
761 { oid_rsa_md5, { 0, NULL } }, NULL };
762 DWORD size, value;
763 CMSG_STREAM_INFO streamInfo = { 0, nop_stream_output, NULL };
764 BYTE buf[16];
766 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
767 NULL, NULL);
768 /* Content and bare content are always gettable for non-streamed messages */
769 size = 0;
770 ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &size);
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 /* The hash is also available. */
776 size = 0;
777 ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &size);
778 ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
779 ok(size == sizeof(buf), "Unexpected size %d\n", size);
780 ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, buf, &size);
781 if (size == sizeof(buf))
782 ok(!memcmp(buf, emptyHashParam, size), "Unexpected value\n");
783 /* By getting the hash, further updates are not allowed */
784 SetLastError(0xdeadbeef);
785 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
786 ok(!ret && GetLastError() == NTE_BAD_HASH_STATE,
787 "Expected NTE_BAD_HASH_STATE, got %x\n", GetLastError());
788 /* The version is also available, and should be zero for this message. */
789 size = 0;
790 ret = CryptMsgGetParam(msg, CMSG_VERSION_PARAM, 0, NULL, &size);
791 ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
792 size = sizeof(value);
793 ret = CryptMsgGetParam(msg, CMSG_VERSION_PARAM, 0, (LPBYTE)&value, &size);
794 ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
795 ok(value == 0, "Expected version 0, got %d\n", value);
796 /* As usual, the type isn't available. */
797 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, NULL, &size);
798 ok(!ret, "Expected failure\n");
799 CryptMsgClose(msg);
801 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
802 NULL, &streamInfo);
803 /* Streamed messages don't allow you to get the content or bare content. */
804 SetLastError(0xdeadbeef);
805 ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &size);
806 ok(!ret && GetLastError() == E_INVALIDARG,
807 "Expected E_INVALIDARG, got %x\n", GetLastError());
808 SetLastError(0xdeadbeef);
809 ret = CryptMsgGetParam(msg, CMSG_BARE_CONTENT_PARAM, 0, NULL, &size);
810 ok(!ret && GetLastError() == E_INVALIDARG,
811 "Expected E_INVALIDARG, got %x\n", GetLastError());
812 /* The hash is still available. */
813 size = 0;
814 ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &size);
815 ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
816 ok(size == sizeof(buf), "Unexpected size %d\n", size);
817 ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, buf, &size);
818 ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
819 if (size == sizeof(buf))
820 ok(!memcmp(buf, emptyHashParam, size), "Unexpected value\n");
821 /* After updating the hash, further updates aren't allowed on streamed
822 * messages either.
824 SetLastError(0xdeadbeef);
825 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
826 ok(!ret && GetLastError() == NTE_BAD_HASH_STATE,
827 "Expected NTE_BAD_HASH_STATE, got %x\n", GetLastError());
828 CryptMsgClose(msg);
831 static const BYTE hashEmptyBareContent[] = {
832 0x30,0x17,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,
833 0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0x04,0x00 };
834 static const BYTE hashEmptyContent[] = {
835 0x30,0x26,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x05,0xa0,0x19,
836 0x30,0x17,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,
837 0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0x04,0x00 };
838 static const BYTE hashBareContent[] = {
839 0x30,0x38,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,
840 0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
841 0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04,0x04,0x10,0x08,0xd6,0xc0,
842 0x5a,0x21,0x51,0x2a,0x79,0xa1,0xdf,0xeb,0x9d,0x2a,0x8f,0x26,0x2f };
843 static const BYTE hashContent[] = {
844 0x30,0x47,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x05,0xa0,0x3a,
845 0x30,0x38,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,
846 0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
847 0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04,0x04,0x10,0x08,0xd6,0xc0,
848 0x5a,0x21,0x51,0x2a,0x79,0xa1,0xdf,0xeb,0x9d,0x2a,0x8f,0x26,0x2f };
850 static const BYTE detachedHashNonFinalBareContent[] = {
851 0x30,0x20,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,
852 0x02,0x05,0x05,0x00,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
853 0x07,0x01,0x04,0x00 };
854 static const BYTE detachedHashNonFinalContent[] = {
855 0x30,0x2f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x05,0xa0,0x22,
856 0x30,0x20,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,
857 0x02,0x05,0x05,0x00,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
858 0x07,0x01,0x04,0x00 };
859 static const BYTE detachedHashBareContent[] = {
860 0x30,0x30,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,
861 0x02,0x05,0x05,0x00,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
862 0x07,0x01,0x04,0x10,0x08,0xd6,0xc0,0x5a,0x21,0x51,0x2a,0x79,0xa1,0xdf,0xeb,
863 0x9d,0x2a,0x8f,0x26,0x2f };
864 static const BYTE detachedHashContent[] = {
865 0x30,0x3f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x05,0xa0,0x32,
866 0x30,0x30,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,
867 0x02,0x05,0x05,0x00,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
868 0x07,0x01,0x04,0x10,0x08,0xd6,0xc0,0x5a,0x21,0x51,0x2a,0x79,0xa1,0xdf,0xeb,
869 0x9d,0x2a,0x8f,0x26,0x2f };
871 static void test_hash_msg_encoding(void)
873 HCRYPTMSG msg;
874 CMSG_HASHED_ENCODE_INFO hashInfo = { sizeof(hashInfo), 0 };
875 BOOL ret;
876 struct update_accum accum = { 0, NULL }, empty_accum = { 0, NULL };
877 CMSG_STREAM_INFO streamInfo = { 0, accumulating_stream_output, &accum };
878 static char oid_rsa_md5[] = szOID_RSA_MD5;
880 hashInfo.HashAlgorithm.pszObjId = oid_rsa_md5;
881 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
882 NULL, NULL);
883 check_param("hash empty bare content", msg, CMSG_BARE_CONTENT_PARAM,
884 hashEmptyBareContent, sizeof(hashEmptyBareContent));
885 check_param("hash empty content", msg, CMSG_CONTENT_PARAM,
886 hashEmptyContent, sizeof(hashEmptyContent));
887 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
888 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
889 check_param("hash bare content", msg, CMSG_BARE_CONTENT_PARAM,
890 hashBareContent, sizeof(hashBareContent));
891 check_param("hash content", msg, CMSG_CONTENT_PARAM,
892 hashContent, sizeof(hashContent));
893 CryptMsgClose(msg);
894 /* Same test, but with CMSG_BARE_CONTENT_FLAG set */
895 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_BARE_CONTENT_FLAG,
896 CMSG_HASHED, &hashInfo, NULL, NULL);
897 check_param("hash empty bare content", msg, CMSG_BARE_CONTENT_PARAM,
898 hashEmptyBareContent, sizeof(hashEmptyBareContent));
899 check_param("hash empty content", msg, CMSG_CONTENT_PARAM,
900 hashEmptyContent, sizeof(hashEmptyContent));
901 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
902 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
903 check_param("hash bare content", msg, CMSG_BARE_CONTENT_PARAM,
904 hashBareContent, sizeof(hashBareContent));
905 check_param("hash content", msg, CMSG_CONTENT_PARAM,
906 hashContent, sizeof(hashContent));
907 CryptMsgClose(msg);
908 /* Same test, but with CMSG_DETACHED_FLAG set */
909 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG,
910 CMSG_HASHED, &hashInfo, NULL, NULL);
911 check_param("detached hash empty bare content", msg,
912 CMSG_BARE_CONTENT_PARAM, hashEmptyBareContent,
913 sizeof(hashEmptyBareContent));
914 check_param("detached hash empty content", msg, CMSG_CONTENT_PARAM,
915 hashEmptyContent, sizeof(hashEmptyContent));
916 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
917 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
918 check_param("detached hash not final bare content", msg,
919 CMSG_BARE_CONTENT_PARAM, detachedHashNonFinalBareContent,
920 sizeof(detachedHashNonFinalBareContent));
921 check_param("detached hash not final content", msg, CMSG_CONTENT_PARAM,
922 detachedHashNonFinalContent, sizeof(detachedHashNonFinalContent));
923 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
924 ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError());
925 check_param("detached hash bare content", msg, CMSG_BARE_CONTENT_PARAM,
926 detachedHashBareContent, sizeof(detachedHashBareContent));
927 check_param("detached hash content", msg, CMSG_CONTENT_PARAM,
928 detachedHashContent, sizeof(detachedHashContent));
929 check_param("detached hash bare content", msg, CMSG_BARE_CONTENT_PARAM,
930 detachedHashBareContent, sizeof(detachedHashBareContent));
931 check_param("detached hash content", msg, CMSG_CONTENT_PARAM,
932 detachedHashContent, sizeof(detachedHashContent));
933 CryptMsgClose(msg);
934 /* In what appears to be a bug, streamed updates to hash messages don't
935 * call the output function.
937 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
938 NULL, &streamInfo);
939 ret = CryptMsgUpdate(msg, NULL, 0, FALSE);
940 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
941 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
942 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
943 CryptMsgClose(msg);
944 check_updates("empty hash message", &empty_accum, &accum);
945 free_updates(&accum);
947 streamInfo.cbContent = sizeof(msgData);
948 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
949 NULL, &streamInfo);
950 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
951 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
952 CryptMsgClose(msg);
953 check_updates("hash message", &empty_accum, &accum);
954 free_updates(&accum);
956 streamInfo.cbContent = sizeof(msgData);
957 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG,
958 CMSG_HASHED, &hashInfo, NULL, &streamInfo);
959 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
960 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
961 CryptMsgClose(msg);
962 check_updates("detached hash message", &empty_accum, &accum);
963 free_updates(&accum);
966 static void test_hash_msg(void)
968 test_hash_msg_open();
969 test_hash_msg_update();
970 test_hash_msg_get_param();
971 test_hash_msg_encoding();
974 static const WCHAR cspNameW[] = { 'W','i','n','e','C','r','y','p','t','T','e',
975 'm','p',0 };
976 static BYTE serialNum[] = { 1 };
977 static BYTE encodedCommonName[] = { 0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,
978 0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
980 static void test_signed_msg_open(void)
982 HCRYPTMSG msg;
983 BOOL ret;
984 CMSG_SIGNED_ENCODE_INFO signInfo = { 0 };
985 CMSG_SIGNER_ENCODE_INFO signer = { sizeof(signer), 0 };
986 CERT_INFO certInfo = { 0 };
987 static char oid_rsa_md5[] = szOID_RSA_MD5;
989 SetLastError(0xdeadbeef);
990 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo,
991 NULL, NULL);
992 ok(!msg && GetLastError() == E_INVALIDARG,
993 "Expected E_INVALIDARG, got %x\n", GetLastError());
994 signInfo.cbSize = sizeof(signInfo);
995 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo,
996 NULL, NULL);
997 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
998 CryptMsgClose(msg);
1000 signInfo.cSigners = 1;
1001 signInfo.rgSigners = &signer;
1002 /* With signer.pCertInfo unset, attempting to open this message this
1003 * crashes.
1005 signer.pCertInfo = &certInfo;
1006 /* The cert info must contain a serial number and an issuer. */
1007 SetLastError(0xdeadbeef);
1008 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo,
1009 NULL, NULL);
1010 ok(!msg && GetLastError() == E_INVALIDARG,
1011 "Expected E_INVALIDARG, got %x\n", GetLastError());
1012 certInfo.SerialNumber.cbData = sizeof(serialNum);
1013 certInfo.SerialNumber.pbData = serialNum;
1014 SetLastError(0xdeadbeef);
1015 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo,
1016 NULL, NULL);
1017 ok(!msg && GetLastError() == E_INVALIDARG,
1018 "Expected E_INVALIDARG, got %x\n", GetLastError());
1019 certInfo.Issuer.cbData = sizeof(encodedCommonName);
1020 certInfo.Issuer.pbData = encodedCommonName;
1021 SetLastError(0xdeadbeef);
1022 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo,
1023 NULL, NULL);
1024 ok(!msg && GetLastError() == E_INVALIDARG,
1025 "Expected E_INVALIDARG, got %x\n", GetLastError());
1027 /* The signer's hCryptProv must be set to something. Whether it's usable
1028 * or not will be checked after the hash algorithm is checked (see next
1029 * test.)
1031 signer.hCryptProv = 1;
1032 SetLastError(0xdeadbeef);
1033 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo,
1034 NULL, NULL);
1035 ok(!msg && GetLastError() == CRYPT_E_UNKNOWN_ALGO,
1036 "Expected CRYPT_E_UNKNOWN_ALGO, got %x\n", GetLastError());
1037 /* The signer's hash algorithm must also be set. */
1038 signer.HashAlgorithm.pszObjId = oid_rsa_md5;
1039 SetLastError(0xdeadbeef);
1040 /* Crashes in advapi32 in wine, don't do it */
1041 if (0) {
1042 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED,
1043 &signInfo, NULL, NULL);
1044 ok(!msg && GetLastError() == ERROR_INVALID_PARAMETER,
1045 "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1047 /* The signer's hCryptProv must also be valid. */
1048 ret = CryptAcquireContextW(&signer.hCryptProv, cspNameW, NULL,
1049 PROV_RSA_FULL, CRYPT_NEWKEYSET);
1050 if (!ret && GetLastError() == NTE_EXISTS)
1051 ret = CryptAcquireContextW(&signer.hCryptProv, cspNameW, NULL,
1052 PROV_RSA_FULL, 0);
1053 ok(ret, "CryptAcquireContextW failed: %x\n", GetLastError());
1054 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo,
1055 NULL, NULL);
1056 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
1057 CryptMsgClose(msg);
1059 CryptReleaseContext(signer.hCryptProv, 0);
1060 CryptAcquireContextW(&signer.hCryptProv, cspNameW, MS_DEF_PROV_W,
1061 PROV_RSA_FULL, CRYPT_DELETEKEYSET);
1064 static const BYTE privKey[] = {
1065 0x07, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00,
1066 0x02, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x79, 0x10, 0x1c, 0xd0, 0x6b, 0x10,
1067 0x18, 0x30, 0x94, 0x61, 0xdc, 0x0e, 0xcb, 0x96, 0x4e, 0x21, 0x3f, 0x79, 0xcd,
1068 0xa9, 0x17, 0x62, 0xbc, 0xbb, 0x61, 0x4c, 0xe0, 0x75, 0x38, 0x6c, 0xf3, 0xde,
1069 0x60, 0x86, 0x03, 0x97, 0x65, 0xeb, 0x1e, 0x6b, 0xdb, 0x53, 0x85, 0xad, 0x68,
1070 0x21, 0xf1, 0x5d, 0xe7, 0x1f, 0xe6, 0x53, 0xb4, 0xbb, 0x59, 0x3e, 0x14, 0x27,
1071 0xb1, 0x83, 0xa7, 0x3a, 0x54, 0xe2, 0x8f, 0x65, 0x8e, 0x6a, 0x4a, 0xcf, 0x3b,
1072 0x1f, 0x65, 0xff, 0xfe, 0xf1, 0x31, 0x3a, 0x37, 0x7a, 0x8b, 0xcb, 0xc6, 0xd4,
1073 0x98, 0x50, 0x36, 0x67, 0xe4, 0xa1, 0xe8, 0x7e, 0x8a, 0xc5, 0x23, 0xf2, 0x77,
1074 0xf5, 0x37, 0x61, 0x49, 0x72, 0x59, 0xe8, 0x3d, 0xf7, 0x60, 0xb2, 0x77, 0xca,
1075 0x78, 0x54, 0x6d, 0x65, 0x9e, 0x03, 0x97, 0x1b, 0x61, 0xbd, 0x0c, 0xd8, 0x06,
1076 0x63, 0xe2, 0xc5, 0x48, 0xef, 0xb3, 0xe2, 0x6e, 0x98, 0x7d, 0xbd, 0x4e, 0x72,
1077 0x91, 0xdb, 0x31, 0x57, 0xe3, 0x65, 0x3a, 0x49, 0xca, 0xec, 0xd2, 0x02, 0x4e,
1078 0x22, 0x7e, 0x72, 0x8e, 0xf9, 0x79, 0x84, 0x82, 0xdf, 0x7b, 0x92, 0x2d, 0xaf,
1079 0xc9, 0xe4, 0x33, 0xef, 0x89, 0x5c, 0x66, 0x99, 0xd8, 0x80, 0x81, 0x47, 0x2b,
1080 0xb1, 0x66, 0x02, 0x84, 0x59, 0x7b, 0xc3, 0xbe, 0x98, 0x45, 0x4a, 0x3d, 0xdd,
1081 0xea, 0x2b, 0xdf, 0x4e, 0xb4, 0x24, 0x6b, 0xec, 0xe7, 0xd9, 0x0c, 0x45, 0xb8,
1082 0xbe, 0xca, 0x69, 0x37, 0x92, 0x4c, 0x38, 0x6b, 0x96, 0x6d, 0xcd, 0x86, 0x67,
1083 0x5c, 0xea, 0x54, 0x94, 0xa4, 0xca, 0xa4, 0x02, 0xa5, 0x21, 0x4d, 0xae, 0x40,
1084 0x8f, 0x9d, 0x51, 0x83, 0xf2, 0x3f, 0x33, 0xc1, 0x72, 0xb4, 0x1d, 0x94, 0x6e,
1085 0x7d, 0xe4, 0x27, 0x3f, 0xea, 0xff, 0xe5, 0x9b, 0xa7, 0x5e, 0x55, 0x8e, 0x0d,
1086 0x69, 0x1c, 0x7a, 0xff, 0x81, 0x9d, 0x53, 0x52, 0x97, 0x9a, 0x76, 0x79, 0xda,
1087 0x93, 0x32, 0x16, 0xec, 0x69, 0x51, 0x1a, 0x4e, 0xc3, 0xf1, 0x72, 0x80, 0x78,
1088 0x5e, 0x66, 0x4a, 0x8d, 0x85, 0x2f, 0x3f, 0xb2, 0xa7 };
1090 static void test_signed_msg_update(void)
1092 HCRYPTMSG msg;
1093 BOOL ret;
1094 CMSG_SIGNED_ENCODE_INFO signInfo = { sizeof(signInfo), 0 };
1095 CMSG_SIGNER_ENCODE_INFO signer = { sizeof(signer), 0 };
1096 CERT_INFO certInfo = { 0 };
1097 HCRYPTKEY key;
1098 char oid_rsa_md5[] = szOID_RSA_MD5;
1100 certInfo.SerialNumber.cbData = sizeof(serialNum);
1101 certInfo.SerialNumber.pbData = serialNum;
1102 certInfo.Issuer.cbData = sizeof(encodedCommonName);
1103 certInfo.Issuer.pbData = encodedCommonName;
1104 signer.pCertInfo = &certInfo;
1105 signer.HashAlgorithm.pszObjId = oid_rsa_md5;
1106 signInfo.cSigners = 1;
1107 signInfo.rgSigners = &signer;
1108 ret = CryptAcquireContextW(&signer.hCryptProv, cspNameW, NULL,
1109 PROV_RSA_FULL, CRYPT_NEWKEYSET);
1110 if (!ret && GetLastError() == NTE_EXISTS)
1111 ret = CryptAcquireContextW(&signer.hCryptProv, cspNameW, NULL,
1112 PROV_RSA_FULL, 0);
1113 ok(ret, "CryptAcquireContextW failed: %x\n", GetLastError());
1114 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING,
1115 CMSG_DETACHED_FLAG, CMSG_SIGNED, &signInfo, NULL, NULL);
1116 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
1117 /* CMSG_SIGNED allows non-final updates. */
1118 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
1119 todo_wine
1120 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1121 /* CMSG_SIGNED also allows non-final updates with no data. */
1122 ret = CryptMsgUpdate(msg, NULL, 0, FALSE);
1123 todo_wine
1124 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1125 /* The final update requires a private key in the hCryptProv, in order to
1126 * generate the signature.
1128 SetLastError(0xdeadbeef);
1129 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
1130 todo_wine
1131 ok(!ret && GetLastError() == NTE_BAD_KEYSET,
1132 "Expected NTE_BAD_KEYSET, got %x\n", GetLastError());
1133 ret = CryptImportKey(signer.hCryptProv, (LPBYTE)privKey, sizeof(privKey),
1134 0, 0, &key);
1135 ok(ret, "CryptImportKey failed: %08x\n", GetLastError());
1136 /* The final update should be able to succeed now that a key exists, but
1137 * the previous (invalid) final update prevents it.
1139 SetLastError(0xdeadbeef);
1140 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
1141 ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
1142 "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
1143 CryptMsgClose(msg);
1145 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING,
1146 CMSG_DETACHED_FLAG, CMSG_SIGNED, &signInfo, NULL, NULL);
1147 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
1148 /* CMSG_SIGNED allows non-final updates. */
1149 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
1150 todo_wine
1151 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1152 /* CMSG_SIGNED also allows non-final updates with no data. */
1153 ret = CryptMsgUpdate(msg, NULL, 0, FALSE);
1154 todo_wine
1155 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1156 /* Now that the private key exists, the final update can succeed (even
1157 * with no data.)
1159 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
1160 todo_wine
1161 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1162 /* But no updates are allowed after the final update. */
1163 SetLastError(0xdeadbeef);
1164 ret = CryptMsgUpdate(msg, NULL, 0, FALSE);
1165 ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
1166 "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
1167 SetLastError(0xdeadbeef);
1168 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
1169 ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
1170 "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
1171 CryptMsgClose(msg);
1173 CryptDestroyKey(key);
1174 CryptReleaseContext(signer.hCryptProv, 0);
1175 CryptAcquireContextW(&signer.hCryptProv, cspNameW, NULL, PROV_RSA_FULL,
1176 CRYPT_DELETEKEYSET);
1179 static void test_signed_msg(void)
1181 test_signed_msg_open();
1182 test_signed_msg_update();
1185 static CRYPT_DATA_BLOB b4 = { 0, NULL };
1186 static const struct update_accum a4 = { 1, &b4 };
1188 static const BYTE bogusOIDContent[] = {
1189 0x30,0x0f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x07,0xa0,0x02,
1190 0x04,0x00 };
1191 static const BYTE bogusHashContent[] = {
1192 0x30,0x47,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x05,0xa0,0x3a,
1193 0x30,0x38,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,
1194 0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
1195 0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04,0x04,0x10,0x00,0xd6,0xc0,
1196 0x5a,0x21,0x51,0x2a,0x79,0xa1,0xdf,0xeb,0x9d,0x2a,0x8f,0x26,0x2f };
1198 static void test_decode_msg_update(void)
1200 HCRYPTMSG msg;
1201 BOOL ret;
1202 CMSG_STREAM_INFO streamInfo = { 0 };
1203 DWORD i;
1204 struct update_accum accum = { 0, NULL };
1206 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1207 /* Update with a full message in a final update */
1208 ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent), TRUE);
1209 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1210 /* Can't update after a final update */
1211 SetLastError(0xdeadbeef);
1212 ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent), TRUE);
1213 ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
1214 "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
1215 CryptMsgClose(msg);
1217 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1218 /* Can't send a non-final update without streaming */
1219 SetLastError(0xdeadbeef);
1220 ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent),
1221 FALSE);
1222 ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
1223 "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
1224 /* A subsequent final update succeeds */
1225 ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent), TRUE);
1226 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1227 CryptMsgClose(msg);
1229 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, &streamInfo);
1230 /* Updating a message that has a NULL stream callback fails */
1231 SetLastError(0xdeadbeef);
1232 ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent),
1233 FALSE);
1234 todo_wine
1235 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
1236 "Expected STATUS_ACCESS_VIOLATION, got %x\n", GetLastError());
1237 /* Changing the callback pointer after the fact yields the same error (so
1238 * the message must copy the stream info, not just store a pointer to it)
1240 streamInfo.pfnStreamOutput = nop_stream_output;
1241 SetLastError(0xdeadbeef);
1242 ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent),
1243 FALSE);
1244 todo_wine
1245 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
1246 "Expected STATUS_ACCESS_VIOLATION, got %x\n", GetLastError());
1247 CryptMsgClose(msg);
1249 /* Empty non-final updates are allowed when streaming.. */
1250 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, &streamInfo);
1251 ret = CryptMsgUpdate(msg, NULL, 0, FALSE);
1252 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1253 /* but final updates aren't when not enough data has been received. */
1254 SetLastError(0xdeadbeef);
1255 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
1256 todo_wine
1257 ok(!ret && GetLastError() == CRYPT_E_STREAM_INSUFFICIENT_DATA,
1258 "Expected CRYPT_E_STREAM_INSUFFICIENT_DATA, got %x\n", GetLastError());
1259 CryptMsgClose(msg);
1261 /* Updating the message byte by byte is legal */
1262 streamInfo.pfnStreamOutput = accumulating_stream_output;
1263 streamInfo.pvArg = &accum;
1264 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, &streamInfo);
1265 for (i = 0, ret = TRUE; ret && i < sizeof(dataEmptyContent); i++)
1266 ret = CryptMsgUpdate(msg, &dataEmptyContent[i], 1, FALSE);
1267 ok(ret, "CryptMsgUpdate failed on byte %d: %x\n", i, GetLastError());
1268 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
1269 ok(ret, "CryptMsgUpdate failed on byte %d: %x\n", i, GetLastError());
1270 CryptMsgClose(msg);
1271 todo_wine
1272 check_updates("byte-by-byte empty content", &a4, &accum);
1273 free_updates(&accum);
1275 /* Decoding bogus content fails in non-streaming mode.. */
1276 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1277 SetLastError(0xdeadbeef);
1278 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
1279 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1280 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
1281 CryptMsgClose(msg);
1282 /* and as the final update in streaming mode.. */
1283 streamInfo.pfnStreamOutput = nop_stream_output;
1284 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, &streamInfo);
1285 SetLastError(0xdeadbeef);
1286 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
1287 todo_wine
1288 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1289 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
1290 CryptMsgClose(msg);
1291 /* and even as a non-final update in streaming mode. */
1292 streamInfo.pfnStreamOutput = nop_stream_output;
1293 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, &streamInfo);
1294 SetLastError(0xdeadbeef);
1295 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
1296 todo_wine
1297 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1298 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
1299 CryptMsgClose(msg);
1301 /* An empty message can be opened with indetermined type.. */
1302 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1303 ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent),
1304 TRUE);
1305 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1306 /* but decoding it as an explicitly typed message fails. */
1307 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, 0, NULL,
1308 NULL);
1309 SetLastError(0xdeadbeef);
1310 ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent),
1311 TRUE);
1312 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1313 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
1314 CryptMsgClose(msg);
1315 /* On the other hand, decoding the bare content of an empty message fails
1316 * with unspecified type..
1318 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1319 SetLastError(0xdeadbeef);
1320 ret = CryptMsgUpdate(msg, dataEmptyBareContent,
1321 sizeof(dataEmptyBareContent), TRUE);
1322 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1323 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
1324 CryptMsgClose(msg);
1325 /* but succeeds with explicit type. */
1326 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, 0, NULL,
1327 NULL);
1328 ret = CryptMsgUpdate(msg, dataEmptyBareContent,
1329 sizeof(dataEmptyBareContent), TRUE);
1330 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1331 CryptMsgClose(msg);
1333 /* Decoding valid content with an unsupported OID fails */
1334 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1335 SetLastError(0xdeadbeef);
1336 ret = CryptMsgUpdate(msg, bogusOIDContent, sizeof(bogusOIDContent), TRUE);
1337 ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE,
1338 "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
1339 CryptMsgClose(msg);
1341 /* Similarly, opening an empty hash with unspecified type succeeds.. */
1342 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1343 SetLastError(0xdeadbeef);
1344 ret = CryptMsgUpdate(msg, hashEmptyContent, sizeof(hashEmptyContent), TRUE);
1345 ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError());
1346 CryptMsgClose(msg);
1347 /* while with specified type it fails. */
1348 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL,
1349 NULL);
1350 SetLastError(0xdeadbeef);
1351 ret = CryptMsgUpdate(msg, hashEmptyContent, sizeof(hashEmptyContent), TRUE);
1352 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1353 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
1354 CryptMsgClose(msg);
1355 /* On the other hand, decoding the bare content of an empty hash message
1356 * fails with unspecified type..
1358 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1359 SetLastError(0xdeadbeef);
1360 ret = CryptMsgUpdate(msg, hashEmptyBareContent,
1361 sizeof(hashEmptyBareContent), TRUE);
1362 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1363 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
1364 CryptMsgClose(msg);
1365 /* but succeeds with explicit type. */
1366 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL,
1367 NULL);
1368 ret = CryptMsgUpdate(msg, hashEmptyBareContent,
1369 sizeof(hashEmptyBareContent), TRUE);
1370 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1371 CryptMsgClose(msg);
1373 /* And again, opening a (non-empty) hash message with unspecified type
1374 * succeeds..
1376 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1377 SetLastError(0xdeadbeef);
1378 ret = CryptMsgUpdate(msg, hashContent, sizeof(hashContent), TRUE);
1379 ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError());
1380 CryptMsgClose(msg);
1381 /* while with specified type it fails.. */
1382 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL,
1383 NULL);
1384 SetLastError(0xdeadbeef);
1385 ret = CryptMsgUpdate(msg, hashContent, sizeof(hashContent), TRUE);
1386 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1387 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
1388 CryptMsgClose(msg);
1389 /* and decoding the bare content of a non-empty hash message fails with
1390 * unspecified type..
1392 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1393 SetLastError(0xdeadbeef);
1394 ret = CryptMsgUpdate(msg, hashBareContent, sizeof(hashBareContent), TRUE);
1395 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1396 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
1397 CryptMsgClose(msg);
1398 /* but succeeds with explicit type. */
1399 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL,
1400 NULL);
1401 ret = CryptMsgUpdate(msg, hashBareContent, sizeof(hashBareContent), TRUE);
1402 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1403 CryptMsgClose(msg);
1405 /* Opening a (non-empty) hash message with unspecified type and a bogus
1406 * hash value succeeds..
1408 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1409 SetLastError(0xdeadbeef);
1410 ret = CryptMsgUpdate(msg, bogusHashContent, sizeof(bogusHashContent), TRUE);
1411 ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError());
1412 CryptMsgClose(msg);
1415 static const BYTE hashParam[] = { 0x08,0xd6,0xc0,0x5a,0x21,0x51,0x2a,0x79,0xa1,
1416 0xdf,0xeb,0x9d,0x2a,0x8f,0x26,0x2f };
1418 static void test_decode_msg_get_param(void)
1420 HCRYPTMSG msg;
1421 BOOL ret;
1422 DWORD size = 0, version;
1424 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1425 SetLastError(0xdeadbeef);
1426 ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &size);
1427 ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE,
1428 "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
1429 ret = CryptMsgUpdate(msg, dataContent, sizeof(dataContent), TRUE);
1430 check_param("data content", msg, CMSG_CONTENT_PARAM, msgData,
1431 sizeof(msgData));
1432 CryptMsgClose(msg);
1434 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1435 ret = CryptMsgUpdate(msg, hashEmptyContent, sizeof(hashEmptyContent), TRUE);
1436 check_param("empty hash content", msg, CMSG_CONTENT_PARAM, NULL, 0);
1437 check_param("empty hash hash data", msg, CMSG_HASH_DATA_PARAM, NULL, 0);
1438 check_param("empty hash computed hash", msg, CMSG_COMPUTED_HASH_PARAM,
1439 emptyHashParam, sizeof(emptyHashParam));
1440 CryptMsgClose(msg);
1441 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1442 ret = CryptMsgUpdate(msg, hashContent, sizeof(hashContent), TRUE);
1443 check_param("hash content", msg, CMSG_CONTENT_PARAM, msgData,
1444 sizeof(msgData));
1445 check_param("hash hash data", msg, CMSG_HASH_DATA_PARAM, hashParam,
1446 sizeof(hashParam));
1447 check_param("hash computed hash", msg, CMSG_COMPUTED_HASH_PARAM,
1448 hashParam, sizeof(hashParam));
1449 size = strlen(szOID_RSA_data) + 1;
1450 check_param("hash inner OID", msg, CMSG_INNER_CONTENT_TYPE_PARAM,
1451 (const BYTE *)szOID_RSA_data, strlen(szOID_RSA_data) + 1);
1452 version = CMSG_HASHED_DATA_V0;
1453 check_param("hash version", msg, CMSG_VERSION_PARAM, (const BYTE *)&version,
1454 sizeof(version));
1455 CryptMsgClose(msg);
1458 static void test_decode_msg(void)
1460 test_decode_msg_update();
1461 test_decode_msg_get_param();
1464 START_TEST(msg)
1466 /* Basic parameter checking tests */
1467 test_msg_open_to_encode();
1468 test_msg_open_to_decode();
1469 test_msg_get_param();
1470 test_msg_close();
1472 /* Message-type specific tests */
1473 test_data_msg();
1474 test_hash_msg();
1475 test_signed_msg();
1476 test_decode_msg();