crypt32: Fix CryptFreeTls when calling with a freed index.
[wine] / dlls / crypt32 / base64.c
1 /*
2  * base64 encoder/decoder
3  *
4  * Copyright 2005 by Kai Blin
5  * Copyright 2006 Juan Lang
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winerror.h"
26 #include "wincrypt.h"
27 #include "wine/debug.h"
28 #include "wine/unicode.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
31
32 #define CERT_HEADER          "-----BEGIN CERTIFICATE-----"
33 #define CERT_TRAILER         "-----END CERTIFICATE-----"
34 #define CERT_REQUEST_HEADER  "-----BEGIN NEW CERTIFICATE REQUEST-----"
35 #define CERT_REQUEST_TRAILER "-----END NEW CERTIFICATE REQUEST-----"
36 #define X509_HEADER          "-----BEGIN X509 CRL-----"
37 #define X509_TRAILER         "-----END X509 CRL-----"
38
39 static const WCHAR CERT_HEADER_W[] = {
40 '-','-','-','-','-','B','E','G','I','N',' ','C','E','R','T','I','F','I','C',
41 'A','T','E','-','-','-','-','-',0 };
42 static const WCHAR CERT_TRAILER_W[] = {
43 '-','-','-','-','-','E','N','D',' ','C','E','R','T','I','F','I','C','A','T',
44 'E','-','-','-','-','-',0 };
45 static const WCHAR CERT_REQUEST_HEADER_W[] = {
46 '-','-','-','-','-','B','E','G','I','N',' ','N','E','W',' ','C','E','R','T',
47 'I','F','I','C','A','T','E','R','E','Q','U','E','S','T','-','-','-','-','-',0 };
48 static const WCHAR CERT_REQUEST_TRAILER_W[] = {
49 '-','-','-','-','-','E','N','D',' ','N','E','W',' ','C','E','R','T','I','F',
50 'I','C','A','T','E','R','E','Q','U','E','S','T','-','-','-','-','-',0 };
51 static const WCHAR X509_HEADER_W[] = {
52 '-','-','-','-','-','B','E','G','I','N',' ','X','5','0','9',' ','C','R','L',
53 '-','-','-','-','-',0 };
54 static const WCHAR X509_TRAILER_W[] = {
55 '-','-','-','-','-','E','N','D',' ','X','5','0','9',' ','C','R','L','-','-',
56 '-','-','-',0 };
57
58 static const char b64[] =
59 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
60
61 typedef BOOL (*BinaryToStringAFunc)(const BYTE *pbBinary,
62  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString);
63 typedef BOOL (*BinaryToStringWFunc)(const BYTE *pbBinary,
64  DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString);
65
66 static BOOL EncodeBinaryToBinaryA(const BYTE *pbBinary,
67  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
68 {
69     BOOL ret = TRUE;
70
71     if (*pcchString < cbBinary)
72     {
73         if (!pszString)
74             *pcchString = cbBinary;
75         else
76         {
77             SetLastError(ERROR_INSUFFICIENT_BUFFER);
78             *pcchString = cbBinary;
79             ret = FALSE;
80         }
81     }
82     else
83     {
84         if (cbBinary)
85             memcpy(pszString, pbBinary, cbBinary);
86         *pcchString = cbBinary;
87     }
88     return ret;
89 }
90
91 static LONG encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep,
92  char* out_buf, DWORD *out_len)
93 {
94     int div, i;
95     const BYTE *d = in_buf;
96     int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
97     DWORD needed;
98     LPSTR ptr;
99
100     TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
101     needed = bytes + pad_bytes + 1;
102     if (sep)
103         needed += (needed / 64 + 1) * strlen(sep);
104
105     if (needed > *out_len)
106     {
107         *out_len = needed;
108         return ERROR_INSUFFICIENT_BUFFER;
109     }
110     else
111         *out_len = needed;
112
113     /* Three bytes of input give 4 chars of output */
114     div = in_len / 3;
115
116     ptr = out_buf;
117     i = 0;
118     while (div > 0)
119     {
120         if (sep && i && i % 64 == 0)
121         {
122             strcpy(ptr, sep);
123             ptr += strlen(sep);
124         }
125         /* first char is the first 6 bits of the first byte*/
126         *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
127         /* second char is the last 2 bits of the first byte and the first 4
128          * bits of the second byte */
129         *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
130         /* third char is the last 4 bits of the second byte and the first 2
131          * bits of the third byte */
132         *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
133         /* fourth char is the remaining 6 bits of the third byte */
134         *ptr++ = b64[   d[2]       & 0x3f];
135         i += 4;
136         d += 3;
137         div--;
138     }
139
140     switch(pad_bytes)
141     {
142         case 1:
143             /* first char is the first 6 bits of the first byte*/
144             *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
145             /* second char is the last 2 bits of the first byte and the first 4
146              * bits of the second byte */
147             *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
148             /* third char is the last 4 bits of the second byte padded with
149              * two zeroes */
150             *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
151             /* fourth char is a = to indicate one byte of padding */
152             *ptr++ = '=';
153             break;
154         case 2:
155             /* first char is the first 6 bits of the first byte*/
156             *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
157             /* second char is the last 2 bits of the first byte padded with
158              * four zeroes*/
159             *ptr++ = b64[ ((d[0] << 4) & 0x30)];
160             /* third char is = to indicate padding */
161             *ptr++ = '=';
162             /* fourth char is = to indicate padding */
163             *ptr++ = '=';
164             break;
165     }
166     if (sep)
167         strcpy(ptr, sep);
168
169     return ERROR_SUCCESS;
170 }
171
172 static BOOL BinaryToBase64A(const BYTE *pbBinary,
173  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
174 {
175     static const char crlf[] = "\r\n", lf[] = "\n";
176     BOOL ret = TRUE;
177     LPCSTR header = NULL, trailer = NULL, sep;
178     DWORD charsNeeded;
179
180     if (dwFlags & CRYPT_STRING_NOCR)
181         sep = lf;
182     else if (dwFlags & CRYPT_STRING_NOCRLF)
183         sep = NULL;
184     else
185         sep = crlf;
186     switch (dwFlags & 0x0fffffff)
187     {
188     case CRYPT_STRING_BASE64:
189         /* no header or footer */
190         break;
191     case CRYPT_STRING_BASE64HEADER:
192         header = CERT_HEADER;
193         trailer = CERT_TRAILER;
194         break;
195     case CRYPT_STRING_BASE64REQUESTHEADER:
196         header = CERT_REQUEST_HEADER;
197         trailer = CERT_REQUEST_TRAILER;
198         break;
199     case CRYPT_STRING_BASE64X509CRLHEADER:
200         header = X509_HEADER;
201         trailer = X509_TRAILER;
202         break;
203     }
204
205     charsNeeded = 0;
206     encodeBase64A(pbBinary, cbBinary, sep, NULL, &charsNeeded);
207     if (sep)
208         charsNeeded += strlen(sep);
209     if (header)
210         charsNeeded += strlen(header) + strlen(sep);
211     if (trailer)
212         charsNeeded += strlen(trailer) + strlen(sep);
213     if (charsNeeded <= *pcchString)
214     {
215         LPSTR ptr = pszString;
216         DWORD size = charsNeeded;
217
218         if (header)
219         {
220             strcpy(ptr, header);
221             ptr += strlen(ptr);
222             if (sep)
223             {
224                 strcpy(ptr, sep);
225                 ptr += strlen(sep);
226             }
227         }
228         encodeBase64A(pbBinary, cbBinary, sep, ptr, &size);
229         ptr += size - 1;
230         if (trailer)
231         {
232             strcpy(ptr, trailer);
233             ptr += strlen(ptr);
234             if (sep)
235             {
236                 strcpy(ptr, sep);
237                 ptr += strlen(sep);
238             }
239         }
240         *pcchString = charsNeeded - 1;
241     }
242     else if (pszString)
243     {
244         *pcchString = charsNeeded;
245         SetLastError(ERROR_INSUFFICIENT_BUFFER);
246         ret = FALSE;
247     }
248     else
249         *pcchString = charsNeeded;
250     return ret;
251 }
252
253 BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary,
254  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
255 {
256     BinaryToStringAFunc encoder = NULL;
257
258     TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
259      pcchString);
260
261     if (!pbBinary)
262     {
263         SetLastError(ERROR_INVALID_PARAMETER);
264         return FALSE;
265     }
266     if (!pcchString)
267     {
268         SetLastError(ERROR_INVALID_PARAMETER);
269         return FALSE;
270     }
271
272     switch (dwFlags & 0x0fffffff)
273     {
274     case CRYPT_STRING_BINARY:
275         encoder = EncodeBinaryToBinaryA;
276         break;
277     case CRYPT_STRING_BASE64:
278     case CRYPT_STRING_BASE64HEADER:
279     case CRYPT_STRING_BASE64REQUESTHEADER:
280     case CRYPT_STRING_BASE64X509CRLHEADER:
281         encoder = BinaryToBase64A;
282         break;
283     case CRYPT_STRING_HEX:
284     case CRYPT_STRING_HEXASCII:
285     case CRYPT_STRING_HEXADDR:
286     case CRYPT_STRING_HEXASCIIADDR:
287         FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
288         /* fall through */
289     default:
290         SetLastError(ERROR_INVALID_PARAMETER);
291         return FALSE;
292     }
293     return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
294 }
295
296 static LONG encodeBase64W(const BYTE *in_buf, int in_len, LPCWSTR sep,
297  WCHAR* out_buf, DWORD *out_len)
298 {
299     int div, i;
300     const BYTE *d = in_buf;
301     int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
302     DWORD needed;
303     LPWSTR ptr;
304
305     TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
306     needed = bytes + pad_bytes + 1;
307     if (sep)
308         needed += (needed / 64 + 1) * strlenW(sep);
309
310     if (needed > *out_len)
311     {
312         *out_len = needed;
313         return ERROR_INSUFFICIENT_BUFFER;
314     }
315     else
316         *out_len = needed;
317
318     /* Three bytes of input give 4 chars of output */
319     div = in_len / 3;
320
321     ptr = out_buf;
322     i = 0;
323     while (div > 0)
324     {
325         if (sep && i && i % 64 == 0)
326         {
327             strcpyW(ptr, sep);
328             ptr += strlenW(sep);
329         }
330         /* first char is the first 6 bits of the first byte*/
331         *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
332         /* second char is the last 2 bits of the first byte and the first 4
333          * bits of the second byte */
334         *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
335         /* third char is the last 4 bits of the second byte and the first 2
336          * bits of the third byte */
337         *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
338         /* fourth char is the remaining 6 bits of the third byte */
339         *ptr++ = b64[   d[2]       & 0x3f];
340         i += 4;
341         d += 3;
342         div--;
343     }
344
345     switch(pad_bytes)
346     {
347         case 1:
348             /* first char is the first 6 bits of the first byte*/
349             *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
350             /* second char is the last 2 bits of the first byte and the first 4
351              * bits of the second byte */
352             *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
353             /* third char is the last 4 bits of the second byte padded with
354              * two zeroes */
355             *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
356             /* fourth char is a = to indicate one byte of padding */
357             *ptr++ = '=';
358             break;
359         case 2:
360             /* first char is the first 6 bits of the first byte*/
361             *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
362             /* second char is the last 2 bits of the first byte padded with
363              * four zeroes*/
364             *ptr++ = b64[ ((d[0] << 4) & 0x30)];
365             /* third char is = to indicate padding */
366             *ptr++ = '=';
367             /* fourth char is = to indicate padding */
368             *ptr++ = '=';
369             break;
370     }
371     if (sep)
372         strcpyW(ptr, sep);
373
374     return ERROR_SUCCESS;
375 }
376
377 static BOOL BinaryToBase64W(const BYTE *pbBinary,
378  DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
379 {
380     static const WCHAR crlf[] = { '\r','\n',0 }, lf[] = { '\n',0 };
381     BOOL ret = TRUE;
382     LPCWSTR header = NULL, trailer = NULL, sep;
383     DWORD charsNeeded;
384
385     if (dwFlags & CRYPT_STRING_NOCR)
386         sep = lf;
387     else if (dwFlags & CRYPT_STRING_NOCRLF)
388         sep = NULL;
389     else
390         sep = crlf;
391     switch (dwFlags & 0x0fffffff)
392     {
393     case CRYPT_STRING_BASE64:
394         /* no header or footer */
395         break;
396     case CRYPT_STRING_BASE64HEADER:
397         header = CERT_HEADER_W;
398         trailer = CERT_TRAILER_W;
399         break;
400     case CRYPT_STRING_BASE64REQUESTHEADER:
401         header = CERT_REQUEST_HEADER_W;
402         trailer = CERT_REQUEST_TRAILER_W;
403         break;
404     case CRYPT_STRING_BASE64X509CRLHEADER:
405         header = X509_HEADER_W;
406         trailer = X509_TRAILER_W;
407         break;
408     }
409
410     charsNeeded = 0;
411     encodeBase64W(pbBinary, cbBinary, sep, NULL, &charsNeeded);
412     if (sep)
413         charsNeeded += strlenW(sep);
414     if (header)
415         charsNeeded += strlenW(header) + strlenW(sep);
416     if (trailer)
417         charsNeeded += strlenW(trailer) + strlenW(sep);
418     if (charsNeeded <= *pcchString)
419     {
420         LPWSTR ptr = pszString;
421         DWORD size = charsNeeded;
422
423         if (header)
424         {
425             strcpyW(ptr, header);
426             ptr += strlenW(ptr);
427             if (sep)
428             {
429                 strcpyW(ptr, sep);
430                 ptr += strlenW(sep);
431             }
432         }
433         encodeBase64W(pbBinary, cbBinary, sep, ptr, &size);
434         ptr += size - 1;
435         if (trailer)
436         {
437             strcpyW(ptr, trailer);
438             ptr += strlenW(ptr);
439             if (sep)
440             {
441                 strcpyW(ptr, sep);
442                 ptr += strlenW(sep);
443             }
444         }
445         *pcchString = charsNeeded - 1;
446     }
447     else if (pszString)
448     {
449         *pcchString = charsNeeded;
450         SetLastError(ERROR_INSUFFICIENT_BUFFER);
451         ret = FALSE;
452     }
453     else
454         *pcchString = charsNeeded;
455     return ret;
456 }
457
458 BOOL WINAPI CryptBinaryToStringW(const BYTE *pbBinary,
459  DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
460 {
461     BinaryToStringWFunc encoder = NULL;
462
463     TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
464      pcchString);
465
466     if (!pbBinary)
467     {
468         SetLastError(ERROR_INVALID_PARAMETER);
469         return FALSE;
470     }
471     if (!pcchString)
472     {
473         SetLastError(ERROR_INVALID_PARAMETER);
474         return FALSE;
475     }
476
477     switch (dwFlags & 0x0fffffff)
478     {
479     case CRYPT_STRING_BASE64:
480     case CRYPT_STRING_BASE64HEADER:
481     case CRYPT_STRING_BASE64REQUESTHEADER:
482     case CRYPT_STRING_BASE64X509CRLHEADER:
483         encoder = BinaryToBase64W;
484         break;
485     case CRYPT_STRING_BINARY:
486     case CRYPT_STRING_HEX:
487     case CRYPT_STRING_HEXASCII:
488     case CRYPT_STRING_HEXADDR:
489     case CRYPT_STRING_HEXASCIIADDR:
490         FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
491         /* fall through */
492     default:
493         SetLastError(ERROR_INVALID_PARAMETER);
494         return FALSE;
495     }
496     return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
497 }
498
499 static inline BYTE decodeBase64Byte(int c)
500 {
501     BYTE ret;
502
503     if (c >= 'A' && c <= 'Z')
504         ret = c - 'A';
505     else if (c >= 'a' && c <= 'z')
506         ret = c - 'a' + 26;
507     else if (c >= '0' && c <= '9')
508         ret = c - '0' + 52;
509     else if (c == '+')
510         ret = 62;
511     else if (c == '/')
512         ret = 63;
513     else
514         ret = 64;
515     return ret;
516 }
517
518 static LONG decodeBase64Block(const char *in_buf, int in_len,
519  const char **nextBlock, PBYTE out_buf, DWORD *out_len)
520 {
521     int len = in_len, i;
522     const char *d = in_buf;
523     int  ip0, ip1, ip2, ip3;
524
525     if (len < 4)
526         return ERROR_INVALID_DATA;
527
528     i = 0;
529     if (d[2] == '=')
530     {
531         if ((ip0 = decodeBase64Byte(d[0])) > 63)
532             return ERROR_INVALID_DATA;
533         if ((ip1 = decodeBase64Byte(d[1])) > 63)
534             return ERROR_INVALID_DATA;
535
536         if (out_buf)
537             out_buf[i] = (ip0 << 2) | (ip1 >> 4);
538         i++;
539     }
540     else if (d[3] == '=')
541     {
542         if ((ip0 = decodeBase64Byte(d[0])) > 63)
543             return ERROR_INVALID_DATA;
544         if ((ip1 = decodeBase64Byte(d[1])) > 63)
545             return ERROR_INVALID_DATA;
546         if ((ip2 = decodeBase64Byte(d[2])) > 63)
547             return ERROR_INVALID_DATA;
548
549         if (out_buf)
550         {
551             out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
552             out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
553         }
554         i += 2;
555     }
556     else
557     {
558         if ((ip0 = decodeBase64Byte(d[0])) > 63)
559             return ERROR_INVALID_DATA;
560         if ((ip1 = decodeBase64Byte(d[1])) > 63)
561             return ERROR_INVALID_DATA;
562         if ((ip2 = decodeBase64Byte(d[2])) > 63)
563             return ERROR_INVALID_DATA;
564         if ((ip3 = decodeBase64Byte(d[3])) > 63)
565             return ERROR_INVALID_DATA;
566
567         if (out_buf)
568         {
569             out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
570             out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
571             out_buf[i + 2] = (ip2 << 6) |  ip3;
572         }
573         i += 3;
574     }
575     if (len >= 6 && d[4] == '\r' && d[5] == '\n')
576         *nextBlock = d + 6;
577     else if (len >= 5 && d[4] == '\n')
578         *nextBlock = d + 5;
579     else if (len >= 4 && d[4])
580         *nextBlock = d + 4;
581     else
582         *nextBlock = NULL;
583     *out_len = i;
584     return ERROR_SUCCESS;
585 }
586
587 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
588  * string to convert.
589  */
590 typedef LONG (*StringToBinaryAFunc)(LPCSTR pszString, DWORD cchString,
591  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
592
593 static LONG Base64ToBinaryA(LPCSTR pszString, DWORD cchString,
594  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
595 {
596     LONG ret = ERROR_SUCCESS;
597     const char *nextBlock;
598     DWORD outLen = 0;
599
600     nextBlock = pszString;
601     while (nextBlock && !ret)
602     {
603         DWORD len = 0;
604
605         ret = decodeBase64Block(nextBlock, cchString - (nextBlock - pszString),
606          &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
607         if (!ret)
608             outLen += len;
609         if (cchString - (nextBlock - pszString) <= 0)
610             nextBlock = NULL;
611     }
612     *pcbBinary = outLen;
613     if (!ret)
614     {
615         if (pdwSkip)
616             *pdwSkip = 0;
617         if (pdwFlags)
618             *pdwFlags = CRYPT_STRING_BASE64;
619     }
620     else if (ret == ERROR_INSUFFICIENT_BUFFER)
621     {
622         if (!pbBinary)
623             ret = ERROR_SUCCESS;
624     }
625     return ret;
626 }
627
628 static LONG Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString,
629  DWORD cchString, LPCSTR header, LPCSTR trailer, BYTE *pbBinary,
630  DWORD *pcbBinary, DWORD *pdwSkip)
631 {
632     LONG ret;
633     LPCSTR ptr;
634
635     if (cchString > strlen(header) + strlen(trailer)
636      && (ptr = strstr(pszString, header)) != NULL)
637     {
638         LPCSTR trailerSpot = pszString + cchString - strlen(trailer);
639
640         if (pszString[cchString - 1] == '\n')
641         {
642             cchString--;
643             trailerSpot--;
644         }
645         if (pszString[cchString - 1] == '\r')
646         {
647             cchString--;
648             trailerSpot--;
649         }
650         if (!strncmp(trailerSpot, trailer, strlen(trailer)))
651         {
652             if (pdwSkip)
653                 *pdwSkip = ptr - pszString;
654             ptr += strlen(header);
655             if (*ptr == '\r') ptr++;
656             if (*ptr == '\n') ptr++;
657             cchString -= ptr - pszString + strlen(trailer);
658             ret = Base64ToBinaryA(ptr, cchString, pbBinary, pcbBinary, NULL,
659              NULL);
660         }
661         else
662             ret = ERROR_INVALID_DATA;
663     }
664     else
665         ret = ERROR_INVALID_DATA;
666     return ret;
667 }
668
669 static LONG Base64HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
670  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
671 {
672     LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
673      CERT_HEADER, CERT_TRAILER, pbBinary, pcbBinary, pdwSkip);
674
675     if (!ret && pdwFlags)
676         *pdwFlags = CRYPT_STRING_BASE64HEADER;
677     return ret;
678 }
679
680 static LONG Base64RequestHeaderToBinaryA(LPCSTR pszString, DWORD cchString,
681  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
682 {
683     LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
684      CERT_REQUEST_HEADER, CERT_REQUEST_TRAILER, pbBinary, pcbBinary, pdwSkip);
685
686     if (!ret && pdwFlags)
687         *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
688     return ret;
689 }
690
691 static LONG Base64X509HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
692  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
693 {
694     LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
695      X509_HEADER, X509_TRAILER, pbBinary, pcbBinary, pdwSkip);
696
697     if (!ret && pdwFlags)
698         *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
699     return ret;
700 }
701
702 static LONG Base64AnyToBinaryA(LPCSTR pszString, DWORD cchString,
703  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
704 {
705     LONG ret;
706
707     ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
708      pdwSkip, pdwFlags);
709     if (ret == ERROR_INVALID_DATA)
710         ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
711          pdwSkip, pdwFlags);
712     return ret;
713 }
714
715 static LONG DecodeBinaryToBinaryA(LPCSTR pszString, DWORD cchString,
716  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
717 {
718     LONG ret = ERROR_SUCCESS;
719
720     if (*pcbBinary < cchString)
721     {
722         if (!pbBinary)
723             *pcbBinary = cchString;
724         else
725         {
726             ret = ERROR_INSUFFICIENT_BUFFER;
727             *pcbBinary = cchString;
728         }
729     }
730     else
731     {
732         if (cchString)
733             memcpy(pbBinary, pszString, cchString);
734         *pcbBinary = cchString;
735     }
736     return ret;
737 }
738
739 static LONG DecodeAnyA(LPCSTR pszString, DWORD cchString,
740  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
741 {
742     LONG ret;
743
744     ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
745      pdwSkip, pdwFlags);
746     if (ret == ERROR_INVALID_DATA)
747         ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
748          pdwSkip, pdwFlags);
749     if (ret == ERROR_INVALID_DATA)
750         ret = DecodeBinaryToBinaryA(pszString, cchString, pbBinary, pcbBinary,
751          pdwSkip, pdwFlags);
752     return ret;
753 }
754
755 BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString,
756  DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
757  DWORD *pdwSkip, DWORD *pdwFlags)
758 {
759     StringToBinaryAFunc decoder;
760     LONG ret;
761
762     TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_a(pszString),
763      cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
764
765     if (!pszString)
766     {
767         SetLastError(ERROR_INVALID_PARAMETER);
768         return FALSE;
769     }
770     /* Only the bottom byte contains valid types */
771     if (dwFlags & 0xfffffff0)
772     {
773         SetLastError(ERROR_INVALID_DATA);
774         return FALSE;
775     }
776     switch (dwFlags)
777     {
778     case CRYPT_STRING_BASE64_ANY:
779         decoder = Base64AnyToBinaryA;
780         break;
781     case CRYPT_STRING_BASE64:
782         decoder = Base64ToBinaryA;
783         break;
784     case CRYPT_STRING_BASE64HEADER:
785         decoder = Base64HeaderToBinaryA;
786         break;
787     case CRYPT_STRING_BASE64REQUESTHEADER:
788         decoder = Base64RequestHeaderToBinaryA;
789         break;
790     case CRYPT_STRING_BASE64X509CRLHEADER:
791         decoder = Base64X509HeaderToBinaryA;
792         break;
793     case CRYPT_STRING_BINARY:
794         decoder = DecodeBinaryToBinaryA;
795         break;
796     case CRYPT_STRING_ANY:
797         decoder = DecodeAnyA;
798         break;
799     case CRYPT_STRING_HEX:
800     case CRYPT_STRING_HEXASCII:
801     case CRYPT_STRING_HEXADDR:
802     case CRYPT_STRING_HEXASCIIADDR:
803         FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
804         /* fall through */
805     default:
806         SetLastError(ERROR_INVALID_PARAMETER);
807         return FALSE;
808     }
809     if (!cchString)
810         cchString = strlen(pszString);
811     ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
812     if (ret)
813         SetLastError(ret);
814     return (ret == ERROR_SUCCESS) ? TRUE : FALSE;
815 }
816
817 static LONG decodeBase64BlockW(const WCHAR *in_buf, int in_len,
818  const WCHAR **nextBlock, PBYTE out_buf, DWORD *out_len)
819 {
820     int len = in_len, i;
821     const WCHAR *d = in_buf;
822     int  ip0, ip1, ip2, ip3;
823
824     if (len < 4)
825         return ERROR_INVALID_DATA;
826
827     i = 0;
828     if (d[2] == '=')
829     {
830         if ((ip0 = decodeBase64Byte(d[0])) > 63)
831             return ERROR_INVALID_DATA;
832         if ((ip1 = decodeBase64Byte(d[1])) > 63)
833             return ERROR_INVALID_DATA;
834
835         if (out_buf)
836             out_buf[i] = (ip0 << 2) | (ip1 >> 4);
837         i++;
838     }
839     else if (d[3] == '=')
840     {
841         if ((ip0 = decodeBase64Byte(d[0])) > 63)
842             return ERROR_INVALID_DATA;
843         if ((ip1 = decodeBase64Byte(d[1])) > 63)
844             return ERROR_INVALID_DATA;
845         if ((ip2 = decodeBase64Byte(d[2])) > 63)
846             return ERROR_INVALID_DATA;
847
848         if (out_buf)
849         {
850             out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
851             out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
852         }
853         i += 2;
854     }
855     else
856     {
857         if ((ip0 = decodeBase64Byte(d[0])) > 63)
858             return ERROR_INVALID_DATA;
859         if ((ip1 = decodeBase64Byte(d[1])) > 63)
860             return ERROR_INVALID_DATA;
861         if ((ip2 = decodeBase64Byte(d[2])) > 63)
862             return ERROR_INVALID_DATA;
863         if ((ip3 = decodeBase64Byte(d[3])) > 63)
864             return ERROR_INVALID_DATA;
865
866         if (out_buf)
867         {
868             out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
869             out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
870             out_buf[i + 2] = (ip2 << 6) |  ip3;
871         }
872         i += 3;
873     }
874     if (len >= 6 && d[4] == '\r' && d[5] == '\n')
875         *nextBlock = d + 6;
876     else if (len >= 5 && d[4] == '\n')
877         *nextBlock = d + 5;
878     else if (len >= 4 && d[4])
879         *nextBlock = d + 4;
880     else
881         *nextBlock = NULL;
882     *out_len = i;
883     return ERROR_SUCCESS;
884 }
885
886 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
887  * string to convert.
888  */
889 typedef LONG (*StringToBinaryWFunc)(LPCWSTR pszString, DWORD cchString,
890  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
891
892 static LONG Base64ToBinaryW(LPCWSTR pszString, DWORD cchString,
893  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
894 {
895     LONG ret = ERROR_SUCCESS;
896     const WCHAR *nextBlock;
897     DWORD outLen = 0;
898
899     nextBlock = pszString;
900     while (nextBlock && !ret)
901     {
902         DWORD len = 0;
903
904         ret = decodeBase64BlockW(nextBlock, cchString - (nextBlock - pszString),
905          &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
906         if (!ret)
907             outLen += len;
908         if (cchString - (nextBlock - pszString) <= 0)
909             nextBlock = NULL;
910     }
911     *pcbBinary = outLen;
912     if (!ret)
913     {
914         if (pdwSkip)
915             *pdwSkip = 0;
916         if (pdwFlags)
917             *pdwFlags = CRYPT_STRING_BASE64;
918     }
919     else if (ret == ERROR_INSUFFICIENT_BUFFER)
920     {
921         if (!pbBinary)
922             ret = ERROR_SUCCESS;
923     }
924     return ret;
925 }
926
927 static LONG Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString,
928  DWORD cchString, LPCWSTR header, LPCWSTR trailer, BYTE *pbBinary,
929  DWORD *pcbBinary, DWORD *pdwSkip)
930 {
931     LONG ret;
932     LPCWSTR ptr;
933
934     if (cchString > strlenW(header) + strlenW(trailer)
935      && (ptr = strstrW(pszString, header)) != NULL)
936     {
937         LPCWSTR trailerSpot = pszString + cchString - strlenW(trailer);
938
939         if (pszString[cchString - 1] == '\n')
940         {
941             cchString--;
942             trailerSpot--;
943         }
944         if (pszString[cchString - 1] == '\r')
945         {
946             cchString--;
947             trailerSpot--;
948         }
949         if (!strncmpW(trailerSpot, trailer, strlenW(trailer)))
950         {
951             if (pdwSkip)
952                 *pdwSkip = ptr - pszString;
953             ptr += strlenW(header);
954             if (*ptr == '\r') ptr++;
955             if (*ptr == '\n') ptr++;
956             cchString -= ptr - pszString + strlenW(trailer);
957             ret = Base64ToBinaryW(ptr, cchString, pbBinary, pcbBinary, NULL,
958              NULL);
959         }
960         else
961             ret = ERROR_INVALID_DATA;
962     }
963     else
964         ret = ERROR_INVALID_DATA;
965     return ret;
966 }
967
968 static LONG Base64HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
969  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
970 {
971     LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
972      CERT_HEADER_W, CERT_TRAILER_W, pbBinary, pcbBinary, pdwSkip);
973
974     if (!ret && pdwFlags)
975         *pdwFlags = CRYPT_STRING_BASE64HEADER;
976     return ret;
977 }
978
979 static LONG Base64RequestHeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
980  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
981 {
982     LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
983      CERT_REQUEST_HEADER_W, CERT_REQUEST_TRAILER_W, pbBinary, pcbBinary,
984      pdwSkip);
985
986     if (!ret && pdwFlags)
987         *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
988     return ret;
989 }
990
991 static LONG Base64X509HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
992  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
993 {
994     LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
995      X509_HEADER_W, X509_TRAILER_W, pbBinary, pcbBinary, pdwSkip);
996
997     if (!ret && pdwFlags)
998         *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
999     return ret;
1000 }
1001
1002 static LONG Base64AnyToBinaryW(LPCWSTR pszString, DWORD cchString,
1003  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1004 {
1005     LONG ret;
1006
1007     ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1008      pdwSkip, pdwFlags);
1009     if (ret == ERROR_INVALID_DATA)
1010         ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1011          pdwSkip, pdwFlags);
1012     return ret;
1013 }
1014
1015 static LONG DecodeBinaryToBinaryW(LPCWSTR pszString, DWORD cchString,
1016  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1017 {
1018     LONG ret = ERROR_SUCCESS;
1019
1020     if (*pcbBinary < cchString)
1021     {
1022         if (!pbBinary)
1023             *pcbBinary = cchString;
1024         else
1025         {
1026             ret = ERROR_INSUFFICIENT_BUFFER;
1027             *pcbBinary = cchString;
1028         }
1029     }
1030     else
1031     {
1032         if (cchString)
1033             memcpy(pbBinary, pszString, cchString * sizeof(WCHAR));
1034         *pcbBinary = cchString * sizeof(WCHAR);
1035     }
1036     return ret;
1037 }
1038
1039 static LONG DecodeAnyW(LPCWSTR pszString, DWORD cchString,
1040  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1041 {
1042     LONG ret;
1043
1044     ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1045      pdwSkip, pdwFlags);
1046     if (ret == ERROR_INVALID_DATA)
1047         ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1048          pdwSkip, pdwFlags);
1049     if (ret == ERROR_INVALID_DATA)
1050         ret = DecodeBinaryToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1051          pdwSkip, pdwFlags);
1052     return ret;
1053 }
1054
1055 BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString,
1056  DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
1057  DWORD *pdwSkip, DWORD *pdwFlags)
1058 {
1059     StringToBinaryWFunc decoder;
1060     LONG ret;
1061
1062     TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_w(pszString),
1063      cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1064
1065     if (!pszString)
1066     {
1067         SetLastError(ERROR_INVALID_PARAMETER);
1068         return FALSE;
1069     }
1070     /* Only the bottom byte contains valid types */
1071     if (dwFlags & 0xfffffff0)
1072     {
1073         SetLastError(ERROR_INVALID_DATA);
1074         return FALSE;
1075     }
1076     switch (dwFlags)
1077     {
1078     case CRYPT_STRING_BASE64_ANY:
1079         decoder = Base64AnyToBinaryW;
1080         break;
1081     case CRYPT_STRING_BASE64:
1082         decoder = Base64ToBinaryW;
1083         break;
1084     case CRYPT_STRING_BASE64HEADER:
1085         decoder = Base64HeaderToBinaryW;
1086         break;
1087     case CRYPT_STRING_BASE64REQUESTHEADER:
1088         decoder = Base64RequestHeaderToBinaryW;
1089         break;
1090     case CRYPT_STRING_BASE64X509CRLHEADER:
1091         decoder = Base64X509HeaderToBinaryW;
1092         break;
1093     case CRYPT_STRING_BINARY:
1094         decoder = DecodeBinaryToBinaryW;
1095         break;
1096     case CRYPT_STRING_ANY:
1097         decoder = DecodeAnyW;
1098         break;
1099     case CRYPT_STRING_HEX:
1100     case CRYPT_STRING_HEXASCII:
1101     case CRYPT_STRING_HEXADDR:
1102     case CRYPT_STRING_HEXASCIIADDR:
1103         FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
1104         /* fall through */
1105     default:
1106         SetLastError(ERROR_INVALID_PARAMETER);
1107         return FALSE;
1108     }
1109     if (!cchString)
1110         cchString = strlenW(pszString);
1111     ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1112     if (ret)
1113         SetLastError(ret);
1114     return (ret == ERROR_SUCCESS) ? TRUE : FALSE;
1115 }