crypt32: Test and implement encoding signed messages with certificates.
[wine/wine-kai.git] / dlls / crypt32 / tests / msg.c
blobde11303ec1638b66508b272496c4c398e82e0b7e
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 char oid_rsa_md5[] = szOID_RSA_MD5;
32 static void test_msg_open_to_encode(void)
34 HCRYPTMSG msg;
36 /* Crash
37 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_ENVELOPED, NULL,
38 NULL, NULL);
39 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, NULL, NULL,
40 NULL);
41 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, NULL, NULL,
42 NULL);
45 /* Bad encodings */
46 SetLastError(0xdeadbeef);
47 msg = CryptMsgOpenToEncode(0, 0, 0, NULL, NULL, NULL);
48 ok(!msg && GetLastError() == E_INVALIDARG,
49 "Expected E_INVALIDARG, got %x\n", GetLastError());
50 SetLastError(0xdeadbeef);
51 msg = CryptMsgOpenToEncode(X509_ASN_ENCODING, 0, 0, NULL, NULL, NULL);
52 ok(!msg && GetLastError() == E_INVALIDARG,
53 "Expected E_INVALIDARG, got %x\n", GetLastError());
55 /* Bad message types */
56 SetLastError(0xdeadbeef);
57 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, 0, NULL, NULL, NULL);
58 ok(!msg && GetLastError() == CRYPT_E_INVALID_MSG_TYPE,
59 "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
60 SetLastError(0xdeadbeef);
61 msg = CryptMsgOpenToEncode(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, 0,
62 NULL, NULL, NULL);
63 ok(!msg && GetLastError() == CRYPT_E_INVALID_MSG_TYPE,
64 "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
65 SetLastError(0xdeadbeef);
66 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0,
67 CMSG_SIGNED_AND_ENVELOPED, NULL, NULL, NULL);
68 ok(!msg && GetLastError() == CRYPT_E_INVALID_MSG_TYPE,
69 "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
70 SetLastError(0xdeadbeef);
71 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_ENCRYPTED, NULL,
72 NULL, NULL);
73 ok(!msg && GetLastError() == CRYPT_E_INVALID_MSG_TYPE,
74 "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
77 static void test_msg_open_to_decode(void)
79 HCRYPTMSG msg;
80 CMSG_STREAM_INFO streamInfo = { 0 };
82 SetLastError(0xdeadbeef);
83 msg = CryptMsgOpenToDecode(0, 0, 0, 0, NULL, NULL);
84 ok(!msg && GetLastError() == E_INVALIDARG,
85 "Expected E_INVALIDARG, got %x\n", GetLastError());
87 /* Bad encodings */
88 SetLastError(0xdeadbeef);
89 msg = CryptMsgOpenToDecode(X509_ASN_ENCODING, 0, 0, 0, NULL, NULL);
90 ok(!msg && GetLastError() == E_INVALIDARG,
91 "Expected E_INVALIDARG, got %x\n", GetLastError());
92 SetLastError(0xdeadbeef);
93 msg = CryptMsgOpenToDecode(X509_ASN_ENCODING, 0, CMSG_DATA, 0, NULL, NULL);
94 ok(!msg && GetLastError() == E_INVALIDARG,
95 "Expected E_INVALIDARG, got %x\n", GetLastError());
97 /* The message type can be explicit... */
98 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, 0, NULL,
99 NULL);
100 ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
101 CryptMsgClose(msg);
102 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_ENVELOPED, 0, NULL,
103 NULL);
104 ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
105 CryptMsgClose(msg);
106 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL,
107 NULL);
108 ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
109 CryptMsgClose(msg);
110 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, 0, NULL,
111 NULL);
112 ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
113 CryptMsgClose(msg);
114 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0,
115 CMSG_SIGNED_AND_ENVELOPED, 0, NULL, NULL);
116 ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
117 CryptMsgClose(msg);
118 /* or implicit.. */
119 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
120 ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
121 CryptMsgClose(msg);
122 /* or even invalid. */
123 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_ENCRYPTED, 0, NULL,
124 NULL);
125 ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
126 CryptMsgClose(msg);
127 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 1000, 0, NULL, NULL);
128 ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
129 CryptMsgClose(msg);
131 /* And even though the stream info parameter "must be set to NULL" for
132 * CMSG_HASHED, it's still accepted.
134 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL,
135 &streamInfo);
136 ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
137 CryptMsgClose(msg);
140 static void test_msg_get_param(void)
142 BOOL ret;
143 HCRYPTMSG msg;
144 DWORD size, i, value;
145 CMSG_SIGNED_ENCODE_INFO signInfo = { sizeof(signInfo), 0 };
146 CMSG_SIGNER_ENCODE_INFO signer = { sizeof(signer), 0 };
148 /* Crash
149 ret = CryptMsgGetParam(NULL, 0, 0, NULL, NULL);
150 ret = CryptMsgGetParam(NULL, 0, 0, NULL, &size);
151 ret = CryptMsgGetParam(msg, 0, 0, NULL, NULL);
154 /* Decoded messages */
155 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
156 ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
157 /* For decoded messages, the type is always available */
158 size = 0;
159 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, NULL, &size);
160 ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError());
161 size = sizeof(value);
162 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, (LPBYTE)&value, &size);
163 ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError());
164 /* For this (empty) message, the type isn't set */
165 ok(value == 0, "Expected type 0, got %d\n", value);
166 CryptMsgClose(msg);
168 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, 0, NULL,
169 NULL);
170 ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
171 /* For explicitly typed messages, the type is known. */
172 size = sizeof(value);
173 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, (LPBYTE)&value, &size);
174 ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError());
175 ok(value == CMSG_DATA, "Expected CMSG_DATA, got %d\n", value);
176 for (i = CMSG_CONTENT_PARAM; i <= CMSG_CMS_SIGNER_INFO_PARAM; i++)
178 size = 0;
179 ret = CryptMsgGetParam(msg, i, 0, NULL, &size);
180 ok(!ret, "Parameter %d: expected failure\n", i);
182 CryptMsgClose(msg);
184 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_ENVELOPED, 0, NULL,
185 NULL);
186 ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
187 size = sizeof(value);
188 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, (LPBYTE)&value, &size);
189 ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError());
190 ok(value == CMSG_ENVELOPED, "Expected CMSG_ENVELOPED, got %d\n", value);
191 for (i = CMSG_CONTENT_PARAM; i <= CMSG_CMS_SIGNER_INFO_PARAM; i++)
193 size = 0;
194 ret = CryptMsgGetParam(msg, i, 0, NULL, &size);
195 ok(!ret, "Parameter %d: expected failure\n", i);
197 CryptMsgClose(msg);
199 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL,
200 NULL);
201 ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
202 size = sizeof(value);
203 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, (LPBYTE)&value, &size);
204 ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError());
205 ok(value == CMSG_HASHED, "Expected CMSG_HASHED, got %d\n", value);
206 for (i = CMSG_CONTENT_PARAM; i <= CMSG_CMS_SIGNER_INFO_PARAM; i++)
208 size = 0;
209 ret = CryptMsgGetParam(msg, i, 0, NULL, &size);
210 ok(!ret, "Parameter %d: expected failure\n", i);
212 CryptMsgClose(msg);
214 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, 0, NULL,
215 NULL);
216 ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
217 size = sizeof(value);
218 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, (LPBYTE)&value, &size);
219 ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError());
220 ok(value == CMSG_SIGNED, "Expected CMSG_SIGNED, got %d\n", value);
221 for (i = CMSG_CONTENT_PARAM; i <= CMSG_CMS_SIGNER_INFO_PARAM; i++)
223 size = 0;
224 ret = CryptMsgGetParam(msg, i, 0, NULL, &size);
225 ok(!ret, "Parameter %d: expected failure\n", i);
227 CryptMsgClose(msg);
229 /* Explicitly typed messages get their types set, even if they're invalid */
230 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_ENCRYPTED, 0, NULL,
231 NULL);
232 ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
233 size = sizeof(value);
234 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, (LPBYTE)&value, &size);
235 ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError());
236 ok(value == CMSG_ENCRYPTED, "Expected CMSG_ENCRYPTED, got %d\n", value);
237 CryptMsgClose(msg);
239 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 1000, 0, NULL, NULL);
240 ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
241 size = sizeof(value);
242 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, (LPBYTE)&value, &size);
243 ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError());
244 ok(value == 1000, "Expected 1000, got %d\n", value);
245 CryptMsgClose(msg);
248 static void test_msg_close(void)
250 BOOL ret;
251 HCRYPTMSG msg;
253 /* NULL succeeds.. */
254 ret = CryptMsgClose(NULL);
255 ok(ret, "CryptMsgClose failed: %x\n", GetLastError());
256 /* but an arbitrary pointer crashes. */
257 if (0)
258 ret = CryptMsgClose((HCRYPTMSG)1);
259 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
260 NULL);
261 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
262 ret = CryptMsgClose(msg);
263 ok(ret, "CryptMsgClose failed: %x\n", GetLastError());
266 static void check_param(LPCSTR test, HCRYPTMSG msg, DWORD param,
267 const BYTE *expected, DWORD expectedSize)
269 DWORD size;
270 LPBYTE buf;
271 BOOL ret;
273 size = 0xdeadbeef;
274 ret = CryptMsgGetParam(msg, param, 0, NULL, &size);
275 ok(ret, "%s: CryptMsgGetParam failed: %08x\n", test, GetLastError());
276 buf = HeapAlloc(GetProcessHeap(), 0, size);
277 ret = CryptMsgGetParam(msg, param, 0, buf, &size);
278 ok(ret, "%s: CryptMsgGetParam failed: %08x\n", test, GetLastError());
279 ok(size == expectedSize, "%s: expected size %d, got %d\n", test,
280 expectedSize, size);
281 if (size == expectedSize && size)
282 ok(!memcmp(buf, expected, size), "%s: unexpected data\n", test);
283 HeapFree(GetProcessHeap(), 0, buf);
286 static void test_data_msg_open(void)
288 HCRYPTMSG msg;
289 CMSG_HASHED_ENCODE_INFO hashInfo = { 0 };
290 CMSG_STREAM_INFO streamInfo = { 0 };
291 char oid[] = "1.2.3";
293 /* The data message type takes no additional info */
294 SetLastError(0xdeadbeef);
295 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, &hashInfo,
296 NULL, NULL);
297 ok(!msg && GetLastError() == E_INVALIDARG,
298 "Expected E_INVALIDARG, got %x\n", GetLastError());
299 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
300 NULL);
301 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
302 CryptMsgClose(msg);
304 /* An empty stream info is allowed. */
305 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
306 &streamInfo);
307 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
308 CryptMsgClose(msg);
310 /* Passing a bogus inner OID succeeds for a non-streamed message.. */
311 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, oid,
312 NULL);
313 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
314 CryptMsgClose(msg);
315 /* and still succeeds when CMSG_DETACHED_FLAG is passed.. */
316 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG,
317 CMSG_DATA, NULL, oid, NULL);
318 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
319 CryptMsgClose(msg);
320 /* and when a stream info is given, even though you're not supposed to be
321 * able to use anything but szOID_RSA_data when streaming is being used.
323 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG,
324 CMSG_DATA, NULL, oid, &streamInfo);
325 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
326 CryptMsgClose(msg);
329 static const BYTE msgData[] = { 1, 2, 3, 4 };
331 static BOOL WINAPI nop_stream_output(const void *pvArg, BYTE *pb, DWORD cb,
332 BOOL final)
334 return TRUE;
337 static void test_data_msg_update(void)
339 HCRYPTMSG msg;
340 BOOL ret;
341 CMSG_STREAM_INFO streamInfo = { 0 };
343 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
344 NULL);
345 /* Can't update a message that wasn't opened detached with final = FALSE */
346 SetLastError(0xdeadbeef);
347 ret = CryptMsgUpdate(msg, NULL, 0, FALSE);
348 ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
349 "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
350 /* Updating it with final = TRUE succeeds */
351 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
352 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
353 /* Any subsequent update will fail, as the last was final */
354 SetLastError(0xdeadbeef);
355 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
356 ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
357 "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
358 CryptMsgClose(msg);
360 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
361 NULL);
362 /* Can't update a message with no data */
363 SetLastError(0xdeadbeef);
364 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
365 ok(!ret && GetLastError() == E_INVALIDARG,
366 "Expected E_INVALIDARG, got %x\n", GetLastError());
367 /* Curiously, a valid update will now fail as well, presumably because of
368 * the last (invalid, but final) update.
370 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
371 ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
372 "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
373 CryptMsgClose(msg);
375 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG,
376 CMSG_DATA, NULL, NULL, NULL);
377 /* Doesn't appear to be able to update CMSG-DATA with non-final updates */
378 SetLastError(0xdeadbeef);
379 ret = CryptMsgUpdate(msg, NULL, 0, FALSE);
380 ok(!ret && GetLastError() == E_INVALIDARG,
381 "Expected E_INVALIDARG, got %x\n", GetLastError());
382 SetLastError(0xdeadbeef);
383 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
384 ok(!ret && GetLastError() == E_INVALIDARG,
385 "Expected E_INVALIDARG, got %x\n", GetLastError());
386 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
387 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
388 CryptMsgClose(msg);
390 /* Calling update after opening with an empty stream info (with a bogus
391 * output function) yields an error:
393 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
394 &streamInfo);
395 SetLastError(0xdeadbeef);
396 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
397 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
398 "Expected STATUS_ACCESS_VIOLATION, got %x\n", GetLastError());
399 CryptMsgClose(msg);
400 /* Calling update with a valid output function succeeds, even if the data
401 * exceeds the size specified in the stream info.
403 streamInfo.pfnStreamOutput = nop_stream_output;
404 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
405 &streamInfo);
406 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
407 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
408 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
409 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
410 CryptMsgClose(msg);
413 static void test_data_msg_get_param(void)
415 HCRYPTMSG msg;
416 DWORD size;
417 BOOL ret;
418 CMSG_STREAM_INFO streamInfo = { 0, nop_stream_output, NULL };
420 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
421 NULL);
423 /* Content and bare content are always gettable when not streaming */
424 size = 0;
425 ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &size);
426 ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
427 size = 0;
428 ret = CryptMsgGetParam(msg, CMSG_BARE_CONTENT_PARAM, 0, NULL, &size);
429 ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
430 /* But for this type of message, the signer and hash aren't applicable,
431 * and the type isn't available.
433 size = 0;
434 SetLastError(0xdeadbeef);
435 ret = CryptMsgGetParam(msg, CMSG_ENCODED_SIGNER, 0, NULL, &size);
436 ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE,
437 "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
438 SetLastError(0xdeadbeef);
439 ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &size);
440 ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE,
441 "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
442 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, NULL, &size);
443 ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE,
444 "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
445 CryptMsgClose(msg);
447 /* Can't get content or bare content when streaming */
448 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL,
449 NULL, &streamInfo);
450 SetLastError(0xdeadbeef);
451 ret = CryptMsgGetParam(msg, CMSG_BARE_CONTENT_PARAM, 0, NULL, &size);
452 ok(!ret && GetLastError() == E_INVALIDARG,
453 "Expected E_INVALIDARG, got %x\n", GetLastError());
454 SetLastError(0xdeadbeef);
455 ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &size);
456 ok(!ret && GetLastError() == E_INVALIDARG,
457 "Expected E_INVALIDARG, got %x\n", GetLastError());
458 CryptMsgClose(msg);
461 static const BYTE dataEmptyBareContent[] = { 0x04,0x00 };
462 static const BYTE dataEmptyContent[] = {
463 0x30,0x0f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x02,
464 0x04,0x00 };
465 static const BYTE dataBareContent[] = { 0x04,0x04,0x01,0x02,0x03,0x04 };
466 static const BYTE dataContent[] = {
467 0x30,0x13,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x06,
468 0x04,0x04,0x01,0x02,0x03,0x04 };
470 struct update_accum
472 DWORD cUpdates;
473 CRYPT_DATA_BLOB *updates;
476 static BOOL WINAPI accumulating_stream_output(const void *pvArg, BYTE *pb,
477 DWORD cb, BOOL final)
479 struct update_accum *accum = (struct update_accum *)pvArg;
480 BOOL ret = FALSE;
482 if (accum->cUpdates)
483 accum->updates = CryptMemRealloc(accum->updates,
484 (accum->cUpdates + 1) * sizeof(CRYPT_DATA_BLOB));
485 else
486 accum->updates = CryptMemAlloc(sizeof(CRYPT_DATA_BLOB));
487 if (accum->updates)
489 CRYPT_DATA_BLOB *blob = &accum->updates[accum->cUpdates];
491 blob->pbData = CryptMemAlloc(cb);
492 if (blob->pbData)
494 memcpy(blob->pbData, pb, cb);
495 blob->cbData = cb;
496 ret = TRUE;
498 accum->cUpdates++;
500 return ret;
503 /* The updates of a (bogus) definite-length encoded message */
504 static BYTE u1[] = { 0x30,0x0f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
505 0x07,0x01,0xa0,0x02,0x04,0x00 };
506 static BYTE u2[] = { 0x01,0x02,0x03,0x04 };
507 static CRYPT_DATA_BLOB b1[] = {
508 { sizeof(u1), u1 },
509 { sizeof(u2), u2 },
510 { sizeof(u2), u2 },
512 static const struct update_accum a1 = { sizeof(b1) / sizeof(b1[0]), b1 };
513 /* The updates of a definite-length encoded message */
514 static BYTE u3[] = { 0x30,0x13,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
515 0x07,0x01,0xa0,0x06,0x04,0x04 };
516 static CRYPT_DATA_BLOB b2[] = {
517 { sizeof(u3), u3 },
518 { sizeof(u2), u2 },
520 static const struct update_accum a2 = { sizeof(b2) / sizeof(b2[0]), b2 };
521 /* The updates of an indefinite-length encoded message */
522 static BYTE u4[] = { 0x30,0x80,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
523 0x07,0x01,0xa0,0x80,0x24,0x80 };
524 static BYTE u5[] = { 0x04,0x04 };
525 static BYTE u6[] = { 0x00,0x00,0x00,0x00,0x00,0x00 };
526 static CRYPT_DATA_BLOB b3[] = {
527 { sizeof(u4), u4 },
528 { sizeof(u5), u5 },
529 { sizeof(u2), u2 },
530 { sizeof(u5), u5 },
531 { sizeof(u2), u2 },
532 { sizeof(u6), u6 },
534 static const struct update_accum a3 = { sizeof(b3) / sizeof(b3[0]), b3 };
536 static void check_updates(LPCSTR header, const struct update_accum *expected,
537 const struct update_accum *got)
539 DWORD i;
541 ok(expected->cUpdates == got->cUpdates,
542 "%s: expected %d updates, got %d\n", header, expected->cUpdates,
543 got->cUpdates);
544 if (expected->cUpdates == got->cUpdates)
545 for (i = 0; i < min(expected->cUpdates, got->cUpdates); i++)
547 ok(expected->updates[i].cbData == got->updates[i].cbData,
548 "%s, update %d: expected %d bytes, got %d\n", header, i,
549 expected->updates[i].cbData, got->updates[i].cbData);
550 if (expected->updates[i].cbData && expected->updates[i].cbData ==
551 got->updates[i].cbData)
552 ok(!memcmp(expected->updates[i].pbData, got->updates[i].pbData,
553 got->updates[i].cbData), "%s, update %d: unexpected value\n",
554 header, i);
558 /* Frees the updates stored in accum */
559 static void free_updates(struct update_accum *accum)
561 DWORD i;
563 for (i = 0; i < accum->cUpdates; i++)
564 CryptMemFree(accum->updates[i].pbData);
565 CryptMemFree(accum->updates);
566 accum->updates = NULL;
567 accum->cUpdates = 0;
570 static void test_data_msg_encoding(void)
572 HCRYPTMSG msg;
573 BOOL ret;
574 static char oid[] = "1.2.3";
575 struct update_accum accum = { 0, NULL };
576 CMSG_STREAM_INFO streamInfo = { 0, accumulating_stream_output, &accum };
578 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL,
579 NULL);
580 check_param("data empty bare content", msg, CMSG_BARE_CONTENT_PARAM,
581 dataEmptyBareContent, sizeof(dataEmptyBareContent));
582 check_param("data empty content", msg, CMSG_CONTENT_PARAM, dataEmptyContent,
583 sizeof(dataEmptyContent));
584 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
585 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
586 check_param("data bare content", msg, CMSG_BARE_CONTENT_PARAM,
587 dataBareContent, sizeof(dataBareContent));
588 check_param("data content", msg, CMSG_CONTENT_PARAM, dataContent,
589 sizeof(dataContent));
590 CryptMsgClose(msg);
591 /* Same test, but with CMSG_BARE_CONTENT_FLAG set */
592 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_BARE_CONTENT_FLAG,
593 CMSG_DATA, NULL, NULL, NULL);
594 check_param("data empty bare content", msg, CMSG_BARE_CONTENT_PARAM,
595 dataEmptyBareContent, sizeof(dataEmptyBareContent));
596 check_param("data empty content", msg, CMSG_CONTENT_PARAM, dataEmptyContent,
597 sizeof(dataEmptyContent));
598 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
599 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
600 check_param("data bare content", msg, CMSG_BARE_CONTENT_PARAM,
601 dataBareContent, sizeof(dataBareContent));
602 check_param("data content", msg, CMSG_CONTENT_PARAM, dataContent,
603 sizeof(dataContent));
604 CryptMsgClose(msg);
605 /* The inner OID is apparently ignored */
606 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, oid,
607 NULL);
608 check_param("data bogus oid bare content", msg, CMSG_BARE_CONTENT_PARAM,
609 dataEmptyBareContent, sizeof(dataEmptyBareContent));
610 check_param("data bogus oid content", msg, CMSG_CONTENT_PARAM,
611 dataEmptyContent, sizeof(dataEmptyContent));
612 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
613 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
614 check_param("data bare content", msg, CMSG_BARE_CONTENT_PARAM,
615 dataBareContent, sizeof(dataBareContent));
616 check_param("data content", msg, CMSG_CONTENT_PARAM, dataContent,
617 sizeof(dataContent));
618 CryptMsgClose(msg);
619 /* A streaming message is DER encoded if the length is not 0xffffffff, but
620 * curiously, updates aren't validated to make sure they don't exceed the
621 * stated length. (The resulting output will of course fail to decode.)
623 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL,
624 NULL, &streamInfo);
625 CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
626 CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
627 CryptMsgClose(msg);
628 check_updates("bogus data message with definite length", &a1, &accum);
629 free_updates(&accum);
630 /* A valid definite-length encoding: */
631 streamInfo.cbContent = sizeof(msgData);
632 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL,
633 NULL, &streamInfo);
634 CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
635 CryptMsgClose(msg);
636 check_updates("data message with definite length", &a2, &accum);
637 free_updates(&accum);
638 /* An indefinite-length encoding: */
639 streamInfo.cbContent = 0xffffffff;
640 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL,
641 NULL, &streamInfo);
642 CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
643 CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
644 CryptMsgClose(msg);
645 todo_wine
646 check_updates("data message with indefinite length", &a3, &accum);
647 free_updates(&accum);
650 static void test_data_msg(void)
652 test_data_msg_open();
653 test_data_msg_update();
654 test_data_msg_get_param();
655 test_data_msg_encoding();
658 static void test_hash_msg_open(void)
660 HCRYPTMSG msg;
661 CMSG_HASHED_ENCODE_INFO hashInfo = { 0 };
662 CMSG_STREAM_INFO streamInfo = { 0, nop_stream_output, NULL };
664 SetLastError(0xdeadbeef);
665 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
666 NULL, NULL);
667 ok(!msg && GetLastError() == E_INVALIDARG,
668 "Expected E_INVALIDARG, got %x\n", GetLastError());
669 hashInfo.cbSize = sizeof(hashInfo);
670 SetLastError(0xdeadbeef);
671 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
672 NULL, NULL);
673 ok(!msg && GetLastError() == CRYPT_E_UNKNOWN_ALGO,
674 "Expected CRYPT_E_UNKNOWN_ALGO, got %x\n", GetLastError());
675 hashInfo.HashAlgorithm.pszObjId = oid_rsa_md5;
676 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
677 NULL, NULL);
678 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
679 CryptMsgClose(msg);
680 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG,
681 CMSG_HASHED, &hashInfo, NULL, NULL);
682 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
683 CryptMsgClose(msg);
684 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG,
685 CMSG_HASHED, &hashInfo, NULL, &streamInfo);
686 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
687 CryptMsgClose(msg);
690 static void test_hash_msg_update(void)
692 HCRYPTMSG msg;
693 BOOL ret;
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 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];
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 ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
771 size = 0;
772 ret = CryptMsgGetParam(msg, CMSG_BARE_CONTENT_PARAM, 0, NULL, &size);
773 ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
774 /* The hash is also available. */
775 size = 0;
776 ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &size);
777 ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
778 ok(size == sizeof(buf), "Unexpected size %d\n", size);
779 ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, buf, &size);
780 if (size == sizeof(buf))
781 ok(!memcmp(buf, emptyHashParam, size), "Unexpected value\n");
782 /* By getting the hash, further updates are not allowed */
783 SetLastError(0xdeadbeef);
784 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
785 ok(!ret && GetLastError() == NTE_BAD_HASH_STATE,
786 "Expected NTE_BAD_HASH_STATE, got %x\n", GetLastError());
787 /* The version is also available, and should be zero for this message. */
788 size = 0;
789 ret = CryptMsgGetParam(msg, CMSG_VERSION_PARAM, 0, NULL, &size);
790 ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
791 size = sizeof(value);
792 ret = CryptMsgGetParam(msg, CMSG_VERSION_PARAM, 0, (LPBYTE)&value, &size);
793 ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
794 ok(value == 0, "Expected version 0, got %d\n", value);
795 /* As usual, the type isn't available. */
796 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, NULL, &size);
797 ok(!ret, "Expected failure\n");
798 CryptMsgClose(msg);
800 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
801 NULL, &streamInfo);
802 /* Streamed messages don't allow you to get the content or bare content. */
803 SetLastError(0xdeadbeef);
804 ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &size);
805 ok(!ret && GetLastError() == E_INVALIDARG,
806 "Expected E_INVALIDARG, got %x\n", GetLastError());
807 SetLastError(0xdeadbeef);
808 ret = CryptMsgGetParam(msg, CMSG_BARE_CONTENT_PARAM, 0, NULL, &size);
809 ok(!ret && GetLastError() == E_INVALIDARG,
810 "Expected E_INVALIDARG, got %x\n", GetLastError());
811 /* The hash is still available. */
812 size = 0;
813 ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &size);
814 ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
815 ok(size == sizeof(buf), "Unexpected size %d\n", size);
816 ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, buf, &size);
817 ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
818 if (size == sizeof(buf))
819 ok(!memcmp(buf, emptyHashParam, size), "Unexpected value\n");
820 /* After updating the hash, further updates aren't allowed on streamed
821 * messages either.
823 SetLastError(0xdeadbeef);
824 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
825 ok(!ret && GetLastError() == NTE_BAD_HASH_STATE,
826 "Expected NTE_BAD_HASH_STATE, got %x\n", GetLastError());
827 CryptMsgClose(msg);
830 static const BYTE hashEmptyBareContent[] = {
831 0x30,0x17,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,
832 0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0x04,0x00 };
833 static const BYTE hashEmptyContent[] = {
834 0x30,0x26,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x05,0xa0,0x19,
835 0x30,0x17,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,
836 0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0x04,0x00 };
837 static const BYTE hashBareContent[] = {
838 0x30,0x38,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,
839 0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
840 0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04,0x04,0x10,0x08,0xd6,0xc0,
841 0x5a,0x21,0x51,0x2a,0x79,0xa1,0xdf,0xeb,0x9d,0x2a,0x8f,0x26,0x2f };
842 static const BYTE hashContent[] = {
843 0x30,0x47,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x05,0xa0,0x3a,
844 0x30,0x38,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,
845 0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
846 0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04,0x04,0x10,0x08,0xd6,0xc0,
847 0x5a,0x21,0x51,0x2a,0x79,0xa1,0xdf,0xeb,0x9d,0x2a,0x8f,0x26,0x2f };
849 static const BYTE detachedHashNonFinalBareContent[] = {
850 0x30,0x20,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,
851 0x02,0x05,0x05,0x00,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
852 0x07,0x01,0x04,0x00 };
853 static const BYTE detachedHashNonFinalContent[] = {
854 0x30,0x2f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x05,0xa0,0x22,
855 0x30,0x20,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,
856 0x02,0x05,0x05,0x00,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
857 0x07,0x01,0x04,0x00 };
858 static const BYTE detachedHashBareContent[] = {
859 0x30,0x30,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,
860 0x02,0x05,0x05,0x00,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
861 0x07,0x01,0x04,0x10,0x08,0xd6,0xc0,0x5a,0x21,0x51,0x2a,0x79,0xa1,0xdf,0xeb,
862 0x9d,0x2a,0x8f,0x26,0x2f };
863 static const BYTE detachedHashContent[] = {
864 0x30,0x3f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x05,0xa0,0x32,
865 0x30,0x30,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,
866 0x02,0x05,0x05,0x00,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
867 0x07,0x01,0x04,0x10,0x08,0xd6,0xc0,0x5a,0x21,0x51,0x2a,0x79,0xa1,0xdf,0xeb,
868 0x9d,0x2a,0x8f,0x26,0x2f };
870 static void test_hash_msg_encoding(void)
872 HCRYPTMSG msg;
873 CMSG_HASHED_ENCODE_INFO hashInfo = { sizeof(hashInfo), 0 };
874 BOOL ret;
875 struct update_accum accum = { 0, NULL }, empty_accum = { 0, NULL };
876 CMSG_STREAM_INFO streamInfo = { 0, accumulating_stream_output, &accum };
878 hashInfo.HashAlgorithm.pszObjId = oid_rsa_md5;
879 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
880 NULL, NULL);
881 check_param("hash empty bare content", msg, CMSG_BARE_CONTENT_PARAM,
882 hashEmptyBareContent, sizeof(hashEmptyBareContent));
883 check_param("hash empty content", msg, CMSG_CONTENT_PARAM,
884 hashEmptyContent, sizeof(hashEmptyContent));
885 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
886 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
887 check_param("hash bare content", msg, CMSG_BARE_CONTENT_PARAM,
888 hashBareContent, sizeof(hashBareContent));
889 check_param("hash content", msg, CMSG_CONTENT_PARAM,
890 hashContent, sizeof(hashContent));
891 CryptMsgClose(msg);
892 /* Same test, but with CMSG_BARE_CONTENT_FLAG set */
893 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_BARE_CONTENT_FLAG,
894 CMSG_HASHED, &hashInfo, NULL, NULL);
895 check_param("hash empty bare content", msg, CMSG_BARE_CONTENT_PARAM,
896 hashEmptyBareContent, sizeof(hashEmptyBareContent));
897 check_param("hash empty content", msg, CMSG_CONTENT_PARAM,
898 hashEmptyContent, sizeof(hashEmptyContent));
899 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
900 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
901 check_param("hash bare content", msg, CMSG_BARE_CONTENT_PARAM,
902 hashBareContent, sizeof(hashBareContent));
903 check_param("hash content", msg, CMSG_CONTENT_PARAM,
904 hashContent, sizeof(hashContent));
905 CryptMsgClose(msg);
906 /* Same test, but with CMSG_DETACHED_FLAG set */
907 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG,
908 CMSG_HASHED, &hashInfo, NULL, NULL);
909 check_param("detached hash empty bare content", msg,
910 CMSG_BARE_CONTENT_PARAM, hashEmptyBareContent,
911 sizeof(hashEmptyBareContent));
912 check_param("detached hash empty content", msg, CMSG_CONTENT_PARAM,
913 hashEmptyContent, sizeof(hashEmptyContent));
914 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
915 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
916 check_param("detached hash not final bare content", msg,
917 CMSG_BARE_CONTENT_PARAM, detachedHashNonFinalBareContent,
918 sizeof(detachedHashNonFinalBareContent));
919 check_param("detached hash not final content", msg, CMSG_CONTENT_PARAM,
920 detachedHashNonFinalContent, sizeof(detachedHashNonFinalContent));
921 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
922 ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError());
923 check_param("detached hash bare content", msg, CMSG_BARE_CONTENT_PARAM,
924 detachedHashBareContent, sizeof(detachedHashBareContent));
925 check_param("detached hash content", msg, CMSG_CONTENT_PARAM,
926 detachedHashContent, sizeof(detachedHashContent));
927 check_param("detached hash bare content", msg, CMSG_BARE_CONTENT_PARAM,
928 detachedHashBareContent, sizeof(detachedHashBareContent));
929 check_param("detached hash content", msg, CMSG_CONTENT_PARAM,
930 detachedHashContent, sizeof(detachedHashContent));
931 CryptMsgClose(msg);
932 /* In what appears to be a bug, streamed updates to hash messages don't
933 * call the output function.
935 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
936 NULL, &streamInfo);
937 ret = CryptMsgUpdate(msg, NULL, 0, FALSE);
938 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
939 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
940 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
941 CryptMsgClose(msg);
942 check_updates("empty hash message", &empty_accum, &accum);
943 free_updates(&accum);
945 streamInfo.cbContent = sizeof(msgData);
946 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
947 NULL, &streamInfo);
948 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
949 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
950 CryptMsgClose(msg);
951 check_updates("hash message", &empty_accum, &accum);
952 free_updates(&accum);
954 streamInfo.cbContent = sizeof(msgData);
955 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG,
956 CMSG_HASHED, &hashInfo, NULL, &streamInfo);
957 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
958 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
959 CryptMsgClose(msg);
960 check_updates("detached hash message", &empty_accum, &accum);
961 free_updates(&accum);
964 static void test_hash_msg(void)
966 test_hash_msg_open();
967 test_hash_msg_update();
968 test_hash_msg_get_param();
969 test_hash_msg_encoding();
972 static const WCHAR cspNameW[] = { 'W','i','n','e','C','r','y','p','t','T','e',
973 'm','p',0 };
974 static BYTE serialNum[] = { 1 };
975 static BYTE encodedCommonName[] = { 0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,
976 0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
978 static void test_signed_msg_open(void)
980 HCRYPTMSG msg;
981 BOOL ret;
982 CMSG_SIGNED_ENCODE_INFO signInfo = { 0 };
983 CMSG_SIGNER_ENCODE_INFO signer = { sizeof(signer), 0 };
984 CERT_INFO certInfo = { 0 };
986 SetLastError(0xdeadbeef);
987 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo,
988 NULL, NULL);
989 ok(!msg && GetLastError() == E_INVALIDARG,
990 "Expected E_INVALIDARG, got %x\n", GetLastError());
991 signInfo.cbSize = sizeof(signInfo);
992 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo,
993 NULL, NULL);
994 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
995 CryptMsgClose(msg);
997 signInfo.cSigners = 1;
998 signInfo.rgSigners = &signer;
999 /* With signer.pCertInfo unset, attempting to open this message this
1000 * crashes.
1002 signer.pCertInfo = &certInfo;
1003 /* The cert info must contain a serial number and an issuer. */
1004 SetLastError(0xdeadbeef);
1005 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo,
1006 NULL, NULL);
1007 ok(!msg && GetLastError() == E_INVALIDARG,
1008 "Expected E_INVALIDARG, got %x\n", GetLastError());
1009 certInfo.SerialNumber.cbData = sizeof(serialNum);
1010 certInfo.SerialNumber.pbData = serialNum;
1011 SetLastError(0xdeadbeef);
1012 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo,
1013 NULL, NULL);
1014 ok(!msg && GetLastError() == E_INVALIDARG,
1015 "Expected E_INVALIDARG, got %x\n", GetLastError());
1016 certInfo.Issuer.cbData = sizeof(encodedCommonName);
1017 certInfo.Issuer.pbData = encodedCommonName;
1018 SetLastError(0xdeadbeef);
1019 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo,
1020 NULL, NULL);
1021 ok(!msg && GetLastError() == E_INVALIDARG,
1022 "Expected E_INVALIDARG, got %x\n", GetLastError());
1024 /* The signer's hCryptProv must be set to something. Whether it's usable
1025 * or not will be checked after the hash algorithm is checked (see next
1026 * test.)
1028 signer.hCryptProv = 1;
1029 SetLastError(0xdeadbeef);
1030 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo,
1031 NULL, NULL);
1032 ok(!msg && GetLastError() == CRYPT_E_UNKNOWN_ALGO,
1033 "Expected CRYPT_E_UNKNOWN_ALGO, got %x\n", GetLastError());
1034 /* The signer's hash algorithm must also be set. */
1035 signer.HashAlgorithm.pszObjId = oid_rsa_md5;
1036 SetLastError(0xdeadbeef);
1037 /* Crashes in advapi32 in wine, don't do it */
1038 if (0) {
1039 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED,
1040 &signInfo, NULL, NULL);
1041 ok(!msg && GetLastError() == ERROR_INVALID_PARAMETER,
1042 "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1044 /* The signer's hCryptProv must also be valid. */
1045 ret = CryptAcquireContextW(&signer.hCryptProv, cspNameW, NULL,
1046 PROV_RSA_FULL, CRYPT_NEWKEYSET);
1047 if (!ret && GetLastError() == NTE_EXISTS)
1048 ret = CryptAcquireContextW(&signer.hCryptProv, cspNameW, NULL,
1049 PROV_RSA_FULL, 0);
1050 ok(ret, "CryptAcquireContextW failed: %x\n", GetLastError());
1051 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo,
1052 NULL, NULL);
1053 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
1054 CryptMsgClose(msg);
1056 CryptReleaseContext(signer.hCryptProv, 0);
1057 CryptAcquireContextW(&signer.hCryptProv, cspNameW, MS_DEF_PROV_W,
1058 PROV_RSA_FULL, CRYPT_DELETEKEYSET);
1061 static const BYTE privKey[] = {
1062 0x07, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00,
1063 0x02, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x79, 0x10, 0x1c, 0xd0, 0x6b, 0x10,
1064 0x18, 0x30, 0x94, 0x61, 0xdc, 0x0e, 0xcb, 0x96, 0x4e, 0x21, 0x3f, 0x79, 0xcd,
1065 0xa9, 0x17, 0x62, 0xbc, 0xbb, 0x61, 0x4c, 0xe0, 0x75, 0x38, 0x6c, 0xf3, 0xde,
1066 0x60, 0x86, 0x03, 0x97, 0x65, 0xeb, 0x1e, 0x6b, 0xdb, 0x53, 0x85, 0xad, 0x68,
1067 0x21, 0xf1, 0x5d, 0xe7, 0x1f, 0xe6, 0x53, 0xb4, 0xbb, 0x59, 0x3e, 0x14, 0x27,
1068 0xb1, 0x83, 0xa7, 0x3a, 0x54, 0xe2, 0x8f, 0x65, 0x8e, 0x6a, 0x4a, 0xcf, 0x3b,
1069 0x1f, 0x65, 0xff, 0xfe, 0xf1, 0x31, 0x3a, 0x37, 0x7a, 0x8b, 0xcb, 0xc6, 0xd4,
1070 0x98, 0x50, 0x36, 0x67, 0xe4, 0xa1, 0xe8, 0x7e, 0x8a, 0xc5, 0x23, 0xf2, 0x77,
1071 0xf5, 0x37, 0x61, 0x49, 0x72, 0x59, 0xe8, 0x3d, 0xf7, 0x60, 0xb2, 0x77, 0xca,
1072 0x78, 0x54, 0x6d, 0x65, 0x9e, 0x03, 0x97, 0x1b, 0x61, 0xbd, 0x0c, 0xd8, 0x06,
1073 0x63, 0xe2, 0xc5, 0x48, 0xef, 0xb3, 0xe2, 0x6e, 0x98, 0x7d, 0xbd, 0x4e, 0x72,
1074 0x91, 0xdb, 0x31, 0x57, 0xe3, 0x65, 0x3a, 0x49, 0xca, 0xec, 0xd2, 0x02, 0x4e,
1075 0x22, 0x7e, 0x72, 0x8e, 0xf9, 0x79, 0x84, 0x82, 0xdf, 0x7b, 0x92, 0x2d, 0xaf,
1076 0xc9, 0xe4, 0x33, 0xef, 0x89, 0x5c, 0x66, 0x99, 0xd8, 0x80, 0x81, 0x47, 0x2b,
1077 0xb1, 0x66, 0x02, 0x84, 0x59, 0x7b, 0xc3, 0xbe, 0x98, 0x45, 0x4a, 0x3d, 0xdd,
1078 0xea, 0x2b, 0xdf, 0x4e, 0xb4, 0x24, 0x6b, 0xec, 0xe7, 0xd9, 0x0c, 0x45, 0xb8,
1079 0xbe, 0xca, 0x69, 0x37, 0x92, 0x4c, 0x38, 0x6b, 0x96, 0x6d, 0xcd, 0x86, 0x67,
1080 0x5c, 0xea, 0x54, 0x94, 0xa4, 0xca, 0xa4, 0x02, 0xa5, 0x21, 0x4d, 0xae, 0x40,
1081 0x8f, 0x9d, 0x51, 0x83, 0xf2, 0x3f, 0x33, 0xc1, 0x72, 0xb4, 0x1d, 0x94, 0x6e,
1082 0x7d, 0xe4, 0x27, 0x3f, 0xea, 0xff, 0xe5, 0x9b, 0xa7, 0x5e, 0x55, 0x8e, 0x0d,
1083 0x69, 0x1c, 0x7a, 0xff, 0x81, 0x9d, 0x53, 0x52, 0x97, 0x9a, 0x76, 0x79, 0xda,
1084 0x93, 0x32, 0x16, 0xec, 0x69, 0x51, 0x1a, 0x4e, 0xc3, 0xf1, 0x72, 0x80, 0x78,
1085 0x5e, 0x66, 0x4a, 0x8d, 0x85, 0x2f, 0x3f, 0xb2, 0xa7 };
1087 static void test_signed_msg_update(void)
1089 HCRYPTMSG msg;
1090 BOOL ret;
1091 CMSG_SIGNED_ENCODE_INFO signInfo = { sizeof(signInfo), 0 };
1092 CMSG_SIGNER_ENCODE_INFO signer = { sizeof(signer), 0 };
1093 CERT_INFO certInfo = { 0 };
1094 HCRYPTKEY key;
1096 certInfo.SerialNumber.cbData = sizeof(serialNum);
1097 certInfo.SerialNumber.pbData = serialNum;
1098 certInfo.Issuer.cbData = sizeof(encodedCommonName);
1099 certInfo.Issuer.pbData = encodedCommonName;
1100 signer.pCertInfo = &certInfo;
1101 signer.HashAlgorithm.pszObjId = oid_rsa_md5;
1102 signInfo.cSigners = 1;
1103 signInfo.rgSigners = &signer;
1104 ret = CryptAcquireContextW(&signer.hCryptProv, cspNameW, NULL,
1105 PROV_RSA_FULL, CRYPT_NEWKEYSET);
1106 if (!ret && GetLastError() == NTE_EXISTS)
1107 ret = CryptAcquireContextW(&signer.hCryptProv, cspNameW, NULL,
1108 PROV_RSA_FULL, 0);
1109 ok(ret, "CryptAcquireContextW failed: %x\n", GetLastError());
1110 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING,
1111 CMSG_DETACHED_FLAG, CMSG_SIGNED, &signInfo, NULL, NULL);
1112 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
1113 /* Detached CMSG_SIGNED allows non-final updates. */
1114 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
1115 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1116 /* Detached CMSG_SIGNED also allows non-final updates with no data. */
1117 ret = CryptMsgUpdate(msg, NULL, 0, FALSE);
1118 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1119 /* The final update requires a private key in the hCryptProv, in order to
1120 * generate the signature.
1122 SetLastError(0xdeadbeef);
1123 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
1124 ok(!ret && (GetLastError() == NTE_BAD_KEYSET ||
1125 GetLastError() == NTE_NO_KEY),
1126 "Expected NTE_BAD_KEYSET or NTE_NO_KEY, got %x\n", GetLastError());
1127 ret = CryptImportKey(signer.hCryptProv, (LPBYTE)privKey, sizeof(privKey),
1128 0, 0, &key);
1129 ok(ret, "CryptImportKey failed: %08x\n", GetLastError());
1130 /* The final update should be able to succeed now that a key exists, but
1131 * the previous (invalid) final update prevents it.
1133 SetLastError(0xdeadbeef);
1134 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
1135 ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
1136 "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
1137 CryptMsgClose(msg);
1139 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING,
1140 CMSG_DETACHED_FLAG, CMSG_SIGNED, &signInfo, NULL, NULL);
1141 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
1142 /* Detached CMSG_SIGNED allows non-final updates. */
1143 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
1144 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1145 /* Detached CMSG_SIGNED also allows non-final updates with no data. */
1146 ret = CryptMsgUpdate(msg, NULL, 0, FALSE);
1147 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1148 /* Now that the private key exists, the final update can succeed (even
1149 * with no data.)
1151 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
1152 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1153 /* But no updates are allowed after the final update. */
1154 SetLastError(0xdeadbeef);
1155 ret = CryptMsgUpdate(msg, NULL, 0, FALSE);
1156 ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
1157 "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
1158 SetLastError(0xdeadbeef);
1159 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
1160 ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
1161 "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
1162 CryptMsgClose(msg);
1164 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo,
1165 NULL, NULL);
1166 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
1167 /* Non-detached messages don't allow non-final updates.. */
1168 SetLastError(0xdeadbeef);
1169 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
1170 ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
1171 "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
1172 /* but they do allow final ones. */
1173 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
1174 ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError());
1175 CryptMsgClose(msg);
1176 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo,
1177 NULL, NULL);
1178 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
1179 /* They also allow final updates with no data. */
1180 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
1181 ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError());
1182 CryptMsgClose(msg);
1184 CryptDestroyKey(key);
1185 CryptReleaseContext(signer.hCryptProv, 0);
1186 CryptAcquireContextW(&signer.hCryptProv, cspNameW, NULL, PROV_RSA_FULL,
1187 CRYPT_DELETEKEYSET);
1190 static const BYTE signedEmptyBareContent[] = {
1191 0x30,0x50,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,
1192 0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0x31,0x37,0x30,0x35,0x02,
1193 0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,
1194 0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,
1195 0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,
1196 0x04,0x06,0x00,0x05,0x00,0x04,0x00 };
1197 static const BYTE signedEmptyContent[] = {
1198 0x30,0x5f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0,0x52,
1199 0x30,0x50,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,
1200 0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0x31,0x37,0x30,0x35,0x02,
1201 0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,
1202 0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,
1203 0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,
1204 0x04,0x06,0x00,0x05,0x00,0x04,0x00 };
1205 static const BYTE detachedSignedBareContent[] = {
1206 0x30,0x81,0x99,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,
1207 0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,
1208 0xf7,0x0d,0x01,0x07,0x01,0x31,0x77,0x30,0x75,0x02,0x01,0x01,0x30,0x1a,0x30,
1209 0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,
1210 0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,
1211 0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,
1212 0x04,0x40,0x81,0xa6,0x70,0xb3,0xef,0x59,0xd1,0x66,0xd1,0x9b,0xc0,0x9a,0xb6,
1213 0x9a,0x5e,0x6d,0x6f,0x6d,0x0d,0x59,0xa9,0xaa,0x6e,0xe9,0x2c,0xa0,0x1e,0xee,
1214 0xc2,0x60,0xbc,0x59,0xbe,0x3f,0x63,0x06,0x8d,0xc9,0x11,0x1d,0x23,0x64,0x92,
1215 0xef,0x2e,0xfc,0x57,0x29,0xa4,0xaf,0xe0,0xee,0x93,0x19,0x39,0x51,0xe4,0x44,
1216 0xb8,0x0b,0x28,0xf4,0xa8,0x0d };
1217 static const BYTE detachedSignedContent[] = {
1218 0x30,0x81,0xaa,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0,
1219 0x81,0x9c,0x30,0x81,0x99,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,
1220 0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x0b,0x06,0x09,0x2a,0x86,
1221 0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0x31,0x77,0x30,0x75,0x02,0x01,0x01,0x30,
1222 0x1a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,
1223 0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,
1224 0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,
1225 0x05,0x00,0x04,0x40,0x81,0xa6,0x70,0xb3,0xef,0x59,0xd1,0x66,0xd1,0x9b,0xc0,
1226 0x9a,0xb6,0x9a,0x5e,0x6d,0x6f,0x6d,0x0d,0x59,0xa9,0xaa,0x6e,0xe9,0x2c,0xa0,
1227 0x1e,0xee,0xc2,0x60,0xbc,0x59,0xbe,0x3f,0x63,0x06,0x8d,0xc9,0x11,0x1d,0x23,
1228 0x64,0x92,0xef,0x2e,0xfc,0x57,0x29,0xa4,0xaf,0xe0,0xee,0x93,0x19,0x39,0x51,
1229 0xe4,0x44,0xb8,0x0b,0x28,0xf4,0xa8,0x0d };
1230 static const BYTE signedBareContent[] = {
1231 0x30,0x81,0xa1,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,
1232 0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,0x48,0x86,
1233 0xf7,0x0d,0x01,0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04,0x31,0x77,
1234 0x30,0x75,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,
1235 0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,
1236 0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,
1237 0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x04,0x40,0x81,0xa6,0x70,0xb3,0xef,
1238 0x59,0xd1,0x66,0xd1,0x9b,0xc0,0x9a,0xb6,0x9a,0x5e,0x6d,0x6f,0x6d,0x0d,0x59,
1239 0xa9,0xaa,0x6e,0xe9,0x2c,0xa0,0x1e,0xee,0xc2,0x60,0xbc,0x59,0xbe,0x3f,0x63,
1240 0x06,0x8d,0xc9,0x11,0x1d,0x23,0x64,0x92,0xef,0x2e,0xfc,0x57,0x29,0xa4,0xaf,
1241 0xe0,0xee,0x93,0x19,0x39,0x51,0xe4,0x44,0xb8,0x0b,0x28,0xf4,0xa8,0x0d };
1242 static const BYTE signedContent[] = {
1243 0x30,0x81,0xb2,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0,
1244 0x81,0xa4,0x30,0x81,0xa1,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,
1245 0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,
1246 0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04,
1247 0x31,0x77,0x30,0x75,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30,0x11,
1248 0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,
1249 0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,
1250 0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x04,0x40,0x81,0xa6,0x70,
1251 0xb3,0xef,0x59,0xd1,0x66,0xd1,0x9b,0xc0,0x9a,0xb6,0x9a,0x5e,0x6d,0x6f,0x6d,
1252 0x0d,0x59,0xa9,0xaa,0x6e,0xe9,0x2c,0xa0,0x1e,0xee,0xc2,0x60,0xbc,0x59,0xbe,
1253 0x3f,0x63,0x06,0x8d,0xc9,0x11,0x1d,0x23,0x64,0x92,0xef,0x2e,0xfc,0x57,0x29,
1254 0xa4,0xaf,0xe0,0xee,0x93,0x19,0x39,0x51,0xe4,0x44,0xb8,0x0b,0x28,0xf4,0xa8,
1255 0x0d };
1256 static const BYTE signedHash[] = {
1257 0x08,0xd6,0xc0,0x5a,0x21,0x51,0x2a,0x79,0xa1,0xdf,0xeb,0x9d,0x2a,0x8f,0x26,
1258 0x2f };
1259 static BYTE cert[] = {
1260 0x30,0x7a,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11,
1261 0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,
1262 0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,
1263 0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,
1264 0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,
1265 0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,
1266 0x00,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,0xa3,0x16,0x30,0x14,0x30,
1267 0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,
1268 0xff,0x02,0x01,0x01 };
1269 static const BYTE signedWithCertEmptyBareContent[] = {
1270 0x30,0x81,0xce,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,
1271 0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0xa0,0x7c,0x30,0x7a,
1272 0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,
1273 0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,
1274 0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,
1275 0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,
1276 0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,
1277 0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x30,
1278 0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,0xa3,0x16,0x30,0x14,0x30,0x12,0x06,
1279 0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,
1280 0x01,0x01,0x31,0x37,0x30,0x35,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,
1281 0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,
1282 0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,
1283 0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x04,0x00 };
1284 static const BYTE signedWithCertBareContent[] = {
1285 0x30,0x82,0x01,0x1f,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86,
1286 0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,0x48,
1287 0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04,0xa0,
1288 0x7c,0x30,0x7a,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,
1289 0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,
1290 0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,
1291 0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,
1292 0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11,
1293 0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,
1294 0x67,0x00,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,0xa3,0x16,0x30,0x14,
1295 0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,
1296 0x01,0xff,0x02,0x01,0x01,0x31,0x77,0x30,0x75,0x02,0x01,0x01,0x30,0x1a,0x30,
1297 0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,
1298 0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,
1299 0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,
1300 0x04,0x40,0x81,0xa6,0x70,0xb3,0xef,0x59,0xd1,0x66,0xd1,0x9b,0xc0,0x9a,0xb6,
1301 0x9a,0x5e,0x6d,0x6f,0x6d,0x0d,0x59,0xa9,0xaa,0x6e,0xe9,0x2c,0xa0,0x1e,0xee,
1302 0xc2,0x60,0xbc,0x59,0xbe,0x3f,0x63,0x06,0x8d,0xc9,0x11,0x1d,0x23,0x64,0x92,
1303 0xef,0x2e,0xfc,0x57,0x29,0xa4,0xaf,0xe0,0xee,0x93,0x19,0x39,0x51,0xe4,0x44,
1304 0xb8,0x0b,0x28,0xf4,0xa8,0x0d };
1306 static void test_signed_msg_encoding(void)
1308 HCRYPTMSG msg;
1309 CMSG_SIGNED_ENCODE_INFO signInfo = { sizeof(signInfo), 0 };
1310 CMSG_SIGNER_ENCODE_INFO signer = { sizeof(signer), 0 };
1311 CERT_INFO certInfo = { 0 };
1312 CERT_BLOB encodedCert = { sizeof(cert), cert };
1313 BOOL ret;
1314 HCRYPTKEY key;
1315 DWORD size;
1317 certInfo.SerialNumber.cbData = sizeof(serialNum);
1318 certInfo.SerialNumber.pbData = serialNum;
1319 certInfo.Issuer.cbData = sizeof(encodedCommonName);
1320 certInfo.Issuer.pbData = encodedCommonName;
1321 signer.pCertInfo = &certInfo;
1322 signer.HashAlgorithm.pszObjId = oid_rsa_md5;
1323 signInfo.cSigners = 1;
1324 signInfo.rgSigners = &signer;
1325 ret = CryptAcquireContextW(&signer.hCryptProv, cspNameW, NULL,
1326 PROV_RSA_FULL, CRYPT_NEWKEYSET);
1327 if (!ret && GetLastError() == NTE_EXISTS)
1328 ret = CryptAcquireContextW(&signer.hCryptProv, cspNameW, NULL,
1329 PROV_RSA_FULL, 0);
1330 ok(ret, "CryptAcquireContextW failed: %x\n", GetLastError());
1331 ret = CryptImportKey(signer.hCryptProv, (LPBYTE)privKey, sizeof(privKey),
1332 0, 0, &key);
1333 ok(ret, "CryptImportKey failed: %08x\n", GetLastError());
1335 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING,
1336 CMSG_DETACHED_FLAG, CMSG_SIGNED, &signInfo, NULL, NULL);
1337 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
1339 check_param("detached signed empty bare content", msg,
1340 CMSG_BARE_CONTENT_PARAM, signedEmptyBareContent,
1341 sizeof(signedEmptyBareContent));
1342 check_param("detached signed empty content", msg, CMSG_CONTENT_PARAM,
1343 signedEmptyContent, sizeof(signedEmptyContent));
1344 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
1345 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1346 check_param("detached signed hash", msg, CMSG_COMPUTED_HASH_PARAM,
1347 signedHash, sizeof(signedHash));
1348 check_param("detached signed bare content", msg, CMSG_BARE_CONTENT_PARAM,
1349 detachedSignedBareContent, sizeof(detachedSignedBareContent));
1350 check_param("detached signed content", msg, CMSG_CONTENT_PARAM,
1351 detachedSignedContent, sizeof(detachedSignedContent));
1352 SetLastError(0xdeadbeef);
1353 ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 1, NULL, &size);
1354 ok(!ret && GetLastError() == CRYPT_E_INVALID_INDEX,
1355 "Expected CRYPT_E_INVALID_INDEX, got %x\n", GetLastError());
1357 CryptMsgClose(msg);
1359 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo,
1360 NULL, NULL);
1361 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
1363 check_param("signed empty bare content", msg, CMSG_BARE_CONTENT_PARAM,
1364 signedEmptyBareContent, sizeof(signedEmptyBareContent));
1365 check_param("signed empty content", msg, CMSG_CONTENT_PARAM,
1366 signedEmptyContent, sizeof(signedEmptyContent));
1367 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
1368 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1369 check_param("signed bare content", msg, CMSG_BARE_CONTENT_PARAM,
1370 signedBareContent, sizeof(signedBareContent));
1371 check_param("signed content", msg, CMSG_CONTENT_PARAM,
1372 signedContent, sizeof(signedContent));
1374 CryptMsgClose(msg);
1376 signInfo.rgCertEncoded = &encodedCert;
1377 signInfo.cCertEncoded = 1;
1378 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo,
1379 NULL, NULL);
1380 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
1382 check_param("signed with cert empty bare content", msg,
1383 CMSG_BARE_CONTENT_PARAM, signedWithCertEmptyBareContent,
1384 sizeof(signedWithCertEmptyBareContent));
1385 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
1386 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1387 check_param("signed with cert bare content", msg, CMSG_BARE_CONTENT_PARAM,
1388 signedWithCertBareContent, sizeof(signedWithCertBareContent));
1390 CryptMsgClose(msg);
1392 CryptDestroyKey(key);
1393 CryptReleaseContext(signer.hCryptProv, 0);
1394 CryptAcquireContextW(&signer.hCryptProv, cspNameW, NULL, PROV_RSA_FULL,
1395 CRYPT_DELETEKEYSET);
1398 static void test_signed_msg_get_param(void)
1400 BOOL ret;
1401 HCRYPTMSG msg;
1402 DWORD size, value = 0;
1403 CMSG_SIGNED_ENCODE_INFO signInfo = { sizeof(signInfo), 0 };
1404 CMSG_SIGNER_ENCODE_INFO signer = { sizeof(signer), 0 };
1405 CERT_INFO certInfo = { 0 };
1407 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo,
1408 NULL, NULL);
1409 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
1411 /* Content and bare content are always gettable */
1412 size = 0;
1413 ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &size);
1414 ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
1415 size = 0;
1416 ret = CryptMsgGetParam(msg, CMSG_BARE_CONTENT_PARAM, 0, NULL, &size);
1417 ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
1418 /* For "signed" messages, so is the version. */
1419 size = 0;
1420 ret = CryptMsgGetParam(msg, CMSG_VERSION_PARAM, 0, NULL, &size);
1421 ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
1422 size = sizeof(value);
1423 ret = CryptMsgGetParam(msg, CMSG_VERSION_PARAM, 0, (LPBYTE)&value, &size);
1424 ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
1425 ok(value == CMSG_SIGNED_DATA_V1, "Expected version 1, got %d\n", value);
1426 /* But for this message, with no signers, the hash and signer aren't
1427 * available.
1429 size = 0;
1430 SetLastError(0xdeadbeef);
1431 ret = CryptMsgGetParam(msg, CMSG_ENCODED_SIGNER, 0, NULL, &size);
1432 todo_wine
1433 ok(!ret && GetLastError() == CRYPT_E_INVALID_INDEX,
1434 "Expected CRYPT_E_INVALID_INDEX, got %x\n", GetLastError());
1435 SetLastError(0xdeadbeef);
1436 ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &size);
1437 ok(!ret && GetLastError() == CRYPT_E_INVALID_INDEX,
1438 "Expected CRYPT_E_INVALID_INDEX, got %x\n", GetLastError());
1439 /* As usual, the type isn't available. */
1440 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, NULL, &size);
1441 ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE,
1442 "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
1444 CryptMsgClose(msg);
1446 certInfo.SerialNumber.cbData = sizeof(serialNum);
1447 certInfo.SerialNumber.pbData = serialNum;
1448 certInfo.Issuer.cbData = sizeof(encodedCommonName);
1449 certInfo.Issuer.pbData = encodedCommonName;
1450 signer.pCertInfo = &certInfo;
1451 signer.HashAlgorithm.pszObjId = oid_rsa_md5;
1452 signInfo.cSigners = 1;
1453 signInfo.rgSigners = &signer;
1454 ret = CryptAcquireContextW(&signer.hCryptProv, cspNameW, NULL,
1455 PROV_RSA_FULL, CRYPT_NEWKEYSET);
1456 if (!ret && GetLastError() == NTE_EXISTS)
1457 ret = CryptAcquireContextW(&signer.hCryptProv, cspNameW, NULL,
1458 PROV_RSA_FULL, 0);
1459 ok(ret, "CryptAcquireContextW failed: %x\n", GetLastError());
1460 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo,
1461 NULL, NULL);
1462 ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
1464 /* This message, with one signer, has the hash and signer for index 0
1465 * available, but not for other indexes.
1467 size = 0;
1468 ret = CryptMsgGetParam(msg, CMSG_ENCODED_SIGNER, 0, NULL, &size);
1469 todo_wine
1470 ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError());
1471 ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &size);
1472 ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError());
1473 size = 0;
1474 SetLastError(0xdeadbeef);
1475 ret = CryptMsgGetParam(msg, CMSG_ENCODED_SIGNER, 1, NULL, &size);
1476 todo_wine
1477 ok(!ret && GetLastError() == CRYPT_E_INVALID_INDEX,
1478 "Expected CRYPT_E_INVALID_INDEX, got %x\n", GetLastError());
1479 SetLastError(0xdeadbeef);
1480 ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 1, NULL, &size);
1481 ok(!ret && GetLastError() == CRYPT_E_INVALID_INDEX,
1482 "Expected CRYPT_E_INVALID_INDEX, got %x\n", GetLastError());
1483 /* As usual, the type isn't available. */
1484 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, NULL, &size);
1485 ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE,
1486 "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
1488 CryptMsgClose(msg);
1490 CryptReleaseContext(signer.hCryptProv, 0);
1491 CryptAcquireContextW(&signer.hCryptProv, cspNameW, MS_DEF_PROV_W,
1492 PROV_RSA_FULL, CRYPT_DELETEKEYSET);
1495 static void test_signed_msg(void)
1497 test_signed_msg_open();
1498 test_signed_msg_update();
1499 test_signed_msg_encoding();
1500 test_signed_msg_get_param();
1503 static CRYPT_DATA_BLOB b4 = { 0, NULL };
1504 static const struct update_accum a4 = { 1, &b4 };
1506 static const BYTE bogusOIDContent[] = {
1507 0x30,0x0f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x07,0xa0,0x02,
1508 0x04,0x00 };
1509 static const BYTE bogusHashContent[] = {
1510 0x30,0x47,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x05,0xa0,0x3a,
1511 0x30,0x38,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,
1512 0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
1513 0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04,0x04,0x10,0x00,0xd6,0xc0,
1514 0x5a,0x21,0x51,0x2a,0x79,0xa1,0xdf,0xeb,0x9d,0x2a,0x8f,0x26,0x2f };
1516 static void test_decode_msg_update(void)
1518 HCRYPTMSG msg;
1519 BOOL ret;
1520 CMSG_STREAM_INFO streamInfo = { 0 };
1521 DWORD i;
1522 struct update_accum accum = { 0, NULL };
1524 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1525 /* Update with a full message in a final update */
1526 ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent), TRUE);
1527 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1528 /* Can't update after a final update */
1529 SetLastError(0xdeadbeef);
1530 ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent), TRUE);
1531 ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
1532 "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
1533 CryptMsgClose(msg);
1535 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1536 /* Can't send a non-final update without streaming */
1537 SetLastError(0xdeadbeef);
1538 ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent),
1539 FALSE);
1540 ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR,
1541 "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
1542 /* A subsequent final update succeeds */
1543 ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent), TRUE);
1544 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1545 CryptMsgClose(msg);
1547 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, &streamInfo);
1548 /* Updating a message that has a NULL stream callback fails */
1549 SetLastError(0xdeadbeef);
1550 ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent),
1551 FALSE);
1552 todo_wine
1553 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
1554 "Expected STATUS_ACCESS_VIOLATION, got %x\n", GetLastError());
1555 /* Changing the callback pointer after the fact yields the same error (so
1556 * the message must copy the stream info, not just store a pointer to it)
1558 streamInfo.pfnStreamOutput = nop_stream_output;
1559 SetLastError(0xdeadbeef);
1560 ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent),
1561 FALSE);
1562 todo_wine
1563 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
1564 "Expected STATUS_ACCESS_VIOLATION, got %x\n", GetLastError());
1565 CryptMsgClose(msg);
1567 /* Empty non-final updates are allowed when streaming.. */
1568 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, &streamInfo);
1569 ret = CryptMsgUpdate(msg, NULL, 0, FALSE);
1570 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1571 /* but final updates aren't when not enough data has been received. */
1572 SetLastError(0xdeadbeef);
1573 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
1574 todo_wine
1575 ok(!ret && GetLastError() == CRYPT_E_STREAM_INSUFFICIENT_DATA,
1576 "Expected CRYPT_E_STREAM_INSUFFICIENT_DATA, got %x\n", GetLastError());
1577 CryptMsgClose(msg);
1579 /* Updating the message byte by byte is legal */
1580 streamInfo.pfnStreamOutput = accumulating_stream_output;
1581 streamInfo.pvArg = &accum;
1582 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, &streamInfo);
1583 for (i = 0, ret = TRUE; ret && i < sizeof(dataEmptyContent); i++)
1584 ret = CryptMsgUpdate(msg, &dataEmptyContent[i], 1, FALSE);
1585 ok(ret, "CryptMsgUpdate failed on byte %d: %x\n", i, GetLastError());
1586 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
1587 ok(ret, "CryptMsgUpdate failed on byte %d: %x\n", i, GetLastError());
1588 CryptMsgClose(msg);
1589 todo_wine
1590 check_updates("byte-by-byte empty content", &a4, &accum);
1591 free_updates(&accum);
1593 /* Decoding bogus content fails in non-streaming mode.. */
1594 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1595 SetLastError(0xdeadbeef);
1596 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
1597 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1598 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
1599 CryptMsgClose(msg);
1600 /* and as the final update in streaming mode.. */
1601 streamInfo.pfnStreamOutput = nop_stream_output;
1602 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, &streamInfo);
1603 SetLastError(0xdeadbeef);
1604 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
1605 todo_wine
1606 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1607 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
1608 CryptMsgClose(msg);
1609 /* and even as a non-final update in streaming mode. */
1610 streamInfo.pfnStreamOutput = nop_stream_output;
1611 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, &streamInfo);
1612 SetLastError(0xdeadbeef);
1613 ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
1614 todo_wine
1615 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1616 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
1617 CryptMsgClose(msg);
1619 /* An empty message can be opened with indetermined type.. */
1620 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1621 ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent),
1622 TRUE);
1623 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1624 /* but decoding it as an explicitly typed message fails. */
1625 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, 0, NULL,
1626 NULL);
1627 SetLastError(0xdeadbeef);
1628 ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent),
1629 TRUE);
1630 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1631 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
1632 CryptMsgClose(msg);
1633 /* On the other hand, decoding the bare content of an empty message fails
1634 * with unspecified type..
1636 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1637 SetLastError(0xdeadbeef);
1638 ret = CryptMsgUpdate(msg, dataEmptyBareContent,
1639 sizeof(dataEmptyBareContent), TRUE);
1640 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1641 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
1642 CryptMsgClose(msg);
1643 /* but succeeds with explicit type. */
1644 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, 0, NULL,
1645 NULL);
1646 ret = CryptMsgUpdate(msg, dataEmptyBareContent,
1647 sizeof(dataEmptyBareContent), TRUE);
1648 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1649 CryptMsgClose(msg);
1651 /* Decoding valid content with an unsupported OID fails */
1652 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1653 SetLastError(0xdeadbeef);
1654 ret = CryptMsgUpdate(msg, bogusOIDContent, sizeof(bogusOIDContent), TRUE);
1655 ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE,
1656 "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
1657 CryptMsgClose(msg);
1659 /* Similarly, opening an empty hash with unspecified type succeeds.. */
1660 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1661 SetLastError(0xdeadbeef);
1662 ret = CryptMsgUpdate(msg, hashEmptyContent, sizeof(hashEmptyContent), TRUE);
1663 ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError());
1664 CryptMsgClose(msg);
1665 /* while with specified type it fails. */
1666 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL,
1667 NULL);
1668 SetLastError(0xdeadbeef);
1669 ret = CryptMsgUpdate(msg, hashEmptyContent, sizeof(hashEmptyContent), TRUE);
1670 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1671 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
1672 CryptMsgClose(msg);
1673 /* On the other hand, decoding the bare content of an empty hash message
1674 * fails with unspecified type..
1676 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1677 SetLastError(0xdeadbeef);
1678 ret = CryptMsgUpdate(msg, hashEmptyBareContent,
1679 sizeof(hashEmptyBareContent), TRUE);
1680 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1681 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
1682 CryptMsgClose(msg);
1683 /* but succeeds with explicit type. */
1684 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL,
1685 NULL);
1686 ret = CryptMsgUpdate(msg, hashEmptyBareContent,
1687 sizeof(hashEmptyBareContent), TRUE);
1688 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1689 CryptMsgClose(msg);
1691 /* And again, opening a (non-empty) hash message with unspecified type
1692 * succeeds..
1694 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1695 SetLastError(0xdeadbeef);
1696 ret = CryptMsgUpdate(msg, hashContent, sizeof(hashContent), TRUE);
1697 ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError());
1698 CryptMsgClose(msg);
1699 /* while with specified type it fails.. */
1700 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL,
1701 NULL);
1702 SetLastError(0xdeadbeef);
1703 ret = CryptMsgUpdate(msg, hashContent, sizeof(hashContent), TRUE);
1704 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1705 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
1706 CryptMsgClose(msg);
1707 /* and decoding the bare content of a non-empty hash message fails with
1708 * unspecified type..
1710 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1711 SetLastError(0xdeadbeef);
1712 ret = CryptMsgUpdate(msg, hashBareContent, sizeof(hashBareContent), TRUE);
1713 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1714 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
1715 CryptMsgClose(msg);
1716 /* but succeeds with explicit type. */
1717 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL,
1718 NULL);
1719 ret = CryptMsgUpdate(msg, hashBareContent, sizeof(hashBareContent), TRUE);
1720 ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
1721 CryptMsgClose(msg);
1723 /* Opening a (non-empty) hash message with unspecified type and a bogus
1724 * hash value succeeds..
1726 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1727 SetLastError(0xdeadbeef);
1728 ret = CryptMsgUpdate(msg, bogusHashContent, sizeof(bogusHashContent), TRUE);
1729 ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError());
1730 CryptMsgClose(msg);
1733 static const BYTE hashParam[] = { 0x08,0xd6,0xc0,0x5a,0x21,0x51,0x2a,0x79,0xa1,
1734 0xdf,0xeb,0x9d,0x2a,0x8f,0x26,0x2f };
1736 static void test_decode_msg_get_param(void)
1738 HCRYPTMSG msg;
1739 BOOL ret;
1740 DWORD size = 0, version;
1742 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1743 SetLastError(0xdeadbeef);
1744 ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &size);
1745 ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE,
1746 "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
1747 ret = CryptMsgUpdate(msg, dataContent, sizeof(dataContent), TRUE);
1748 check_param("data content", msg, CMSG_CONTENT_PARAM, msgData,
1749 sizeof(msgData));
1750 CryptMsgClose(msg);
1752 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1753 ret = CryptMsgUpdate(msg, hashEmptyContent, sizeof(hashEmptyContent), TRUE);
1754 check_param("empty hash content", msg, CMSG_CONTENT_PARAM, NULL, 0);
1755 check_param("empty hash hash data", msg, CMSG_HASH_DATA_PARAM, NULL, 0);
1756 check_param("empty hash computed hash", msg, CMSG_COMPUTED_HASH_PARAM,
1757 emptyHashParam, sizeof(emptyHashParam));
1758 CryptMsgClose(msg);
1759 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL);
1760 ret = CryptMsgUpdate(msg, hashContent, sizeof(hashContent), TRUE);
1761 check_param("hash content", msg, CMSG_CONTENT_PARAM, msgData,
1762 sizeof(msgData));
1763 check_param("hash hash data", msg, CMSG_HASH_DATA_PARAM, hashParam,
1764 sizeof(hashParam));
1765 check_param("hash computed hash", msg, CMSG_COMPUTED_HASH_PARAM,
1766 hashParam, sizeof(hashParam));
1767 size = strlen(szOID_RSA_data) + 1;
1768 check_param("hash inner OID", msg, CMSG_INNER_CONTENT_TYPE_PARAM,
1769 (const BYTE *)szOID_RSA_data, strlen(szOID_RSA_data) + 1);
1770 version = CMSG_HASHED_DATA_V0;
1771 check_param("hash version", msg, CMSG_VERSION_PARAM, (const BYTE *)&version,
1772 sizeof(version));
1773 CryptMsgClose(msg);
1776 static void test_decode_msg(void)
1778 test_decode_msg_update();
1779 test_decode_msg_get_param();
1782 START_TEST(msg)
1784 /* Basic parameter checking tests */
1785 test_msg_open_to_encode();
1786 test_msg_open_to_decode();
1787 test_msg_get_param();
1788 test_msg_close();
1790 /* Message-type specific tests */
1791 test_data_msg();
1792 test_hash_msg();
1793 test_signed_msg();
1794 test_decode_msg();