crypt32: Make a copy of a passed-in stream info rather than assuming the pointer...
[wine.git] / dlls / crypt32 / msg.c
blob7280642652c2da80d25e19eadd734972a8acda5e
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"
23 #include "wine/debug.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
27 /* Called when a message's ref count reaches zero. Free any message-specific
28 * data here.
30 typedef void (*CryptMsgCloseFunc)(HCRYPTMSG msg);
32 typedef BOOL (*CryptMsgGetParamFunc)(HCRYPTMSG hCryptMsg, DWORD dwParamType,
33 DWORD dwIndex, void *pvData, DWORD *pcbData);
35 typedef BOOL (*CryptMsgUpdateFunc)(HCRYPTMSG hCryptMsg, const BYTE *pbData,
36 DWORD cbData, BOOL fFinal);
38 typedef struct _CryptMsgBase
40 LONG ref;
41 DWORD open_flags;
42 BOOL streamed;
43 CMSG_STREAM_INFO stream_info;
44 BOOL finalized;
45 CryptMsgCloseFunc close;
46 CryptMsgUpdateFunc update;
47 CryptMsgGetParamFunc get_param;
48 } CryptMsgBase;
50 static inline void CryptMsgBase_Init(CryptMsgBase *msg, DWORD dwFlags,
51 PCMSG_STREAM_INFO pStreamInfo, CryptMsgCloseFunc close,
52 CryptMsgGetParamFunc get_param, CryptMsgUpdateFunc update)
54 msg->ref = 1;
55 msg->open_flags = dwFlags;
56 if (pStreamInfo)
58 msg->streamed = TRUE;
59 memcpy(&msg->stream_info, pStreamInfo, sizeof(msg->stream_info));
61 else
63 msg->streamed = FALSE;
64 memset(&msg->stream_info, 0, sizeof(msg->stream_info));
66 msg->close = close;
67 msg->get_param = get_param;
68 msg->update = update;
69 msg->finalized = FALSE;
72 typedef struct _CDataEncodeMsg
74 CryptMsgBase base;
75 DWORD bare_content_len;
76 LPBYTE bare_content;
77 } CDataEncodeMsg;
79 static const BYTE empty_data_content[] = { 0x04,0x00 };
81 static void CDataEncodeMsg_Close(HCRYPTMSG hCryptMsg)
83 CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg;
85 if (msg->bare_content != empty_data_content)
86 LocalFree(msg->bare_content);
89 static BOOL CDataEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
90 DWORD cbData, BOOL fFinal)
92 CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg;
93 BOOL ret = FALSE;
95 if (msg->base.finalized)
96 SetLastError(CRYPT_E_MSG_ERROR);
97 else if (!fFinal)
99 if (msg->base.open_flags & CMSG_DETACHED_FLAG)
100 SetLastError(E_INVALIDARG);
101 else
102 SetLastError(CRYPT_E_MSG_ERROR);
104 else
106 msg->base.finalized = TRUE;
107 if (!cbData)
108 SetLastError(E_INVALIDARG);
109 else
111 CRYPT_DATA_BLOB blob = { cbData, (LPBYTE)pbData };
113 /* data messages don't allow non-final updates, don't bother
114 * checking whether data already exist, they can't.
116 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
117 &blob, CRYPT_ENCODE_ALLOC_FLAG, NULL, &msg->bare_content,
118 &msg->bare_content_len);
119 if (ret && msg->base.streamed)
120 FIXME("stream info unimplemented\n");
123 return ret;
126 static BOOL CDataEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
127 DWORD dwIndex, void *pvData, DWORD *pcbData)
129 CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg;
130 BOOL ret = FALSE;
132 switch (dwParamType)
134 case CMSG_CONTENT_PARAM:
136 CRYPT_CONTENT_INFO info;
137 char rsa_data[] = "1.2.840.113549.1.7.1";
139 info.pszObjId = rsa_data;
140 info.Content.cbData = msg->bare_content_len;
141 info.Content.pbData = msg->bare_content;
142 ret = CryptEncodeObject(X509_ASN_ENCODING, PKCS_CONTENT_INFO, &info,
143 pvData, pcbData);
144 break;
146 case CMSG_BARE_CONTENT_PARAM:
147 if (!pvData)
149 *pcbData = msg->bare_content_len;
150 ret = TRUE;
152 else if (*pcbData < msg->bare_content_len)
154 *pcbData = msg->bare_content_len;
155 SetLastError(ERROR_MORE_DATA);
157 else
159 *pcbData = msg->bare_content_len;
160 memcpy(pvData, msg->bare_content, msg->bare_content_len);
161 ret = TRUE;
163 break;
164 default:
165 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
167 return ret;
170 static HCRYPTMSG CDataEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo,
171 LPSTR pszInnerContentObjID, PCMSG_STREAM_INFO pStreamInfo)
173 CDataEncodeMsg *msg;
175 if (pvMsgEncodeInfo)
177 SetLastError(E_INVALIDARG);
178 return NULL;
180 msg = CryptMemAlloc(sizeof(CDataEncodeMsg));
181 if (msg)
183 CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
184 CDataEncodeMsg_Close, CDataEncodeMsg_GetParam, CDataEncodeMsg_Update);
185 msg->bare_content_len = sizeof(empty_data_content);
186 msg->bare_content = (LPBYTE)empty_data_content;
188 return (HCRYPTMSG)msg;
191 static inline const char *MSG_TYPE_STR(DWORD type)
193 switch (type)
195 #define _x(x) case (x): return #x
196 _x(CMSG_DATA);
197 _x(CMSG_SIGNED);
198 _x(CMSG_ENVELOPED);
199 _x(CMSG_SIGNED_AND_ENVELOPED);
200 _x(CMSG_HASHED);
201 _x(CMSG_ENCRYPTED);
202 #undef _x
203 default:
204 return wine_dbg_sprintf("unknown (%d)", type);
208 HCRYPTMSG WINAPI CryptMsgOpenToEncode(DWORD dwMsgEncodingType, DWORD dwFlags,
209 DWORD dwMsgType, const void *pvMsgEncodeInfo, LPSTR pszInnerContentObjID,
210 PCMSG_STREAM_INFO pStreamInfo)
212 HCRYPTMSG msg = NULL;
214 TRACE("(%08x, %08x, %08x, %p, %s, %p)\n", dwMsgEncodingType, dwFlags,
215 dwMsgType, pvMsgEncodeInfo, debugstr_a(pszInnerContentObjID), pStreamInfo);
217 if (GET_CMSG_ENCODING_TYPE(dwMsgEncodingType) != PKCS_7_ASN_ENCODING)
219 SetLastError(E_INVALIDARG);
220 return NULL;
222 switch (dwMsgType)
224 case CMSG_DATA:
225 msg = CDataEncodeMsg_Open(dwFlags, pvMsgEncodeInfo,
226 pszInnerContentObjID, pStreamInfo);
227 break;
228 case CMSG_SIGNED:
229 case CMSG_ENVELOPED:
230 case CMSG_HASHED:
231 FIXME("unimplemented for type %s\n", MSG_TYPE_STR(dwMsgType));
232 break;
233 case CMSG_SIGNED_AND_ENVELOPED:
234 case CMSG_ENCRYPTED:
235 /* defined but invalid, fall through */
236 default:
237 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
239 return msg;
242 HCRYPTMSG WINAPI CryptMsgOpenToDecode(DWORD dwMsgEncodingType, DWORD dwFlags,
243 DWORD dwMsgType, HCRYPTPROV hCryptProv, PCERT_INFO pRecipientInfo,
244 PCMSG_STREAM_INFO pStreamInfo)
246 FIXME("(%08x, %08x, %08x, %08lx, %p, %p): stub\n", dwMsgEncodingType,
247 dwFlags, dwMsgType, hCryptProv, pRecipientInfo, pStreamInfo);
249 if (GET_CMSG_ENCODING_TYPE(dwMsgEncodingType) != PKCS_7_ASN_ENCODING)
251 SetLastError(E_INVALIDARG);
252 return NULL;
254 return NULL;
257 HCRYPTMSG WINAPI CryptMsgDuplicate(HCRYPTMSG hCryptMsg)
259 TRACE("(%p)\n", hCryptMsg);
261 if (hCryptMsg)
263 CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
265 InterlockedIncrement(&msg->ref);
267 return hCryptMsg;
270 BOOL WINAPI CryptMsgClose(HCRYPTMSG hCryptMsg)
272 TRACE("(%p)\n", hCryptMsg);
274 if (hCryptMsg)
276 CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
278 if (InterlockedDecrement(&msg->ref) == 0)
280 TRACE("freeing %p\n", msg);
281 if (msg->close)
282 msg->close(msg);
283 CryptMemFree(msg);
286 return TRUE;
289 BOOL WINAPI CryptMsgUpdate(HCRYPTMSG hCryptMsg, const BYTE *pbData,
290 DWORD cbData, BOOL fFinal)
292 CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
293 BOOL ret = FALSE;
295 TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal);
296 if (msg && msg->update)
297 ret = msg->update(hCryptMsg, pbData, cbData, fFinal);
298 return ret;
301 BOOL WINAPI CryptMsgGetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
302 DWORD dwIndex, void *pvData, DWORD *pcbData)
304 CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
305 BOOL ret = FALSE;
307 TRACE("(%p, %d, %d, %p, %p)\n", hCryptMsg, dwParamType, dwIndex,
308 pvData, pcbData);
309 if (msg && msg->get_param)
310 ret = msg->get_param(hCryptMsg, dwParamType, dwIndex, pvData, pcbData);
311 return ret;