1 /*
2 * Copyright 2007 Juan Lang
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #include "config.h"
20 #include "wine/port.h"
21
22 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wincrypt.h"
26 #include "snmp.h"
27
28 #include "wine/debug.h"
29 #include "wine/exception.h"
30 #include "crypt32_private.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
33
34 /* Called when a message's ref count reaches zero. Free any message-specific
35 * data here.
36 */
37 typedef void (*CryptMsgCloseFunc)(HCRYPTMSG msg);
38
39 typedef BOOL (*CryptMsgGetParamFunc)(HCRYPTMSG hCryptMsg, DWORD dwParamType,
40 DWORD dwIndex, void *pvData, DWORD *pcbData);
41
42 typedef BOOL (*CryptMsgUpdateFunc)(HCRYPTMSG hCryptMsg, const BYTE *pbData,
43 DWORD cbData, BOOL fFinal);
44
45 typedef BOOL (*CryptMsgControlFunc)(HCRYPTMSG hCryptMsg, DWORD dwFlags,
46 DWORD dwCtrlType, const void *pvCtrlPara);
47
48 BOOL CRYPT_DefaultMsgControl(HCRYPTMSG hCryptMsg, DWORD dwFlags,
49 DWORD dwCtrlType, const void *pvCtrlPara)
50 {
51 TRACE("(%p, %08x, %d, %p)\n", hCryptMsg, dwFlags, dwCtrlType, pvCtrlPara);
52 SetLastError(E_INVALIDARG);
53 return FALSE;
54 }
55
56 typedef enum _CryptMsgState {
57 MsgStateInit,
58 MsgStateUpdated,
59 MsgStateDataFinalized,
60 MsgStateFinalized
61 } CryptMsgState;
62
63 typedef struct _CryptMsgBase
64 {
65 LONG ref;
66 DWORD open_flags;
67 BOOL streamed;
68 CMSG_STREAM_INFO stream_info;
69 CryptMsgState state;
70 CryptMsgCloseFunc close;
71 CryptMsgUpdateFunc update;
72 CryptMsgGetParamFunc get_param;
73 CryptMsgControlFunc control;
74 } CryptMsgBase;
75
76 static inline void CryptMsgBase_Init(CryptMsgBase *msg, DWORD dwFlags,
77 PCMSG_STREAM_INFO pStreamInfo, CryptMsgCloseFunc close,
78 CryptMsgGetParamFunc get_param, CryptMsgUpdateFunc update,
79 CryptMsgControlFunc control)
80 {
81 msg->ref = 1;
82 msg->open_flags = dwFlags;
83 if (pStreamInfo)
84 {
85 msg->streamed = TRUE;
86 msg->stream_info = *pStreamInfo;
87 }
88 else
89 {
90 msg->streamed = FALSE;
91 memset(&msg->stream_info, 0, sizeof(msg->stream_info));
92 }
93 msg->close = close;
94 msg->get_param = get_param;
95 msg->update = update;
96 msg->control = control;
97 msg->state = MsgStateInit;
98 }
99
100 typedef struct _CDataEncodeMsg
101 {
102 CryptMsgBase base;
103 DWORD bare_content_len;
104 LPBYTE bare_content;
105 } CDataEncodeMsg;
106
107 static const BYTE empty_data_content[] = { 0x04,0x00 };
108
109 static void CDataEncodeMsg_Close(HCRYPTMSG hCryptMsg)
110 {
111 CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg;
112
113 if (msg->bare_content != empty_data_content)
114 LocalFree(msg->bare_content);
115 }
116
117 static BOOL WINAPI CRYPT_EncodeContentLength(DWORD dwCertEncodingType,
118 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
119 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
120 {
121 DWORD dataLen = *(DWORD *)pvStructInfo;
122 DWORD lenBytes;
123 BOOL ret = TRUE;
124
125 /* Trick: report bytes needed based on total message length, even though
126 * the message isn't available yet. The caller will use the length
127 * reported here to encode its length.
128 */
129 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
130 if (!pbEncoded)
131 *pcbEncoded = 1 + lenBytes + dataLen;
132 else
133 {
134 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
135 pcbEncoded, 1 + lenBytes)))
136 {
137 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
138 pbEncoded = *(BYTE **)pbEncoded;
139 *pbEncoded++ = ASN_OCTETSTRING;
140 CRYPT_EncodeLen(dataLen, pbEncoded,
141 &lenBytes);
142 }
143 }
144 return ret;
145 }
146
147 static BOOL CRYPT_EncodeDataContentInfoHeader(CDataEncodeMsg *msg,
148 CRYPT_DATA_BLOB *header)
149 {
150 BOOL ret;
151
152 if (msg->base.streamed && msg->base.stream_info.cbContent == 0xffffffff)
153 {
154 static const BYTE headerValue[] = { 0x30,0x80,0x06,0x09,0x2a,0x86,0x48,
155 0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x80,0x24,0x80 };
156
157 header->pbData = LocalAlloc(0, sizeof(headerValue));
158 if (header->pbData)
159 {
160 header->cbData = sizeof(headerValue);
161 memcpy(header->pbData, headerValue, sizeof(headerValue));
162 ret = TRUE;
163 }
164 else
165 ret = FALSE;
166 }
167 else
168 {
169 struct AsnConstructedItem constructed = { 0,
170 &msg->base.stream_info.cbContent, CRYPT_EncodeContentLength };
171 struct AsnEncodeSequenceItem items[2] = {
172 { szOID_RSA_data, CRYPT_AsnEncodeOid, 0 },
173 { &constructed, CRYPT_AsnEncodeConstructed, 0 },
174 };
175
176 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items,
177 sizeof(items) / sizeof(items[0]), CRYPT_ENCODE_ALLOC_FLAG, NULL,
178 (LPBYTE)&header->pbData, &header->cbData);
179 if (ret)
180 {
181 /* Trick: subtract the content length from the reported length,
182 * as the actual content hasn't come yet.
183 */
184 header->cbData -= msg->base.stream_info.cbContent;
185 }
186 }
187 return ret;
188 }
189
190 static BOOL CDataEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
191 DWORD cbData, BOOL fFinal)
192 {
193 CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg;
194 BOOL ret = FALSE;
195
196 if (msg->base.state == MsgStateFinalized)
197 SetLastError(CRYPT_E_MSG_ERROR);
198 else if (msg->base.streamed)
199 {
200 __TRY
201 {
202 if (msg->base.state != MsgStateUpdated)
203 {
204 CRYPT_DATA_BLOB header;
205
206 ret = CRYPT_EncodeDataContentInfoHeader(msg, &header);
207 if (ret)
208 {
209 ret = msg->base.stream_info.pfnStreamOutput(
210 msg->base.stream_info.pvArg, header.pbData, header.cbData,
211 FALSE);
212 LocalFree(header.pbData);
213 }
214 }
215 /* Curiously, every indefinite-length streamed update appears to
216 * get its own tag and length, regardless of fFinal.
217 */
218 if (msg->base.stream_info.cbContent == 0xffffffff)
219 {
220 BYTE *header;
221 DWORD headerLen;
222
223 ret = CRYPT_EncodeContentLength(X509_ASN_ENCODING, NULL,
224 &cbData, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&header,
225 &headerLen);
226 if (ret)
227 {
228 ret = msg->base.stream_info.pfnStreamOutput(
229 msg->base.stream_info.pvArg, header, headerLen,
230 FALSE);
231 LocalFree(header);
232 }
233 }
234 if (!fFinal)
235 {
236 ret = msg->base.stream_info.pfnStreamOutput(
237 msg->base.stream_info.pvArg, (BYTE *)pbData, cbData,
238 FALSE);
239 msg->base.state = MsgStateUpdated;
240 }
241 else
242 {
243 msg->base.state = MsgStateFinalized;
244 if (msg->base.stream_info.cbContent == 0xffffffff)
245 {
246 BYTE indefinite_trailer[6] = { 0 };
247
248 ret = msg->base.stream_info.pfnStreamOutput(
249 msg->base.stream_info.pvArg, (BYTE *)pbData, cbData,
250 FALSE);
251 if (ret)
252 ret = msg->base.stream_info.pfnStreamOutput(
253 msg->base.stream_info.pvArg, indefinite_trailer,
254 sizeof(indefinite_trailer), TRUE);
255 }
256 else
257 ret = msg->base.stream_info.pfnStreamOutput(
258 msg->base.stream_info.pvArg, (BYTE *)pbData, cbData, TRUE);
259 }
260 }
261 __EXCEPT_PAGE_FAULT
262 {
263 SetLastError(STATUS_ACCESS_VIOLATION);
264 ret = FALSE;
265 }
266 __ENDTRY;
267 }
268 else
269 {
270 if (!fFinal)
271 {
272 if (msg->base.open_flags & CMSG_DETACHED_FLAG)
273 SetLastError(E_INVALIDARG);
274 else
275 SetLastError(CRYPT_E_MSG_ERROR);
276 }
277 else
278 {
279 msg->base.state = MsgStateFinalized;
280 if (!cbData)
281 SetLastError(E_INVALIDARG);
282 else
283 {
284 CRYPT_DATA_BLOB blob = { cbData, (LPBYTE)pbData };
285
286 /* non-streamed data messages don't allow non-final updates,
287 * don't bother checking whether data already exist, they can't.
288 */
289 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
290 &blob, CRYPT_ENCODE_ALLOC_FLAG, NULL, &msg->bare_content,
291 &msg->bare_content_len);
292 }
293 }
294 }
295 return ret;
296 }
297
298 static BOOL CRYPT_CopyParam(void *pvData, DWORD *pcbData, const void *src,
299 DWORD len)
300 {
301 BOOL ret = TRUE;
302
303 if (!pvData)
304 *pcbData = len;
305 else if (*pcbData < len)
306 {
307 *pcbData = len;
308 SetLastError(ERROR_MORE_DATA);
309 ret = FALSE;
310 }
311 else
312 {
313 *pcbData = len;
314 memcpy(pvData, src, len);
315 }
316 return ret;
317 }
318
319 static BOOL CDataEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
320 DWORD dwIndex, void *pvData, DWORD *pcbData)
321 {
322 CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg;
323 BOOL ret = FALSE;
324
325 switch (dwParamType)
326 {
327 case CMSG_CONTENT_PARAM:
328 if (msg->base.streamed)
329 SetLastError(E_INVALIDARG);
330 else
331 {
332 CRYPT_CONTENT_INFO info;
333 char rsa_data[] = "1.2.840.113549.1.7.1";
334
335 info.pszObjId = rsa_data;
336 info.Content.cbData = msg->bare_content_len;
337 info.Content.pbData = msg->bare_content;
338 ret = CryptEncodeObject(X509_ASN_ENCODING, PKCS_CONTENT_INFO, &info,
339 pvData, pcbData);
340 }
341 break;
342 case CMSG_BARE_CONTENT_PARAM:
343 if (msg->base.streamed)
344 SetLastError(E_INVALIDARG);
345 else
346 ret = CRYPT_CopyParam(pvData, pcbData, msg->bare_content,
347 msg->bare_content_len);
348 break;
349 default:
350 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
351 }
352 return ret;
353 }
354
355 static HCRYPTMSG CDataEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo,
356 LPSTR pszInnerContentObjID, PCMSG_STREAM_INFO pStreamInfo)
357 {
358 CDataEncodeMsg *msg;
359
360 if (pvMsgEncodeInfo)
361 {
362 SetLastError(E_INVALIDARG);
363 return NULL;
364 }
365 msg = CryptMemAlloc(sizeof(CDataEncodeMsg));
366 if (msg)
367 {
368 CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
369 CDataEncodeMsg_Close, CDataEncodeMsg_GetParam, CDataEncodeMsg_Update,
370 CRYPT_DefaultMsgControl);
371 msg->bare_content_len = sizeof(empty_data_content);
372 msg->bare_content = (LPBYTE)empty_data_content;
373 }
374 return (HCRYPTMSG)msg;
375 }
376
377 typedef struct _CHashEncodeMsg
378 {
379 CryptMsgBase base;
380 HCRYPTPROV prov;
381 HCRYPTHASH hash;
382 CRYPT_DATA_BLOB data;
383 } CHashEncodeMsg;
384
385 static void CHashEncodeMsg_Close(HCRYPTMSG hCryptMsg)
386 {
387 CHashEncodeMsg *msg = (CHashEncodeMsg *)hCryptMsg;
388
389 CryptMemFree(msg->data.pbData);
390 CryptDestroyHash(msg->hash);
391 if (msg->base.open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
392 CryptReleaseContext(msg->prov, 0);
393 }
394
395 static BOOL CRYPT_EncodePKCSDigestedData(CHashEncodeMsg *msg, void *pvData,
396 DWORD *pcbData)
397 {
398 BOOL ret;
399 ALG_ID algID;
400 DWORD size = sizeof(algID);
401
402 ret = CryptGetHashParam(msg->hash, HP_ALGID, (BYTE *)&algID, &size, 0);
403 if (ret)
404 {
405 CRYPT_DIGESTED_DATA digestedData = { 0 };
406 char oid_rsa_data[] = szOID_RSA_data;
407
408 digestedData.version = CMSG_HASHED_DATA_PKCS_1_5_VERSION;
409 digestedData.DigestAlgorithm.pszObjId = (LPSTR)CertAlgIdToOID(algID);
410 /* FIXME: what about digestedData.DigestAlgorithm.Parameters? */
411 /* Quirk: OID is only encoded messages if an update has happened */
412 if (msg->base.state != MsgStateInit)
413 digestedData.ContentInfo.pszObjId = oid_rsa_data;
414 if (!(msg->base.open_flags & CMSG_DETACHED_FLAG) && msg->data.cbData)
415 {
416 ret = CRYPT_AsnEncodeOctets(0, NULL, &msg->data,
417 CRYPT_ENCODE_ALLOC_FLAG, NULL,
418 (LPBYTE)&digestedData.ContentInfo.Content.pbData,
419 &digestedData.ContentInfo.Content.cbData);
420 }
421 if (msg->base.state == MsgStateFinalized)
422 {
423 size = sizeof(DWORD);
424 ret = CryptGetHashParam(msg->hash, HP_HASHSIZE,
425 (LPBYTE)&digestedData.hash.cbData, &size, 0);
426 if (ret)
427 {
428 digestedData.hash.pbData = CryptMemAlloc(
429 digestedData.hash.cbData);
430 ret = CryptGetHashParam(msg->hash, HP_HASHVAL,
431 digestedData.hash.pbData, &digestedData.hash.cbData, 0);
432 }
433 }
434 if (ret)
435 ret = CRYPT_AsnEncodePKCSDigestedData(&digestedData, pvData,
436 pcbData);
437 CryptMemFree(digestedData.hash.pbData);
438 LocalFree(digestedData.ContentInfo.Content.pbData);
439 }
440 return ret;
441 }
442
443 static BOOL CHashEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
444 DWORD dwIndex, void *pvData, DWORD *pcbData)
445 {
446 CHashEncodeMsg *msg = (CHashEncodeMsg *)hCryptMsg;
447 BOOL ret = FALSE;
448
449 TRACE("(%p, %d, %d, %p, %p)\n", hCryptMsg, dwParamType, dwIndex,
450 pvData, pcbData);
451
452 switch (dwParamType)
453 {
454 case CMSG_BARE_CONTENT_PARAM:
455 if (msg->base.streamed)
456 SetLastError(E_INVALIDARG);
457 else
458 ret = CRYPT_EncodePKCSDigestedData(msg, pvData, pcbData);
459 break;
460 case CMSG_CONTENT_PARAM:
461 {
462 CRYPT_CONTENT_INFO info;
463
464 ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, NULL,
465 &info.Content.cbData);
466 if (ret)
467 {
468 info.Content.pbData = CryptMemAlloc(info.Content.cbData);
469 if (info.Content.pbData)
470 {
471 ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0,
472 info.Content.pbData, &info.Content.cbData);
473 if (ret)
474 {
475 char oid_rsa_hashed[] = szOID_RSA_hashedData;
476
477 info.pszObjId = oid_rsa_hashed;
478 ret = CryptEncodeObjectEx(X509_ASN_ENCODING,
479 PKCS_CONTENT_INFO, &info, 0, NULL, pvData, pcbData);
480 }
481 CryptMemFree(info.Content.pbData);
482 }
483 else
484 ret = FALSE;
485 }
486 break;
487 }
488 case CMSG_COMPUTED_HASH_PARAM:
489 ret = CryptGetHashParam(msg->hash, HP_HASHVAL, (BYTE *)pvData, pcbData,
490 0);
491 break;
492 case CMSG_VERSION_PARAM:
493 if (msg->base.state != MsgStateFinalized)
494 SetLastError(CRYPT_E_MSG_ERROR);
495 else
496 {
497 DWORD version = CMSG_HASHED_DATA_PKCS_1_5_VERSION;
498
499 /* Since the data are always encoded as octets, the version is
500 * always 0 (see rfc3852, section 7)
501 */
502 ret = CRYPT_CopyParam(pvData, pcbData, &version, sizeof(version));
503 }
504 break;
505 default:
506 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
507 }
508 return ret;
509 }
510
511 static BOOL CHashEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
512 DWORD cbData, BOOL fFinal)
513 {
514 CHashEncodeMsg *msg = (CHashEncodeMsg *)hCryptMsg;
515 BOOL ret = FALSE;
516
517 TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal);
518
519 if (msg->base.state == MsgStateFinalized)
520 SetLastError(CRYPT_E_MSG_ERROR);
521 else if (msg->base.streamed || (msg->base.open_flags & CMSG_DETACHED_FLAG))
522 {
523 /* Doesn't do much, as stream output is never called, and you
524 * can't get the content.
525 */
526 ret = CryptHashData(msg->hash, pbData, cbData, 0);
527 msg->base.state = fFinal ? MsgStateFinalized : MsgStateUpdated;
528 }
529 else
530 {
531 if (!fFinal)
532 SetLastError(CRYPT_E_MSG_ERROR);
533 else
534 {
535 ret = CryptHashData(msg->hash, pbData, cbData, 0);
536 if (ret)
537 {
538 msg->data.pbData = CryptMemAlloc(cbData);
539 if (msg->data.pbData)
540 {
541 memcpy(msg->data.pbData + msg->data.cbData, pbData, cbData);
542 msg->data.cbData += cbData;
543 }
544 else
545 ret = FALSE;
546 }
547 msg->base.state = MsgStateFinalized;
548 }
549 }
550 return ret;
551 }
552
553 static HCRYPTMSG CHashEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo,
554 LPSTR pszInnerContentObjID, PCMSG_STREAM_INFO pStreamInfo)
555 {
556 CHashEncodeMsg *msg;
557 const CMSG_HASHED_ENCODE_INFO *info =
558 (const CMSG_HASHED_ENCODE_INFO *)pvMsgEncodeInfo;
559 HCRYPTPROV prov;
560 ALG_ID algID;
561
562 if (info->cbSize != sizeof(CMSG_HASHED_ENCODE_INFO))
563 {
564 SetLastError(E_INVALIDARG);
565 return NULL;
566 }
567 if (!(algID = CertOIDToAlgId(info->HashAlgorithm.pszObjId)))
568 {
569 SetLastError(CRYPT_E_UNKNOWN_ALGO);
570 return NULL;
571 }
572 if (info->hCryptProv)
573 prov = info->hCryptProv;
574 else
575 {
576 prov = CRYPT_GetDefaultProvider();
577 dwFlags &= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG;
578 }
579 msg = CryptMemAlloc(sizeof(CHashEncodeMsg));
580 if (msg)
581 {
582 CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
583 CHashEncodeMsg_Close, CHashEncodeMsg_GetParam, CHashEncodeMsg_Update,
584 CRYPT_DefaultMsgControl);
585 msg->prov = prov;
586 msg->data.cbData = 0;
587 msg->data.pbData = NULL;
588 if (!CryptCreateHash(prov, algID, 0, 0, &msg->hash))
589 {
590 CryptMsgClose(msg);
591 msg = NULL;
592 }
593 }
594 return (HCRYPTMSG)msg;
595 }
596
597 typedef struct _CMSG_SIGNER_ENCODE_INFO_WITH_CMS
598 {
599 DWORD cbSize;
600 PCERT_INFO pCertInfo;
601 HCRYPTPROV hCryptProv;
602 DWORD dwKeySpec;
603 CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
604 void *pvHashAuxInfo;
605 DWORD cAuthAttr;
606 PCRYPT_ATTRIBUTE rgAuthAttr;
607 DWORD cUnauthAttr;
608 PCRYPT_ATTRIBUTE rgUnauthAttr;
609 CERT_ID SignerId;
610 CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm;
611 void *pvHashEncryptionAuxInfo;
612 } CMSG_SIGNER_ENCODE_INFO_WITH_CMS, *PCMSG_SIGNER_ENCODE_INFO_WITH_CMS;
613
614 typedef struct _CMSG_SIGNED_ENCODE_INFO_WITH_CMS
615 {
616 DWORD cbSize;
617 DWORD cSigners;
618 PCMSG_SIGNER_ENCODE_INFO_WITH_CMS rgSigners;
619 DWORD cCertEncoded;
620 PCERT_BLOB rgCertEncoded;
621 DWORD cCrlEncoded;
622 PCRL_BLOB rgCrlEncoded;
623 DWORD cAttrCertEncoded;
624 PCERT_BLOB rgAttrCertEncoded;
625 } CMSG_SIGNED_ENCODE_INFO_WITH_CMS, *PCMSG_SIGNED_ENCODE_INFO_WITH_CMS;
626
627 static BOOL CRYPT_IsValidSigner(CMSG_SIGNER_ENCODE_INFO_WITH_CMS *signer)
628 {
629 if (signer->cbSize != sizeof(CMSG_SIGNER_ENCODE_INFO) &&
630 signer->cbSize != sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS))
631 {
632 SetLastError(E_INVALIDARG);
633 return FALSE;
634 }
635 if (signer->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS))
636 {
637 FIXME("CMSG_SIGNER_ENCODE_INFO with CMS fields unsupported\n");
638 return FALSE;
639 }
640 if (!signer->pCertInfo->SerialNumber.cbData)
641 {
642 SetLastError(E_INVALIDARG);
643 return FALSE;
644 }
645 if (!signer->pCertInfo->Issuer.cbData)
646 {
647 SetLastError(E_INVALIDARG);
648 return FALSE;
649 }
650 if (!signer->hCryptProv)
651 {
652 SetLastError(E_INVALIDARG);
653 return FALSE;
654 }
655 if (!CertOIDToAlgId(signer->HashAlgorithm.pszObjId))
656 {
657 SetLastError(CRYPT_E_UNKNOWN_ALGO);
658 return FALSE;
659 }
660 return TRUE;
661 }
662
663 static BOOL CRYPT_ConstructBlob(CRYPT_DATA_BLOB *out, const CRYPT_DATA_BLOB *in)
664 {
665 BOOL ret = TRUE;
666
667 out->cbData = in->cbData;
668 if (out->cbData)
669 {
670 out->pbData = CryptMemAlloc(out->cbData);
671 if (out->pbData)
672 memcpy(out->pbData, in->pbData, out->cbData);
673 else
674 ret = FALSE;
675 }
676 else
677 out->pbData = NULL;
678 return ret;
679 }
680
681 typedef struct _BlobArray
682 {
683 DWORD cBlobs;
684 PCRYPT_DATA_BLOB blobs;
685 } BlobArray;
686
687 static BOOL CRYPT_ConstructBlobArray(BlobArray *out, const BlobArray *in)
688 {
689 BOOL ret = TRUE;
690
691 out->cBlobs = in->cBlobs;
692 if (out->cBlobs)
693 {
694 out->blobs = CryptMemAlloc(out->cBlobs * sizeof(CRYPT_DATA_BLOB));
695 if (out->blobs)
696 {
697 DWORD i;
698
699 memset(out->blobs, 0, out->cBlobs * sizeof(CRYPT_DATA_BLOB));
700 for (i = 0; ret && i < out->cBlobs; i++)
701 ret = CRYPT_ConstructBlob(&out->blobs[i], &in->blobs[i]);
702 }
703 else
704 ret = FALSE;
705 }
706 return ret;
707 }
708
709 static void CRYPT_FreeBlobArray(BlobArray *array)
710 {
711 DWORD i;
712
713 for (i = 0; i < array->cBlobs; i++)
714 CryptMemFree(array->blobs[i].pbData);
715 CryptMemFree(array->blobs);
716 }
717
718 static BOOL CRYPT_ConstructAttribute(CRYPT_ATTRIBUTE *out,
719 const CRYPT_ATTRIBUTE *in)
720 {
721 BOOL ret;
722
723 out->pszObjId = CryptMemAlloc(strlen(in->pszObjId) + 1);
724 if (out->pszObjId)
725 {
726 strcpy(out->pszObjId, in->pszObjId);
727 ret = CRYPT_ConstructBlobArray((BlobArray *)&out->cValue,
728 (const BlobArray *)&in->cValue);
729 }
730 else
731 ret = FALSE;
732 return ret;
733 }
734
735 static BOOL CRYPT_ConstructAttributes(CRYPT_ATTRIBUTES *out,
736 const CRYPT_ATTRIBUTES *in)
737 {
738 BOOL ret = TRUE;
739
740 out->cAttr = in->cAttr;
741 if (out->cAttr)
742 {
743 out->rgAttr = CryptMemAlloc(out->cAttr * sizeof(CRYPT_ATTRIBUTE));
744 if (out->rgAttr)
745 {
746 DWORD i;
747
748 memset(out->rgAttr, 0, out->cAttr * sizeof(CRYPT_ATTRIBUTE));
749 for (i = 0; ret && i < out->cAttr; i++)
750 ret = CRYPT_ConstructAttribute(&out->rgAttr[i], &in->rgAttr[i]);
751 }
752 else
753 ret = FALSE;
754 }
755 else
756 out->rgAttr = NULL;
757 return ret;
758 }
759
760 /* Constructs a CMSG_SIGNER_INFO from a CMSG_SIGNER_ENCODE_INFO_WITH_CMS. */
761 static BOOL CSignerInfo_Construct(CMSG_SIGNER_INFO *info,
762 CMSG_SIGNER_ENCODE_INFO_WITH_CMS *in)
763 {
764 BOOL ret;
765
766 /* Note: needs to change if CMS fields are supported */
767 info->dwVersion = CMSG_SIGNER_INFO_V1;
768 ret = CRYPT_ConstructBlob(&info->Issuer, &in->pCertInfo->Issuer);
769 if (ret)
770 ret = CRYPT_ConstructBlob(&info->SerialNumber,
771 &in->pCertInfo->SerialNumber);
772 /* Assumption: algorithm IDs will point to static strings, not
773 * stack-based ones, so copying the pointer values is safe.
774 */
775 info->HashAlgorithm.pszObjId = in->HashAlgorithm.pszObjId;
776 if (ret)
777 ret = CRYPT_ConstructBlob(&info->HashAlgorithm.Parameters,
778 &in->HashAlgorithm.Parameters);
779 memset(&info->HashEncryptionAlgorithm, 0,
780 sizeof(info->HashEncryptionAlgorithm));
781 if (ret)
782 ret = CRYPT_ConstructAttributes(&info->AuthAttrs,
783 (CRYPT_ATTRIBUTES *)&in->cAuthAttr);
784 if (ret)
785 ret = CRYPT_ConstructAttributes(&info->UnauthAttrs,
786 (CRYPT_ATTRIBUTES *)&in->cUnauthAttr);
787 return ret;
788 }
789
790 static void CSignerInfo_Free(CMSG_SIGNER_INFO *info)
791 {
792 DWORD i, j;
793
794 CryptMemFree(info->Issuer.pbData);
795 CryptMemFree(info->SerialNumber.pbData);
796 CryptMemFree(info->HashAlgorithm.Parameters.pbData);
797 CryptMemFree(info->EncryptedHash.pbData);
798 for (i = 0; i < info->AuthAttrs.cAttr; i++)
799 {
800 for (j = 0; j < info->AuthAttrs.rgAttr[i].cValue; j++)
801 CryptMemFree(info->AuthAttrs.rgAttr[i].rgValue[j].pbData);
802 CryptMemFree(info->AuthAttrs.rgAttr[i].rgValue);
803 CryptMemFree(info->AuthAttrs.rgAttr[i].pszObjId);
804 }
805 CryptMemFree(info->AuthAttrs.rgAttr);
806 for (i = 0; i < info->UnauthAttrs.cAttr; i++)
807 {
808 for (j = 0; j < info->UnauthAttrs.rgAttr[i].cValue; j++)
809 CryptMemFree(info->UnauthAttrs.rgAttr[i].rgValue[j].pbData);
810 CryptMemFree(info->UnauthAttrs.rgAttr[i].rgValue);
811 CryptMemFree(info->UnauthAttrs.rgAttr[i].pszObjId);
812 }
813 CryptMemFree(info->UnauthAttrs.rgAttr);
814 }
815
816 typedef struct _CSignerHandles
817 {
818 HCRYPTHASH contentHash;
819 HCRYPTHASH authAttrHash;
820 } CSignerHandles;
821
822 typedef struct _CSignedMsgData
823 {
824 CRYPT_SIGNED_INFO *info;
825 DWORD cSignerHandle;
826 CSignerHandles *signerHandles;
827 } CSignedMsgData;
828
829 /* Constructs the signer handles for the signerIndex'th signer of msg_data.
830 * Assumes signerIndex is a valid idnex, and that msg_data's info has already
831 * been constructed.
832 */
833 static BOOL CSignedMsgData_ConstructSignerHandles(CSignedMsgData *msg_data,
834 DWORD signerIndex, HCRYPTPROV crypt_prov)
835 {
836 ALG_ID algID;
837 BOOL ret;
838
839 algID = CertOIDToAlgId(
840 msg_data->info->rgSignerInfo[signerIndex].HashAlgorithm.pszObjId);
841 ret = CryptCreateHash(crypt_prov, algID, 0, 0,
842 &msg_data->signerHandles->contentHash);
843 if (ret && msg_data->info->rgSignerInfo[signerIndex].AuthAttrs.cAttr > 0)
844 ret = CryptCreateHash(crypt_prov, algID, 0, 0,
845 &msg_data->signerHandles->authAttrHash);
846 return ret;
847 }
848
849 /* Allocates a CSignedMsgData's handles. Assumes its info has already been
850 * constructed.
851 */
852 static BOOL CSignedMsgData_AllocateHandles(CSignedMsgData *msg_data)
853 {
854 BOOL ret = TRUE;
855
856 if (msg_data->info->cSignerInfo)
857 {
858 msg_data->signerHandles =
859 CryptMemAlloc(msg_data->info->cSignerInfo * sizeof(CSignerHandles));
860 if (msg_data->signerHandles)
861 {
862 msg_data->cSignerHandle = msg_data->info->cSignerInfo;
863 memset(msg_data->signerHandles, 0,
864 msg_data->info->cSignerInfo * sizeof(CSignerHandles));
865 }
866 else
867 {
868 msg_data->cSignerHandle = 0;
869 ret = FALSE;
870 }
871 }
872 else
873 {
874 msg_data->cSignerHandle = 0;
875 msg_data->signerHandles = NULL;
876 }
877 return ret;
878 }
879
880 static void CSignedMsgData_CloseHandles(CSignedMsgData *msg_data)
881 {
882 DWORD i;
883
884 for (i = 0; i < msg_data->cSignerHandle; i++)
885 {
886 if (msg_data->signerHandles[i].contentHash)
887 CryptDestroyHash(msg_data->signerHandles[i].contentHash);
888 if (msg_data->signerHandles[i].authAttrHash)
889 CryptDestroyHash(msg_data->signerHandles[i].authAttrHash);
890 }
891 CryptMemFree(msg_data->signerHandles);
892 msg_data->signerHandles = NULL;
893 msg_data->cSignerHandle = 0;
894 }
895
896 static BOOL CSignedMsgData_UpdateHash(CSignedMsgData *msg_data,
897 const BYTE *pbData, DWORD cbData)
898 {
899 DWORD i;
900 BOOL ret = TRUE;
901
902 for (i = 0; ret && i < msg_data->cSignerHandle; i++)
903 ret = CryptHashData(msg_data->signerHandles[i].contentHash, pbData,
904 cbData, 0);
905 return ret;
906 }
907
908 static BOOL CRYPT_AppendAttribute(CRYPT_ATTRIBUTES *out,
909 const CRYPT_ATTRIBUTE *in)
910 {
911 BOOL ret = FALSE;
912
913 out->rgAttr = CryptMemRealloc(out->rgAttr,
914 (out->cAttr + 1) * sizeof(CRYPT_ATTRIBUTE));
915 if (out->rgAttr)
916 {
917 ret = CRYPT_ConstructAttribute(&out->rgAttr[out->cAttr], in);
918 if (ret)
919 out->cAttr++;
920 }
921 return ret;
922 }
923
924 static BOOL CSignedMsgData_AppendMessageDigestAttribute(
925 CSignedMsgData *msg_data, DWORD signerIndex)
926 {
927 BOOL ret;
928 DWORD size;
929 CRYPT_HASH_BLOB hash = { 0, NULL }, encodedHash = { 0, NULL };
930 char messageDigest[] = szOID_RSA_messageDigest;
931 CRYPT_ATTRIBUTE messageDigestAttr = { messageDigest, 1, &encodedHash };
932
933 size = sizeof(DWORD);
934 ret = CryptGetHashParam(
935 msg_data->signerHandles[signerIndex].contentHash, HP_HASHSIZE,
936 (LPBYTE)&hash.cbData, &size, 0);
937 if (ret)
938 {
939 hash.pbData = CryptMemAlloc(hash.cbData);
940 ret = CryptGetHashParam(
941 msg_data->signerHandles[signerIndex].contentHash, HP_HASHVAL,
942 hash.pbData, &hash.cbData, 0);
943 if (ret)
944 {