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