ddraw: Y coords are inversed.
[wine] / dlls / crypt32 / msg.c
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 #include <stdarg.h>
19 #include "windef.h"
20 #include "winbase.h"
21 #include "wincrypt.h"
22
23 #include "wine/debug.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
26
27 /* Called when a message's ref count reaches zero.  Free any message-specific
28  * data here.
29  */
30 typedef void (*CryptMsgCloseFunc)(HCRYPTMSG msg);
31
32 typedef BOOL (*CryptMsgGetParamFunc)(HCRYPTMSG hCryptMsg, DWORD dwParamType,
33  DWORD dwIndex, void *pvData, DWORD *pcbData);
34
35 typedef BOOL (*CryptMsgUpdateFunc)(HCRYPTMSG hCryptMsg, const BYTE *pbData,
36  DWORD cbData, BOOL fFinal);
37
38 typedef struct _CryptMsgBase
39 {
40     LONG                 ref;
41     DWORD                open_flags;
42     PCMSG_STREAM_INFO    stream_info;
43     BOOL                 finalized;
44     CryptMsgCloseFunc    close;
45     CryptMsgUpdateFunc   update;
46     CryptMsgGetParamFunc get_param;
47 } CryptMsgBase;
48
49 static inline void CryptMsgBase_Init(CryptMsgBase *msg, DWORD dwFlags,
50  PCMSG_STREAM_INFO pStreamInfo)
51 {
52     msg->ref = 1;
53     msg->open_flags = dwFlags;
54     msg->stream_info = pStreamInfo;
55     msg->finalized = FALSE;
56 }
57
58 typedef struct _CDataEncodeMsg
59 {
60     CryptMsgBase base;
61     DWORD        bare_content_len;
62     LPBYTE       bare_content;
63 } CDataEncodeMsg;
64
65 static const BYTE empty_data_content[] = { 0x04,0x00 };
66
67 static void CDataEncodeMsg_Close(HCRYPTMSG hCryptMsg)
68 {
69     CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg;
70
71     if (msg->bare_content != empty_data_content)
72         LocalFree(msg->bare_content);
73 }
74
75 static BOOL CDataEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
76  DWORD cbData, BOOL fFinal)
77 {
78     CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg;
79     BOOL ret = FALSE;
80
81     if (msg->base.finalized)
82         SetLastError(CRYPT_E_MSG_ERROR);
83     else if (!fFinal)
84     {
85         if (msg->base.open_flags & CMSG_DETACHED_FLAG)
86             SetLastError(E_INVALIDARG);
87         else
88             SetLastError(CRYPT_E_MSG_ERROR);
89     }
90     else
91     {
92         msg->base.finalized = TRUE;
93         if (!cbData)
94             SetLastError(E_INVALIDARG);
95         else
96         {
97             CRYPT_DATA_BLOB blob = { cbData, (LPBYTE)pbData };
98
99             /* data messages don't allow non-final updates, don't bother
100              * checking whether data already exist, they can't.
101              */
102             ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
103              &blob, CRYPT_ENCODE_ALLOC_FLAG, NULL, &msg->bare_content,
104              &msg->bare_content_len);
105             if (ret && msg->base.stream_info)
106                 FIXME("stream info unimplemented\n");
107         }
108     }
109     return ret;
110 }
111
112 static BOOL CDataEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
113  DWORD dwIndex, void *pvData, DWORD *pcbData)
114 {
115     CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg;
116     BOOL ret = FALSE;
117
118     switch (dwParamType)
119     {
120     case CMSG_CONTENT_PARAM:
121     {
122         CRYPT_CONTENT_INFO info;
123         char rsa_data[] = "1.2.840.113549.1.7.1";
124
125         info.pszObjId = rsa_data;
126         info.Content.cbData = msg->bare_content_len;
127         info.Content.pbData = msg->bare_content;
128         ret = CryptEncodeObject(X509_ASN_ENCODING, PKCS_CONTENT_INFO, &info,
129          pvData, pcbData);
130         break;
131     }
132     case CMSG_BARE_CONTENT_PARAM:
133         if (!pvData)
134         {
135             *pcbData = msg->bare_content_len;
136             ret = TRUE;
137         }
138         else if (*pcbData < msg->bare_content_len)
139         {
140             *pcbData = msg->bare_content_len;
141             SetLastError(ERROR_MORE_DATA);
142         }
143         else
144         {
145             *pcbData = msg->bare_content_len;
146             memcpy(pvData, msg->bare_content, msg->bare_content_len);
147             ret = TRUE;
148         }
149         break;
150     default:
151         SetLastError(CRYPT_E_INVALID_MSG_TYPE);
152     }
153     return ret;
154 }
155
156 static HCRYPTMSG CDataEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo,
157  LPSTR pszInnerContentObjID, PCMSG_STREAM_INFO pStreamInfo)
158 {
159     CDataEncodeMsg *msg;
160
161     if (pvMsgEncodeInfo)
162     {
163         SetLastError(E_INVALIDARG);
164         return NULL;
165     }
166     msg = CryptMemAlloc(sizeof(CDataEncodeMsg));
167     if (msg)
168     {
169         CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo);
170         msg->base.close = CDataEncodeMsg_Close;
171         msg->base.update = CDataEncodeMsg_Update;
172         msg->base.get_param = CDataEncodeMsg_GetParam;
173         msg->bare_content_len = sizeof(empty_data_content);
174         msg->bare_content = (LPBYTE)empty_data_content;
175     }
176     return (HCRYPTMSG)msg;
177 }
178
179 static inline const char *MSG_TYPE_STR(DWORD type)
180 {
181     switch (type)
182     {
183 #define _x(x) case (x): return #x
184         _x(CMSG_DATA);
185         _x(CMSG_SIGNED);
186         _x(CMSG_ENVELOPED);
187         _x(CMSG_SIGNED_AND_ENVELOPED);
188         _x(CMSG_HASHED);
189         _x(CMSG_ENCRYPTED);
190 #undef _x
191         default:
192             return wine_dbg_sprintf("unknown (%d)", type);
193     }
194 }
195
196 HCRYPTMSG WINAPI CryptMsgOpenToEncode(DWORD dwMsgEncodingType, DWORD dwFlags,
197  DWORD dwMsgType, const void *pvMsgEncodeInfo, LPSTR pszInnerContentObjID,
198  PCMSG_STREAM_INFO pStreamInfo)
199 {
200     HCRYPTMSG msg = NULL;
201
202     TRACE("(%08x, %08x, %08x, %p, %s, %p)\n", dwMsgEncodingType, dwFlags,
203      dwMsgType, pvMsgEncodeInfo, debugstr_a(pszInnerContentObjID), pStreamInfo);
204
205     if (GET_CMSG_ENCODING_TYPE(dwMsgEncodingType) != PKCS_7_ASN_ENCODING)
206     {
207         SetLastError(E_INVALIDARG);
208         return NULL;
209     }
210     switch (dwMsgType)
211     {
212     case CMSG_DATA:
213         msg = CDataEncodeMsg_Open(dwFlags, pvMsgEncodeInfo,
214          pszInnerContentObjID, pStreamInfo);
215         break;
216     case CMSG_SIGNED:
217     case CMSG_ENVELOPED:
218     case CMSG_HASHED:
219         FIXME("unimplemented for type %s\n", MSG_TYPE_STR(dwMsgType));
220         break;
221     case CMSG_SIGNED_AND_ENVELOPED:
222     case CMSG_ENCRYPTED:
223         /* defined but invalid, fall through */
224     default:
225         SetLastError(CRYPT_E_INVALID_MSG_TYPE);
226     }
227     return msg;
228 }
229
230 HCRYPTMSG WINAPI CryptMsgOpenToDecode(DWORD dwMsgEncodingType, DWORD dwFlags,
231  DWORD dwMsgType, HCRYPTPROV hCryptProv, PCERT_INFO pRecipientInfo,
232  PCMSG_STREAM_INFO pStreamInfo)
233 {
234     FIXME("(%08x, %08x, %08x, %08lx, %p, %p): stub\n", dwMsgEncodingType,
235      dwFlags, dwMsgType, hCryptProv, pRecipientInfo, pStreamInfo);
236
237     if (GET_CMSG_ENCODING_TYPE(dwMsgEncodingType) != PKCS_7_ASN_ENCODING)
238     {
239         SetLastError(E_INVALIDARG);
240         return NULL;
241     }
242     return NULL;
243 }
244
245 HCRYPTMSG WINAPI CryptMsgDuplicate(HCRYPTMSG hCryptMsg)
246 {
247     TRACE("(%p)\n", hCryptMsg);
248
249     if (hCryptMsg)
250     {
251         CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
252
253         InterlockedIncrement(&msg->ref);
254     }
255     return hCryptMsg;
256 }
257
258 BOOL WINAPI CryptMsgClose(HCRYPTMSG hCryptMsg)
259 {
260     TRACE("(%p)\n", hCryptMsg);
261
262     if (hCryptMsg)
263     {
264         CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
265
266         if (InterlockedDecrement(&msg->ref) == 0)
267         {
268             TRACE("freeing %p\n", msg);
269             if (msg->close)
270                 msg->close(msg);
271             CryptMemFree(msg);
272         }
273     }
274     return TRUE;
275 }
276
277 BOOL WINAPI CryptMsgUpdate(HCRYPTMSG hCryptMsg, const BYTE *pbData,
278  DWORD cbData, BOOL fFinal)
279 {
280     CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
281     BOOL ret = FALSE;
282
283     TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal);
284     if (msg && msg->update)
285         ret = msg->update(hCryptMsg, pbData, cbData, fFinal);
286     return ret;
287 }
288
289 BOOL WINAPI CryptMsgGetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
290  DWORD dwIndex, void *pvData, DWORD *pcbData)
291 {
292     CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
293     BOOL ret = FALSE;
294
295     TRACE("(%p, %d, %d, %p, %p)\n", hCryptMsg, dwParamType, dwIndex,
296      pvData, pcbData);
297     if (msg && msg->get_param)
298         ret = msg->get_param(hCryptMsg, dwParamType, dwIndex, pvData, pcbData);
299     return ret;
300 }