crypt32: Add a stub hash message implementation.
[wine/wine64.git] / dlls / crypt32 / msg.c
blob1918713fca83fb5b3e4786a39a7623b3246f2abe
1 /*
2 * Copyright 2007 Juan Lang
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.
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.
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
18 #include <stdarg.h>
19 #include "windef.h"
20 #include "winbase.h"
21 #include "wincrypt.h"
22 #include "snmp.h"
24 #include "wine/debug.h"
25 #include "wine/exception.h"
26 #include "crypt32_private.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
30 /* Called when a message's ref count reaches zero. Free any message-specific
31 * data here.
33 typedef void (*CryptMsgCloseFunc)(HCRYPTMSG msg);
35 typedef BOOL (*CryptMsgGetParamFunc)(HCRYPTMSG hCryptMsg, DWORD dwParamType,
36 DWORD dwIndex, void *pvData, DWORD *pcbData);
38 typedef BOOL (*CryptMsgUpdateFunc)(HCRYPTMSG hCryptMsg, const BYTE *pbData,
39 DWORD cbData, BOOL fFinal);
41 typedef struct _CryptMsgBase
43 LONG ref;
44 DWORD open_flags;
45 BOOL streamed;
46 CMSG_STREAM_INFO stream_info;
47 BOOL finalized;
48 CryptMsgCloseFunc close;
49 CryptMsgUpdateFunc update;
50 CryptMsgGetParamFunc get_param;
51 } CryptMsgBase;
53 static inline void CryptMsgBase_Init(CryptMsgBase *msg, DWORD dwFlags,
54 PCMSG_STREAM_INFO pStreamInfo, CryptMsgCloseFunc close,
55 CryptMsgGetParamFunc get_param, CryptMsgUpdateFunc update)
57 msg->ref = 1;
58 msg->open_flags = dwFlags;
59 if (pStreamInfo)
61 msg->streamed = TRUE;
62 memcpy(&msg->stream_info, pStreamInfo, sizeof(msg->stream_info));
64 else
66 msg->streamed = FALSE;
67 memset(&msg->stream_info, 0, sizeof(msg->stream_info));
69 msg->close = close;
70 msg->get_param = get_param;
71 msg->update = update;
72 msg->finalized = FALSE;
75 typedef struct _CDataEncodeMsg
77 CryptMsgBase base;
78 DWORD bare_content_len;
79 LPBYTE bare_content;
80 BOOL begun;
81 } CDataEncodeMsg;
83 static const BYTE empty_data_content[] = { 0x04,0x00 };
85 static void CDataEncodeMsg_Close(HCRYPTMSG hCryptMsg)
87 CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg;
89 if (msg->bare_content != empty_data_content)
90 LocalFree(msg->bare_content);
93 static WINAPI BOOL CRYPT_EncodeContentLength(DWORD dwCertEncodingType,
94 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
95 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
97 const CDataEncodeMsg *msg = (const CDataEncodeMsg *)pvStructInfo;
98 DWORD lenBytes;
99 BOOL ret = TRUE;
101 /* Trick: report bytes needed based on total message length, even though
102 * the message isn't available yet. The caller will use the length
103 * reported here to encode its length.
105 CRYPT_EncodeLen(msg->base.stream_info.cbContent, NULL, &lenBytes);
106 if (!pbEncoded)
107 *pcbEncoded = 1 + lenBytes + msg->base.stream_info.cbContent;
108 else
110 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
111 pcbEncoded, 1 + lenBytes)))
113 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
114 pbEncoded = *(BYTE **)pbEncoded;
115 *pbEncoded++ = ASN_OCTETSTRING;
116 CRYPT_EncodeLen(msg->base.stream_info.cbContent, pbEncoded,
117 &lenBytes);
120 return ret;
123 static BOOL CRYPT_EncodeDataContentInfoHeader(CDataEncodeMsg *msg,
124 CRYPT_DATA_BLOB *header)
126 BOOL ret;
128 if (msg->base.streamed && msg->base.stream_info.cbContent == 0xffffffff)
130 FIXME("unimplemented for indefinite-length encoding\n");
131 header->cbData = 0;
132 header->pbData = NULL;
133 ret = TRUE;
135 else
137 struct AsnConstructedItem constructed = { 0, msg,
138 CRYPT_EncodeContentLength };
139 struct AsnEncodeSequenceItem items[2] = {
140 { szOID_RSA_data, CRYPT_AsnEncodeOid, 0 },
141 { &constructed, CRYPT_AsnEncodeConstructed, 0 },
144 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items,
145 sizeof(items) / sizeof(items[0]), CRYPT_ENCODE_ALLOC_FLAG, NULL,
146 (LPBYTE)&header->pbData, &header->cbData);
147 if (ret)
149 /* Trick: subtract the content length from the reported length,
150 * as the actual content hasn't come yet.
152 header->cbData -= msg->base.stream_info.cbContent;
155 return ret;
158 static BOOL CDataEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
159 DWORD cbData, BOOL fFinal)
161 CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg;
162 BOOL ret = FALSE;
164 if (msg->base.finalized)
165 SetLastError(CRYPT_E_MSG_ERROR);
166 else if (msg->base.streamed)
168 if (fFinal)
169 msg->base.finalized = TRUE;
170 __TRY
172 if (!msg->begun)
174 CRYPT_DATA_BLOB header;
176 msg->begun = TRUE;
177 ret = CRYPT_EncodeDataContentInfoHeader(msg, &header);
178 if (ret)
180 ret = msg->base.stream_info.pfnStreamOutput(
181 msg->base.stream_info.pvArg, header.pbData, header.cbData,
182 FALSE);
183 LocalFree(header.pbData);
186 if (!fFinal)
187 ret = msg->base.stream_info.pfnStreamOutput(
188 msg->base.stream_info.pvArg, (BYTE *)pbData, cbData,
189 FALSE);
190 else
192 if (msg->base.stream_info.cbContent == 0xffffffff)
194 BYTE indefinite_trailer[6] = { 0 };
196 ret = msg->base.stream_info.pfnStreamOutput(
197 msg->base.stream_info.pvArg, (BYTE *)pbData, cbData,
198 FALSE);
199 if (ret)
200 ret = msg->base.stream_info.pfnStreamOutput(
201 msg->base.stream_info.pvArg, indefinite_trailer,
202 sizeof(indefinite_trailer), TRUE);
204 else
205 ret = msg->base.stream_info.pfnStreamOutput(
206 msg->base.stream_info.pvArg, (BYTE *)pbData, cbData, TRUE);
209 __EXCEPT_PAGE_FAULT
211 SetLastError(STATUS_ACCESS_VIOLATION);
213 __ENDTRY;
215 else
217 if (!fFinal)
219 if (msg->base.open_flags & CMSG_DETACHED_FLAG)
220 SetLastError(E_INVALIDARG);
221 else
222 SetLastError(CRYPT_E_MSG_ERROR);
224 else
226 msg->base.finalized = TRUE;
227 if (!cbData)
228 SetLastError(E_INVALIDARG);
229 else
231 CRYPT_DATA_BLOB blob = { cbData, (LPBYTE)pbData };
233 /* non-streamed data messages don't allow non-final updates,
234 * don't bother checking whether data already exist, they can't.
236 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
237 &blob, CRYPT_ENCODE_ALLOC_FLAG, NULL, &msg->bare_content,
238 &msg->bare_content_len);
242 return ret;
245 static BOOL CDataEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
246 DWORD dwIndex, void *pvData, DWORD *pcbData)
248 CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg;
249 BOOL ret = FALSE;
251 switch (dwParamType)
253 case CMSG_CONTENT_PARAM:
254 if (msg->base.streamed)
255 SetLastError(E_INVALIDARG);
256 else
258 CRYPT_CONTENT_INFO info;
259 char rsa_data[] = "1.2.840.113549.1.7.1";
261 info.pszObjId = rsa_data;
262 info.Content.cbData = msg->bare_content_len;
263 info.Content.pbData = msg->bare_content;
264 ret = CryptEncodeObject(X509_ASN_ENCODING, PKCS_CONTENT_INFO, &info,
265 pvData, pcbData);
267 break;
268 case CMSG_BARE_CONTENT_PARAM:
269 if (msg->base.streamed)
270 SetLastError(E_INVALIDARG);
271 else if (!pvData)
273 *pcbData = msg->bare_content_len;
274 ret = TRUE;
276 else if (*pcbData < msg->bare_content_len)
278 *pcbData = msg->bare_content_len;
279 SetLastError(ERROR_MORE_DATA);
281 else
283 *pcbData = msg->bare_content_len;
284 memcpy(pvData, msg->bare_content, msg->bare_content_len);
285 ret = TRUE;
287 break;
288 default:
289 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
291 return ret;
294 static HCRYPTMSG CDataEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo,
295 LPSTR pszInnerContentObjID, PCMSG_STREAM_INFO pStreamInfo)
297 CDataEncodeMsg *msg;
299 if (pvMsgEncodeInfo)
301 SetLastError(E_INVALIDARG);
302 return NULL;
304 msg = CryptMemAlloc(sizeof(CDataEncodeMsg));
305 if (msg)
307 CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
308 CDataEncodeMsg_Close, CDataEncodeMsg_GetParam, CDataEncodeMsg_Update);
309 msg->bare_content_len = sizeof(empty_data_content);
310 msg->bare_content = (LPBYTE)empty_data_content;
311 msg->begun = FALSE;
313 return (HCRYPTMSG)msg;
316 typedef struct _CHashEncodeMsg
318 CryptMsgBase base;
319 HCRYPTPROV prov;
320 HCRYPTHASH hash;
321 } CHashEncodeMsg;
323 static void CHashEncodeMsg_Close(HCRYPTMSG hCryptMsg)
325 CHashEncodeMsg *msg = (CHashEncodeMsg *)hCryptMsg;
327 CryptDestroyHash(msg->hash);
328 if (msg->base.open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
329 CryptReleaseContext(msg->prov, 0);
332 static BOOL CHashEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
333 DWORD dwIndex, void *pvData, DWORD *pcbData)
335 FIXME("(%p, %d, %d, %p, %p): stub\n", hCryptMsg, dwParamType, dwIndex,
336 pvData, pcbData);
337 return FALSE;
340 static BOOL CHashEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
341 DWORD cbData, BOOL fFinal)
343 FIXME("(%p, %p, %d, %d): stub\n", hCryptMsg, pbData, cbData, fFinal);
344 return FALSE;
347 static HCRYPTMSG CHashEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo,
348 LPSTR pszInnerContentObjID, PCMSG_STREAM_INFO pStreamInfo)
350 CHashEncodeMsg *msg;
351 const CMSG_HASHED_ENCODE_INFO *info =
352 (const CMSG_HASHED_ENCODE_INFO *)pvMsgEncodeInfo;
353 HCRYPTPROV prov;
354 ALG_ID algID;
356 if (info->cbSize != sizeof(CMSG_HASHED_ENCODE_INFO))
358 SetLastError(E_INVALIDARG);
359 return NULL;
361 if (!(algID = CertOIDToAlgId(info->HashAlgorithm.pszObjId)))
363 SetLastError(CRYPT_E_UNKNOWN_ALGO);
364 return NULL;
366 if (info->hCryptProv)
367 prov = info->hCryptProv;
368 else
370 prov = CRYPT_GetDefaultProvider();
371 dwFlags &= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG;
373 msg = CryptMemAlloc(sizeof(CHashEncodeMsg));
374 if (msg)
376 CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
377 CHashEncodeMsg_Close, CHashEncodeMsg_GetParam, CHashEncodeMsg_Update);
378 msg->prov = prov;
379 if (!CryptCreateHash(prov, algID, 0, 0, &msg->hash))
381 CryptMsgClose(msg);
382 msg = NULL;
385 return (HCRYPTMSG)msg;
388 static inline const char *MSG_TYPE_STR(DWORD type)
390 switch (type)
392 #define _x(x) case (x): return #x
393 _x(CMSG_DATA);
394 _x(CMSG_SIGNED);
395 _x(CMSG_ENVELOPED);
396 _x(CMSG_SIGNED_AND_ENVELOPED);
397 _x(CMSG_HASHED);
398 _x(CMSG_ENCRYPTED);
399 #undef _x
400 default:
401 return wine_dbg_sprintf("unknown (%d)", type);
405 HCRYPTMSG WINAPI CryptMsgOpenToEncode(DWORD dwMsgEncodingType, DWORD dwFlags,
406 DWORD dwMsgType, const void *pvMsgEncodeInfo, LPSTR pszInnerContentObjID,
407 PCMSG_STREAM_INFO pStreamInfo)
409 HCRYPTMSG msg = NULL;
411 TRACE("(%08x, %08x, %08x, %p, %s, %p)\n", dwMsgEncodingType, dwFlags,
412 dwMsgType, pvMsgEncodeInfo, debugstr_a(pszInnerContentObjID), pStreamInfo);
414 if (GET_CMSG_ENCODING_TYPE(dwMsgEncodingType) != PKCS_7_ASN_ENCODING)
416 SetLastError(E_INVALIDARG);
417 return NULL;
419 switch (dwMsgType)
421 case CMSG_DATA:
422 msg = CDataEncodeMsg_Open(dwFlags, pvMsgEncodeInfo,
423 pszInnerContentObjID, pStreamInfo);
424 break;
425 case CMSG_HASHED:
426 msg = CHashEncodeMsg_Open(dwFlags, pvMsgEncodeInfo,
427 pszInnerContentObjID, pStreamInfo);
428 break;
429 case CMSG_SIGNED:
430 case CMSG_ENVELOPED:
431 FIXME("unimplemented for type %s\n", MSG_TYPE_STR(dwMsgType));
432 break;
433 case CMSG_SIGNED_AND_ENVELOPED:
434 case CMSG_ENCRYPTED:
435 /* defined but invalid, fall through */
436 default:
437 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
439 return msg;
442 typedef struct _CDecodeMsg
444 CryptMsgBase base;
445 DWORD type;
446 HCRYPTPROV crypt_prov;
447 } CDecodeMsg;
449 static void CDecodeMsg_Close(HCRYPTMSG hCryptMsg)
451 CDecodeMsg *msg = (CDecodeMsg *)hCryptMsg;
453 if (msg->base.open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
454 CryptReleaseContext(msg->crypt_prov, 0);
457 static BOOL CDecodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
458 DWORD cbData, BOOL fFinal)
460 FIXME("(%p, %p, %d, %d): stub\n", hCryptMsg, pbData, cbData, fFinal);
461 return FALSE;
464 static BOOL CDecodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
465 DWORD dwIndex, void *pvData, DWORD *pcbData)
467 CDecodeMsg *msg = (CDecodeMsg *)hCryptMsg;
468 BOOL ret = FALSE;
470 switch (dwParamType)
472 case CMSG_TYPE_PARAM:
473 if (!pvData)
475 *pcbData = sizeof(DWORD);
476 ret = TRUE;
478 else if (*pcbData < sizeof(DWORD))
480 *pcbData = sizeof(DWORD);
481 SetLastError(ERROR_MORE_DATA);
483 else
485 *pcbData = sizeof(DWORD);
486 *(DWORD *)pvData = msg->type;
487 ret = TRUE;
489 break;
490 default:
491 FIXME("unimplemented for parameter %d\n", dwParamType);
492 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
494 return ret;
497 HCRYPTMSG WINAPI CryptMsgOpenToDecode(DWORD dwMsgEncodingType, DWORD dwFlags,
498 DWORD dwMsgType, HCRYPTPROV hCryptProv, PCERT_INFO pRecipientInfo,
499 PCMSG_STREAM_INFO pStreamInfo)
501 CDecodeMsg *msg;
503 TRACE("(%08x, %08x, %08x, %08lx, %p, %p)\n", dwMsgEncodingType,
504 dwFlags, dwMsgType, hCryptProv, pRecipientInfo, pStreamInfo);
506 if (GET_CMSG_ENCODING_TYPE(dwMsgEncodingType) != PKCS_7_ASN_ENCODING)
508 SetLastError(E_INVALIDARG);
509 return NULL;
511 msg = CryptMemAlloc(sizeof(CDecodeMsg));
512 if (msg)
514 CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
515 CDecodeMsg_Close, CDecodeMsg_GetParam, CDecodeMsg_Update);
516 msg->type = dwMsgType;
518 return msg;
521 HCRYPTMSG WINAPI CryptMsgDuplicate(HCRYPTMSG hCryptMsg)
523 TRACE("(%p)\n", hCryptMsg);
525 if (hCryptMsg)
527 CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
529 InterlockedIncrement(&msg->ref);
531 return hCryptMsg;
534 BOOL WINAPI CryptMsgClose(HCRYPTMSG hCryptMsg)
536 TRACE("(%p)\n", hCryptMsg);
538 if (hCryptMsg)
540 CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
542 if (InterlockedDecrement(&msg->ref) == 0)
544 TRACE("freeing %p\n", msg);
545 if (msg->close)
546 msg->close(msg);
547 CryptMemFree(msg);
550 return TRUE;
553 BOOL WINAPI CryptMsgUpdate(HCRYPTMSG hCryptMsg, const BYTE *pbData,
554 DWORD cbData, BOOL fFinal)
556 CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
557 BOOL ret = FALSE;
559 TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal);
560 if (msg && msg->update)
561 ret = msg->update(hCryptMsg, pbData, cbData, fFinal);
562 return ret;
565 BOOL WINAPI CryptMsgGetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
566 DWORD dwIndex, void *pvData, DWORD *pcbData)
568 CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
569 BOOL ret = FALSE;
571 TRACE("(%p, %d, %d, %p, %p)\n", hCryptMsg, dwParamType, dwIndex,
572 pvData, pcbData);
573 if (msg && msg->get_param)
574 ret = msg->get_param(hCryptMsg, dwParamType, dwIndex, pvData, pcbData);
575 return ret;