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
28 #include "wine/test.h"
30 static void test_msg_open_to_encode(void)
35 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_ENVELOPED, NULL,
37 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, NULL, NULL,
39 msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, NULL, NULL,
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,
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
,
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)
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());
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
,
98 ok(msg
!= NULL
, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
100 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, CMSG_ENVELOPED
, 0, NULL
,
102 ok(msg
!= NULL
, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
104 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, CMSG_HASHED
, 0, NULL
,
106 ok(msg
!= NULL
, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
108 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, CMSG_SIGNED
, 0, NULL
,
110 ok(msg
!= NULL
, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
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());
117 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, 0, 0, NULL
, NULL
);
118 ok(msg
!= NULL
, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
120 /* or even invalid. */
121 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, CMSG_ENCRYPTED
, 0, NULL
,
123 ok(msg
!= NULL
, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
125 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, 1000, 0, NULL
, NULL
);
126 ok(msg
!= NULL
, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
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
,
134 ok(msg
!= NULL
, "CryptMsgOpenToDecode failed: %x\n", GetLastError());
138 static void test_msg_get_param(void)
142 DWORD size
, i
, value
;
143 CMSG_SIGNED_ENCODE_INFO signInfo
= { sizeof(signInfo
), 0 };
144 CMSG_SIGNER_ENCODE_INFO signer
= { sizeof(signer
), 0 };
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 */
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
);
166 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, CMSG_DATA
, 0, 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
++)
177 ret
= CryptMsgGetParam(msg
, i
, 0, NULL
, &size
);
178 ok(!ret
, "Parameter %d: expected failure\n", i
);
182 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, CMSG_ENVELOPED
, 0, 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
++)
192 ret
= CryptMsgGetParam(msg
, i
, 0, NULL
, &size
);
193 ok(!ret
, "Parameter %d: expected failure\n", i
);
197 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, CMSG_HASHED
, 0, 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
++)
207 ret
= CryptMsgGetParam(msg
, i
, 0, NULL
, &size
);
208 ok(!ret
, "Parameter %d: expected failure\n", i
);
212 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, CMSG_SIGNED
, 0, 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
++)
222 ret
= CryptMsgGetParam(msg
, i
, 0, NULL
, &size
);
223 ok(!ret
, "Parameter %d: expected failure\n", i
);
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
,
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
);
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
);
246 static void test_msg_close(void)
251 /* NULL succeeds.. */
252 ret
= CryptMsgClose(NULL
);
253 ok(ret
, "CryptMsgClose failed: %x\n", GetLastError());
254 /* but an arbitrary pointer crashes. */
256 ret
= CryptMsgClose((HCRYPTMSG
)1);
257 msg
= CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING
, 0, CMSG_DATA
, NULL
, 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
)
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
,
280 ok(!memcmp(buf
, expected
, size
), "%s: unexpected data\n", test
);
281 HeapFree(GetProcessHeap(), 0, buf
);
284 static void test_data_msg_open(void)
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
,
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
,
299 ok(msg
!= NULL
, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
302 /* An empty stream info is allowed. */
303 msg
= CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING
, 0, CMSG_DATA
, NULL
, NULL
,
305 ok(msg
!= NULL
, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
308 /* Passing a bogus inner OID succeeds for a non-streamed message.. */
309 msg
= CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING
, 0, CMSG_DATA
, NULL
, oid
,
311 ok(msg
!= NULL
, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
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());
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());
327 static const BYTE msgData
[] = { 1, 2, 3, 4 };
329 static BOOL WINAPI
nop_stream_output(const void *pvArg
, BYTE
*pb
, DWORD cb
,
335 static void test_data_msg_update(void)
339 CMSG_STREAM_INFO streamInfo
= { 0 };
341 msg
= CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING
, 0, CMSG_DATA
, NULL
, 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());
358 msg
= CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING
, 0, CMSG_DATA
, NULL
, 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());
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());
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
,
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());
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
,
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());
411 static void test_data_msg_get_param(void)
416 CMSG_STREAM_INFO streamInfo
= { 0, nop_stream_output
, NULL
};
418 msg
= CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING
, 0, CMSG_DATA
, NULL
, NULL
,
421 /* Content and bare content are always gettable when not streaming */
423 ret
= CryptMsgGetParam(msg
, CMSG_CONTENT_PARAM
, 0, NULL
, &size
);
424 ok(ret
, "CryptMsgGetParam failed: %08x\n", GetLastError());
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.
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());
445 /* Can't get content or bare content when streaming */
446 msg
= CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING
, 0, CMSG_DATA
, NULL
,
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());
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,
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 };
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
;
481 accum
->updates
= CryptMemRealloc(accum
->updates
,
482 (accum
->cUpdates
+ 1) * sizeof(CRYPT_DATA_BLOB
));
484 accum
->updates
= CryptMemAlloc(sizeof(CRYPT_DATA_BLOB
));
487 CRYPT_DATA_BLOB
*blob
= &accum
->updates
[accum
->cUpdates
];
489 blob
->pbData
= CryptMemAlloc(cb
);
492 memcpy(blob
->pbData
, pb
, cb
);
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
[] = {
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
[] = {
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
[] = {
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
)
539 ok(expected
->cUpdates
== got
->cUpdates
,
540 "%s: expected %d updates, got %d\n", header
, expected
->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",
556 /* Frees the updates stored in accum */
557 static void free_updates(struct update_accum
*accum
)
561 for (i
= 0; i
< accum
->cUpdates
; i
++)
562 CryptMemFree(accum
->updates
[i
].pbData
);
563 CryptMemFree(accum
->updates
);
564 accum
->updates
= NULL
;
568 static void test_data_msg_encoding(void)
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
,
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
));
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
));
603 /* The inner OID is apparently ignored */
604 msg
= CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING
, 0, CMSG_DATA
, NULL
, oid
,
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
));
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
,
623 CryptMsgUpdate(msg
, msgData
, sizeof(msgData
), FALSE
);
624 CryptMsgUpdate(msg
, msgData
, sizeof(msgData
), TRUE
);
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
,
632 CryptMsgUpdate(msg
, msgData
, sizeof(msgData
), TRUE
);
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
,
640 CryptMsgUpdate(msg
, msgData
, sizeof(msgData
), FALSE
);
641 CryptMsgUpdate(msg
, msgData
, sizeof(msgData
), TRUE
);
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)
659 CMSG_HASHED_ENCODE_INFO hashInfo
= { 0 };
660 static char oid_rsa_md5
[] = szOID_RSA_MD5
;
662 SetLastError(0xdeadbeef);
663 msg
= CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING
, 0, CMSG_HASHED
, &hashInfo
,
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
,
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
,
679 ok(msg
!= NULL
, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
683 static void test_hash_msg_update(void)
687 static char oid_rsa_md5
[] = szOID_RSA_MD5
;
688 CMSG_HASHED_ENCODE_INFO hashInfo
= { sizeof(hashInfo
), 0,
689 { oid_rsa_md5
, { 0, NULL
} }, NULL
};
690 CMSG_STREAM_INFO streamInfo
= { 0, nop_stream_output
, NULL
};
692 msg
= CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING
, CMSG_DETACHED_FLAG
,
693 CMSG_HASHED
, &hashInfo
, NULL
, NULL
);
694 /* Detached hashed messages opened in non-streaming mode allow non-final
697 ret
= CryptMsgUpdate(msg
, msgData
, sizeof(msgData
), FALSE
);
699 ok(ret
, "CryptMsgUpdate failed: %x\n", GetLastError());
700 /* including non-final updates with no data.. */
701 ret
= CryptMsgUpdate(msg
, NULL
, 0, FALSE
);
703 ok(ret
, "CryptMsgUpdate failed: %x\n", GetLastError());
704 /* and final updates with no data. */
705 ret
= CryptMsgUpdate(msg
, NULL
, 0, TRUE
);
707 ok(ret
, "CryptMsgUpdate failed: %x\n", GetLastError());
708 /* But no updates are allowed after the final update. */
709 SetLastError(0xdeadbeef);
710 ret
= CryptMsgUpdate(msg
, NULL
, 0, FALSE
);
712 ok(!ret
&& GetLastError() == CRYPT_E_MSG_ERROR
,
713 "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
714 SetLastError(0xdeadbeef);
715 ret
= CryptMsgUpdate(msg
, NULL
, 0, TRUE
);
717 ok(!ret
&& GetLastError() == CRYPT_E_MSG_ERROR
,
718 "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
720 /* Non-detached messages, in contrast, don't allow non-final updates in
721 * non-streaming mode.
723 msg
= CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING
, 0, CMSG_HASHED
, &hashInfo
,
725 SetLastError(0xdeadbeef);
726 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
);
733 ok(ret
, "CryptMsgUpdate failed: %x\n", GetLastError());
735 /* And, of course, streaming mode allows non-final updates */
736 msg
= CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING
, 0, CMSG_HASHED
, &hashInfo
,
738 ret
= CryptMsgUpdate(msg
, msgData
, sizeof(msgData
), FALSE
);
740 ok(ret
, "CryptMsgUpdate failed: %x\n", GetLastError());
744 static void test_hash_msg(void)
746 test_hash_msg_open();
747 test_hash_msg_update();
750 static CRYPT_DATA_BLOB b4
= { 0, NULL
};
751 static const struct update_accum a4
= { 1, &b4
};
753 static const BYTE bogusOIDContent
[] = {
754 0x30,0x0f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x07,0xa0,0x02,
757 static void test_decode_msg_update(void)
761 CMSG_STREAM_INFO streamInfo
= { 0 };
763 struct update_accum accum
= { 0, NULL
};
765 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, 0, 0, NULL
, NULL
);
766 /* Update with a full message in a final update */
767 ret
= CryptMsgUpdate(msg
, dataEmptyContent
, sizeof(dataEmptyContent
), TRUE
);
769 ok(ret
, "CryptMsgUpdate failed: %x\n", GetLastError());
770 /* Can't update after a final update */
771 SetLastError(0xdeadbeef);
772 ret
= CryptMsgUpdate(msg
, dataEmptyContent
, sizeof(dataEmptyContent
), TRUE
);
774 ok(!ret
&& GetLastError() == CRYPT_E_MSG_ERROR
,
775 "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
778 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, 0, 0, NULL
, NULL
);
779 /* Can't send a non-final update without streaming */
780 SetLastError(0xdeadbeef);
781 ret
= CryptMsgUpdate(msg
, dataEmptyContent
, sizeof(dataEmptyContent
),
784 ok(!ret
&& GetLastError() == CRYPT_E_MSG_ERROR
,
785 "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError());
786 /* A subsequent final update succeeds */
787 ret
= CryptMsgUpdate(msg
, dataEmptyContent
, sizeof(dataEmptyContent
), TRUE
);
789 ok(ret
, "CryptMsgUpdate failed: %x\n", GetLastError());
792 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, 0, 0, NULL
, &streamInfo
);
793 /* Updating a message that has a NULL stream callback fails */
794 SetLastError(0xdeadbeef);
795 ret
= CryptMsgUpdate(msg
, dataEmptyContent
, sizeof(dataEmptyContent
),
798 ok(!ret
&& GetLastError() == STATUS_ACCESS_VIOLATION
,
799 "Expected STATUS_ACCESS_VIOLATION, got %x\n", GetLastError());
800 /* Changing the callback pointer after the fact yields the same error (so
801 * the message must copy the stream info, not just store a pointer to it)
803 streamInfo
.pfnStreamOutput
= nop_stream_output
;
804 SetLastError(0xdeadbeef);
805 ret
= CryptMsgUpdate(msg
, dataEmptyContent
, sizeof(dataEmptyContent
),
808 ok(!ret
&& GetLastError() == STATUS_ACCESS_VIOLATION
,
809 "Expected STATUS_ACCESS_VIOLATION, got %x\n", GetLastError());
812 /* Empty non-final updates are allowed when streaming.. */
813 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, 0, 0, NULL
, &streamInfo
);
814 ret
= CryptMsgUpdate(msg
, NULL
, 0, FALSE
);
816 ok(ret
, "CryptMsgUpdate failed: %x\n", GetLastError());
817 /* but final updates aren't when not enough data has been received. */
818 SetLastError(0xdeadbeef);
819 ret
= CryptMsgUpdate(msg
, NULL
, 0, TRUE
);
821 ok(!ret
&& GetLastError() == CRYPT_E_STREAM_INSUFFICIENT_DATA
,
822 "Expected CRYPT_E_STREAM_INSUFFICIENT_DATA, got %x\n", GetLastError());
825 /* Updating the message byte by byte is legal */
826 streamInfo
.pfnStreamOutput
= accumulating_stream_output
;
827 streamInfo
.pvArg
= &accum
;
828 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, 0, 0, NULL
, &streamInfo
);
829 for (i
= 0, ret
= TRUE
; ret
&& i
< sizeof(dataEmptyContent
); i
++)
830 ret
= CryptMsgUpdate(msg
, &dataEmptyContent
[i
], 1, FALSE
);
832 ok(ret
, "CryptMsgUpdate failed on byte %d: %x\n", i
, GetLastError());
833 ret
= CryptMsgUpdate(msg
, NULL
, 0, TRUE
);
834 ok(ret
, "CryptMsgUpdate failed on byte %d: %x\n", i
, GetLastError());
838 check_updates("byte-by-byte empty content", &a4
, &accum
);
839 free_updates(&accum
);
841 /* Decoding bogus content fails in non-streaming mode.. */
842 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, 0, 0, NULL
, NULL
);
843 SetLastError(0xdeadbeef);
844 ret
= CryptMsgUpdate(msg
, msgData
, sizeof(msgData
), TRUE
);
846 ok(!ret
&& GetLastError() == CRYPT_E_ASN1_BADTAG
,
847 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
849 /* and as the final update in streaming mode.. */
850 streamInfo
.pfnStreamOutput
= nop_stream_output
;
851 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, 0, 0, NULL
, &streamInfo
);
852 SetLastError(0xdeadbeef);
853 ret
= CryptMsgUpdate(msg
, msgData
, sizeof(msgData
), TRUE
);
855 ok(!ret
&& GetLastError() == CRYPT_E_ASN1_BADTAG
,
856 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
858 /* and even as a non-final update in streaming mode. */
859 streamInfo
.pfnStreamOutput
= nop_stream_output
;
860 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, 0, 0, NULL
, &streamInfo
);
861 SetLastError(0xdeadbeef);
862 ret
= CryptMsgUpdate(msg
, msgData
, sizeof(msgData
), FALSE
);
864 ok(!ret
&& GetLastError() == CRYPT_E_ASN1_BADTAG
,
865 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
868 /* An empty message can be opened with indetermined type.. */
869 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, 0, 0, NULL
, NULL
);
870 ret
= CryptMsgUpdate(msg
, dataEmptyContent
, sizeof(dataEmptyContent
),
873 ok(ret
, "CryptMsgUpdate failed: %x\n", GetLastError());
874 /* but decoding it as an explicitly typed message fails. */
875 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, CMSG_DATA
, 0, NULL
,
877 SetLastError(0xdeadbeef);
878 ret
= CryptMsgUpdate(msg
, dataEmptyContent
, sizeof(dataEmptyContent
),
881 ok(!ret
&& GetLastError() == CRYPT_E_ASN1_BADTAG
,
882 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
884 /* On the other hand, decoding the bare content of an empty message fails
885 * with unspecified type..
887 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, 0, 0, NULL
, NULL
);
888 SetLastError(0xdeadbeef);
889 ret
= CryptMsgUpdate(msg
, dataEmptyBareContent
,
890 sizeof(dataEmptyBareContent
), TRUE
);
892 ok(!ret
&& GetLastError() == CRYPT_E_ASN1_BADTAG
,
893 "Expected CRYPT_E_ASN1_BADTAG, got %x\n", GetLastError());
895 /* but succeeds with explicit type. */
896 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, CMSG_DATA
, 0, NULL
,
898 ret
= CryptMsgUpdate(msg
, dataEmptyBareContent
,
899 sizeof(dataEmptyBareContent
), TRUE
);
901 ok(ret
, "CryptMsgUpdate failed: %x\n", GetLastError());
904 /* Decoding valid content with an unsupported OID fails */
905 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
, 0, 0, 0, NULL
, NULL
);
906 SetLastError(0xdeadbeef);
907 ret
= CryptMsgUpdate(msg
, bogusOIDContent
, sizeof(bogusOIDContent
), TRUE
);
909 ok(!ret
&& GetLastError() == CRYPT_E_INVALID_MSG_TYPE
,
910 "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError());
914 static void test_decode_msg(void)
916 test_decode_msg_update();
921 /* Basic parameter checking tests */
922 test_msg_open_to_encode();
923 test_msg_open_to_decode();
924 test_msg_get_param();
927 /* Message-type specific tests */