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