crypt32: Implement CertGetNameStringW for CERT_NAME_RDN_TYPE.
[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
64 static BOOL EncodeBinaryToBinaryA(const BYTE *pbBinary,
65  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
66 {
67     BOOL ret = TRUE;
68
69     if (*pcchString < cbBinary)
70     {
71         if (!pszString)
72             *pcchString = cbBinary;
73         else
74         {
75             SetLastError(ERROR_INSUFFICIENT_BUFFER);
76             *pcchString = cbBinary;
77             ret = FALSE;
78         }
79     }
80     else
81     {
82         if (cbBinary)
83             memcpy(pszString, pbBinary, cbBinary);
84         *pcchString = cbBinary;
85     }
86     return ret;
87 }
88
89 static LONG encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep,
90  char* out_buf, DWORD *out_len)
91 {
92     int div, i;
93     const BYTE *d = in_buf;
94     int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
95     DWORD needed;
96     LPSTR ptr;
97
98     TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
99     needed = bytes + pad_bytes + 1;
100     needed += (needed / 64 + 1) * strlen(sep);
101
102     if (needed > *out_len)
103     {
104         *out_len = needed;
105         return ERROR_INSUFFICIENT_BUFFER;
106     }
107     else
108         *out_len = needed;
109
110     /* Three bytes of input give 4 chars of output */
111     div = in_len / 3;
112
113     ptr = out_buf;
114     i = 0;
115     while (div > 0)
116     {
117         if (i && i % 64 == 0)
118         {
119             strcpy(ptr, sep);
120             ptr += strlen(sep);
121         }
122         /* first char is the first 6 bits of the first byte*/
123         *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
124         /* second char is the last 2 bits of the first byte and the first 4
125          * bits of the second byte */
126         *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
127         /* third char is the last 4 bits of the second byte and the first 2
128          * bits of the third byte */
129         *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
130         /* fourth char is the remaining 6 bits of the third byte */
131         *ptr++ = b64[   d[2]       & 0x3f];
132         i += 4;
133         d += 3;
134         div--;
135     }
136
137     switch(pad_bytes)
138     {
139         case 1:
140             /* first char is the first 6 bits of the first byte*/
141             *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
142             /* second char is the last 2 bits of the first byte and the first 4
143              * bits of the second byte */
144             *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
145             /* third char is the last 4 bits of the second byte padded with
146              * two zeroes */
147             *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
148             /* fourth char is a = to indicate one byte of padding */
149             *ptr++ = '=';
150             break;
151         case 2:
152             /* first char is the first 6 bits of the first byte*/
153             *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
154             /* second char is the last 2 bits of the first byte padded with
155              * four zeroes*/
156             *ptr++ = b64[ ((d[0] << 4) & 0x30)];
157             /* third char is = to indicate padding */
158             *ptr++ = '=';
159             /* fourth char is = to indicate padding */
160             *ptr++ = '=';
161             break;
162     }
163     strcpy(ptr, sep);
164
165     return ERROR_SUCCESS;
166 }
167
168 static BOOL BinaryToBase64A(const BYTE *pbBinary,
169  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
170 {
171     static const char crlf[] = "\r\n", lf[] = "\n";
172     BOOL ret = TRUE;
173     LPCSTR header = NULL, trailer = NULL, sep = NULL;
174     DWORD charsNeeded;
175
176     if (dwFlags & CRYPT_STRING_NOCR)
177         sep = lf;
178     else
179         sep = crlf;
180     switch (dwFlags & 0x7fffffff)
181     {
182     case CRYPT_STRING_BASE64:
183         /* no header or footer */
184         break;
185     case CRYPT_STRING_BASE64HEADER:
186         header = CERT_HEADER;
187         trailer = CERT_TRAILER;
188         break;
189     case CRYPT_STRING_BASE64REQUESTHEADER:
190         header = CERT_REQUEST_HEADER;
191         trailer = CERT_REQUEST_TRAILER;
192         break;
193     case CRYPT_STRING_BASE64X509CRLHEADER:
194         header = X509_HEADER;
195         trailer = X509_TRAILER;
196         break;
197     }
198
199     charsNeeded = 0;
200     encodeBase64A(pbBinary, cbBinary, sep, NULL, &charsNeeded);
201     charsNeeded += strlen(sep);
202     if (header)
203         charsNeeded += strlen(header) + strlen(sep);
204     if (trailer)
205         charsNeeded += strlen(trailer) + strlen(sep);
206     if (charsNeeded <= *pcchString)
207     {
208         LPSTR ptr = pszString;
209         DWORD size = charsNeeded;
210
211         if (header)
212         {
213             strcpy(ptr, header);
214             ptr += strlen(ptr);
215             strcpy(ptr, sep);
216             ptr += strlen(sep);
217         }
218         encodeBase64A(pbBinary, cbBinary, sep, ptr, &size);
219         ptr += size - 1;
220         if (trailer)
221         {
222             strcpy(ptr, trailer);
223             ptr += strlen(ptr);
224             strcpy(ptr, sep);
225             ptr += strlen(sep);
226         }
227         *pcchString = charsNeeded - 1;
228     }
229     else if (pszString)
230     {
231         *pcchString = charsNeeded;
232         SetLastError(ERROR_INSUFFICIENT_BUFFER);
233         ret = FALSE;
234     }
235     else
236         *pcchString = charsNeeded;
237     return ret;
238 }
239
240 BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary,
241  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
242 {
243     BinaryToStringAFunc encoder = NULL;
244
245     TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
246      pcchString);
247
248     if (!pbBinary)
249     {
250         SetLastError(ERROR_INVALID_PARAMETER);
251         return FALSE;
252     }
253     if (!pcchString)
254     {
255         SetLastError(ERROR_INVALID_PARAMETER);
256         return FALSE;
257     }
258
259     switch (dwFlags & 0x7fffffff)
260     {
261     case CRYPT_STRING_BINARY:
262         encoder = EncodeBinaryToBinaryA;
263         break;
264     case CRYPT_STRING_BASE64:
265     case CRYPT_STRING_BASE64HEADER:
266     case CRYPT_STRING_BASE64REQUESTHEADER:
267     case CRYPT_STRING_BASE64X509CRLHEADER:
268         encoder = BinaryToBase64A;
269         break;
270     case CRYPT_STRING_HEX:
271     case CRYPT_STRING_HEXASCII:
272     case CRYPT_STRING_HEXADDR:
273     case CRYPT_STRING_HEXASCIIADDR:
274         FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
275         /* fall through */
276     default:
277         SetLastError(ERROR_INVALID_PARAMETER);
278         return FALSE;
279     }
280     return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
281 }
282
283 static inline BYTE decodeBase64Byte(int c)
284 {
285     BYTE ret;
286
287     if (c >= 'A' && c <= 'Z')
288         ret = c - 'A';
289     else if (c >= 'a' && c <= 'z')
290         ret = c - 'a' + 26;
291     else if (c >= '0' && c <= '9')
292         ret = c - '0' + 52;
293     else if (c == '+')
294         ret = 62;
295     else if (c == '/')
296         ret = 63;
297     else
298         ret = 64;
299     return ret;
300 }
301
302 static LONG decodeBase64Block(const char *in_buf, int in_len,
303  const char **nextBlock, PBYTE out_buf, DWORD *out_len)
304 {
305     int len = in_len, i;
306     const char *d = in_buf;
307     int  ip0, ip1, ip2, ip3;
308
309     if (len < 4)
310         return ERROR_INVALID_DATA;
311
312     i = 0;
313     if (d[2] == '=')
314     {
315         if ((ip0 = decodeBase64Byte(d[0])) > 63)
316             return ERROR_INVALID_DATA;
317         if ((ip1 = decodeBase64Byte(d[1])) > 63)
318             return ERROR_INVALID_DATA;
319
320         if (out_buf)
321             out_buf[i] = (ip0 << 2) | (ip1 >> 4);
322         i++;
323     }
324     else if (d[3] == '=')
325     {
326         if ((ip0 = decodeBase64Byte(d[0])) > 63)
327             return ERROR_INVALID_DATA;
328         if ((ip1 = decodeBase64Byte(d[1])) > 63)
329             return ERROR_INVALID_DATA;
330         if ((ip2 = decodeBase64Byte(d[2])) > 63)
331             return ERROR_INVALID_DATA;
332
333         if (out_buf)
334         {
335             out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
336             out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
337         }
338         i += 2;
339     }
340     else
341     {
342         if ((ip0 = decodeBase64Byte(d[0])) > 63)
343             return ERROR_INVALID_DATA;
344         if ((ip1 = decodeBase64Byte(d[1])) > 63)
345             return ERROR_INVALID_DATA;
346         if ((ip2 = decodeBase64Byte(d[2])) > 63)
347             return ERROR_INVALID_DATA;
348         if ((ip3 = decodeBase64Byte(d[3])) > 63)
349             return ERROR_INVALID_DATA;
350
351         if (out_buf)
352         {
353             out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
354             out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
355             out_buf[i + 2] = (ip2 << 6) |  ip3;
356         }
357         i += 3;
358     }
359     if (len >= 6 && d[4] == '\r' && d[5] == '\n')
360         *nextBlock = d + 6;
361     else if (len >= 5 && d[4] == '\n')
362         *nextBlock = d + 5;
363     else if (len >= 4 && d[4])
364         *nextBlock = d + 4;
365     else
366         *nextBlock = NULL;
367     *out_len = i;
368     return ERROR_SUCCESS;
369 }
370
371 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
372  * string to convert.
373  */
374 typedef LONG (*StringToBinaryAFunc)(LPCSTR pszString, DWORD cchString,
375  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
376
377 static LONG Base64ToBinaryA(LPCSTR pszString, DWORD cchString,
378  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
379 {
380     LONG ret = ERROR_SUCCESS;
381     const char *nextBlock;
382     DWORD outLen = 0;
383
384     nextBlock = pszString;
385     while (nextBlock && !ret)
386     {
387         DWORD len = 0;
388
389         ret = decodeBase64Block(nextBlock, cchString - (nextBlock - pszString),
390          &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
391         if (!ret)
392             outLen += len;
393         if (cchString - (nextBlock - pszString) <= 0)
394             nextBlock = NULL;
395     }
396     *pcbBinary = outLen;
397     if (!ret)
398     {
399         if (pdwSkip)
400             *pdwSkip = 0;
401         if (pdwFlags)
402             *pdwFlags = CRYPT_STRING_BASE64;
403     }
404     else if (ret == ERROR_INSUFFICIENT_BUFFER)
405     {
406         if (!pbBinary)
407             ret = ERROR_SUCCESS;
408     }
409     return ret;
410 }
411
412 static LONG Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString,
413  DWORD cchString, LPCSTR header, LPCSTR trailer, BYTE *pbBinary,
414  DWORD *pcbBinary, DWORD *pdwSkip)
415 {
416     LONG ret;
417     LPCSTR ptr;
418
419     if (cchString > strlen(header) + strlen(trailer)
420      && (ptr = strstr(pszString, header)) != NULL)
421     {
422         LPCSTR trailerSpot = pszString + cchString - strlen(trailer);
423
424         if (pszString[cchString - 1] == '\n')
425         {
426             cchString--;
427             trailerSpot--;
428         }
429         if (pszString[cchString - 1] == '\r')
430         {
431             cchString--;
432             trailerSpot--;
433         }
434         if (!strncmp(trailerSpot, trailer, strlen(trailer)))
435         {
436             if (pdwSkip)
437                 *pdwSkip = ptr - pszString;
438             ptr += strlen(header);
439             if (*ptr == '\r') ptr++;
440             if (*ptr == '\n') ptr++;
441             cchString -= ptr - pszString + strlen(trailer);
442             ret = Base64ToBinaryA(ptr, cchString, pbBinary, pcbBinary, NULL,
443              NULL);
444         }
445         else
446             ret = ERROR_INVALID_DATA;
447     }
448     else
449         ret = ERROR_INVALID_DATA;
450     return ret;
451 }
452
453 static LONG Base64HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
454  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
455 {
456     LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
457      CERT_HEADER, CERT_TRAILER, pbBinary, pcbBinary, pdwSkip);
458
459     if (!ret && pdwFlags)
460         *pdwFlags = CRYPT_STRING_BASE64HEADER;
461     return ret;
462 }
463
464 static LONG Base64RequestHeaderToBinaryA(LPCSTR pszString, DWORD cchString,
465  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
466 {
467     LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
468      CERT_REQUEST_HEADER, CERT_REQUEST_TRAILER, pbBinary, pcbBinary, pdwSkip);
469
470     if (!ret && pdwFlags)
471         *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
472     return ret;
473 }
474
475 static LONG Base64X509HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
476  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
477 {
478     LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
479      X509_HEADER, X509_TRAILER, pbBinary, pcbBinary, pdwSkip);
480
481     if (!ret && pdwFlags)
482         *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
483     return ret;
484 }
485
486 static LONG Base64AnyToBinaryA(LPCSTR pszString, DWORD cchString,
487  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
488 {
489     LONG ret;
490
491     ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
492      pdwSkip, pdwFlags);
493     if (ret == ERROR_INVALID_DATA)
494         ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
495          pdwSkip, pdwFlags);
496     return ret;
497 }
498
499 static LONG DecodeBinaryToBinaryA(LPCSTR pszString, DWORD cchString,
500  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
501 {
502     LONG ret = ERROR_SUCCESS;
503
504     if (*pcbBinary < cchString)
505     {
506         if (!pbBinary)
507             *pcbBinary = cchString;
508         else
509         {
510             ret = ERROR_INSUFFICIENT_BUFFER;
511             *pcbBinary = cchString;
512         }
513     }
514     else
515     {
516         if (cchString)
517             memcpy(pbBinary, pszString, cchString);
518         *pcbBinary = cchString;
519     }
520     return ret;
521 }
522
523 static LONG DecodeAnyA(LPCSTR pszString, DWORD cchString,
524  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
525 {
526     LONG ret;
527
528     ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
529      pdwSkip, pdwFlags);
530     if (ret == ERROR_INVALID_DATA)
531         ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
532          pdwSkip, pdwFlags);
533     if (ret == ERROR_INVALID_DATA)
534         ret = DecodeBinaryToBinaryA(pszString, cchString, pbBinary, pcbBinary,
535          pdwSkip, pdwFlags);
536     return ret;
537 }
538
539 BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString,
540  DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
541  DWORD *pdwSkip, DWORD *pdwFlags)
542 {
543     StringToBinaryAFunc decoder;
544     LONG ret;
545
546     TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_a(pszString),
547      cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
548
549     if (!pszString)
550     {
551         SetLastError(ERROR_INVALID_PARAMETER);
552         return FALSE;
553     }
554     /* Only the bottom byte contains valid types */
555     if (dwFlags & 0xfffffff0)
556     {
557         SetLastError(ERROR_INVALID_DATA);
558         return FALSE;
559     }
560     switch (dwFlags)
561     {
562     case CRYPT_STRING_BASE64_ANY:
563         decoder = Base64AnyToBinaryA;
564         break;
565     case CRYPT_STRING_BASE64:
566         decoder = Base64ToBinaryA;
567         break;
568     case CRYPT_STRING_BASE64HEADER:
569         decoder = Base64HeaderToBinaryA;
570         break;
571     case CRYPT_STRING_BASE64REQUESTHEADER:
572         decoder = Base64RequestHeaderToBinaryA;
573         break;
574     case CRYPT_STRING_BASE64X509CRLHEADER:
575         decoder = Base64X509HeaderToBinaryA;
576         break;
577     case CRYPT_STRING_BINARY:
578         decoder = DecodeBinaryToBinaryA;
579         break;
580     case CRYPT_STRING_ANY:
581         decoder = DecodeAnyA;
582         break;
583     case CRYPT_STRING_HEX:
584     case CRYPT_STRING_HEXASCII:
585     case CRYPT_STRING_HEXADDR:
586     case CRYPT_STRING_HEXASCIIADDR:
587         FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
588         /* fall through */
589     default:
590         SetLastError(ERROR_INVALID_PARAMETER);
591         return FALSE;
592     }
593     if (!cchString)
594         cchString = strlen(pszString);
595     ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
596     if (ret)
597         SetLastError(ret);
598     return (ret == ERROR_SUCCESS) ? TRUE : FALSE;
599 }
600
601 static LONG decodeBase64BlockW(const WCHAR *in_buf, int in_len,
602  const WCHAR **nextBlock, PBYTE out_buf, DWORD *out_len)
603 {
604     int len = in_len, i;
605     const WCHAR *d = in_buf;
606     int  ip0, ip1, ip2, ip3;
607
608     if (len < 4)
609         return ERROR_INVALID_DATA;
610
611     i = 0;
612     if (d[2] == '=')
613     {
614         if ((ip0 = decodeBase64Byte(d[0])) > 63)
615             return ERROR_INVALID_DATA;
616         if ((ip1 = decodeBase64Byte(d[1])) > 63)
617             return ERROR_INVALID_DATA;
618
619         if (out_buf)
620             out_buf[i] = (ip0 << 2) | (ip1 >> 4);
621         i++;
622     }
623     else if (d[3] == '=')
624     {
625         if ((ip0 = decodeBase64Byte(d[0])) > 63)
626             return ERROR_INVALID_DATA;
627         if ((ip1 = decodeBase64Byte(d[1])) > 63)
628             return ERROR_INVALID_DATA;
629         if ((ip2 = decodeBase64Byte(d[2])) > 63)
630             return ERROR_INVALID_DATA;
631
632         if (out_buf)
633         {
634             out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
635             out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
636         }
637         i += 2;
638     }
639     else
640     {
641         if ((ip0 = decodeBase64Byte(d[0])) > 63)
642             return ERROR_INVALID_DATA;
643         if ((ip1 = decodeBase64Byte(d[1])) > 63)
644             return ERROR_INVALID_DATA;
645         if ((ip2 = decodeBase64Byte(d[2])) > 63)
646             return ERROR_INVALID_DATA;
647         if ((ip3 = decodeBase64Byte(d[3])) > 63)
648             return ERROR_INVALID_DATA;
649
650         if (out_buf)
651         {
652             out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
653             out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
654             out_buf[i + 2] = (ip2 << 6) |  ip3;
655         }
656         i += 3;
657     }
658     if (len >= 6 && d[4] == '\r' && d[5] == '\n')
659         *nextBlock = d + 6;
660     else if (len >= 5 && d[4] == '\n')
661         *nextBlock = d + 5;
662     else if (len >= 4 && d[4])
663         *nextBlock = d + 4;
664     else
665         *nextBlock = NULL;
666     *out_len = i;
667     return ERROR_SUCCESS;
668 }
669
670 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
671  * string to convert.
672  */
673 typedef LONG (*StringToBinaryWFunc)(LPCWSTR pszString, DWORD cchString,
674  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
675
676 static LONG Base64ToBinaryW(LPCWSTR pszString, DWORD cchString,
677  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
678 {
679     LONG ret = ERROR_SUCCESS;
680     const WCHAR *nextBlock;
681     DWORD outLen = 0;
682
683     nextBlock = pszString;
684     while (nextBlock && !ret)
685     {
686         DWORD len = 0;
687
688         ret = decodeBase64BlockW(nextBlock, cchString - (nextBlock - pszString),
689          &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
690         if (!ret)
691             outLen += len;
692         if (cchString - (nextBlock - pszString) <= 0)
693             nextBlock = NULL;
694     }
695     *pcbBinary = outLen;
696     if (!ret)
697     {
698         if (pdwSkip)
699             *pdwSkip = 0;
700         if (pdwFlags)
701             *pdwFlags = CRYPT_STRING_BASE64;
702     }
703     else if (ret == ERROR_INSUFFICIENT_BUFFER)
704     {
705         if (!pbBinary)
706             ret = ERROR_SUCCESS;
707     }
708     return ret;
709 }
710
711 static LONG Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString,
712  DWORD cchString, LPCWSTR header, LPCWSTR trailer, BYTE *pbBinary,
713  DWORD *pcbBinary, DWORD *pdwSkip)
714 {
715     LONG ret;
716     LPCWSTR ptr;
717
718     if (cchString > strlenW(header) + strlenW(trailer)
719      && (ptr = strstrW(pszString, header)) != NULL)
720     {
721         LPCWSTR trailerSpot = pszString + cchString - strlenW(trailer);
722
723         if (pszString[cchString - 1] == '\n')
724         {
725             cchString--;
726             trailerSpot--;
727         }
728         if (pszString[cchString - 1] == '\r')
729         {
730             cchString--;
731             trailerSpot--;
732         }
733         if (!strncmpW(trailerSpot, trailer, strlenW(trailer)))
734         {
735             if (pdwSkip)
736                 *pdwSkip = ptr - pszString;
737             ptr += strlenW(header);
738             if (*ptr == '\r') ptr++;
739             if (*ptr == '\n') ptr++;
740             cchString -= ptr - pszString + strlenW(trailer);
741             ret = Base64ToBinaryW(ptr, cchString, pbBinary, pcbBinary, NULL,
742              NULL);
743         }
744         else
745             ret = ERROR_INVALID_DATA;
746     }
747     else
748         ret = ERROR_INVALID_DATA;
749     return ret;
750 }
751
752 static LONG Base64HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
753  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
754 {
755     LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
756      CERT_HEADER_W, CERT_TRAILER_W, pbBinary, pcbBinary, pdwSkip);
757
758     if (!ret && pdwFlags)
759         *pdwFlags = CRYPT_STRING_BASE64HEADER;
760     return ret;
761 }
762
763 static LONG Base64RequestHeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
764  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
765 {
766     LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
767      CERT_REQUEST_HEADER_W, CERT_REQUEST_TRAILER_W, pbBinary, pcbBinary,
768      pdwSkip);
769
770     if (!ret && pdwFlags)
771         *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
772     return ret;
773 }
774
775 static LONG Base64X509HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
776  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
777 {
778     LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
779      X509_HEADER_W, X509_TRAILER_W, pbBinary, pcbBinary, pdwSkip);
780
781     if (!ret && pdwFlags)
782         *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
783     return ret;
784 }
785
786 static LONG Base64AnyToBinaryW(LPCWSTR pszString, DWORD cchString,
787  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
788 {
789     LONG ret;
790
791     ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
792      pdwSkip, pdwFlags);
793     if (ret == ERROR_INVALID_DATA)
794         ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
795          pdwSkip, pdwFlags);
796     return ret;
797 }
798
799 static LONG DecodeBinaryToBinaryW(LPCWSTR pszString, DWORD cchString,
800  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
801 {
802     LONG ret = ERROR_SUCCESS;
803
804     if (*pcbBinary < cchString)
805     {
806         if (!pbBinary)
807             *pcbBinary = cchString;
808         else
809         {
810             ret = ERROR_INSUFFICIENT_BUFFER;
811             *pcbBinary = cchString;
812         }
813     }
814     else
815     {
816         if (cchString)
817             memcpy(pbBinary, pszString, cchString * sizeof(WCHAR));
818         *pcbBinary = cchString * sizeof(WCHAR);
819     }
820     return ret;
821 }
822
823 static LONG DecodeAnyW(LPCWSTR pszString, DWORD cchString,
824  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
825 {
826     LONG ret;
827
828     ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
829      pdwSkip, pdwFlags);
830     if (ret == ERROR_INVALID_DATA)
831         ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
832          pdwSkip, pdwFlags);
833     if (ret == ERROR_INVALID_DATA)
834         ret = DecodeBinaryToBinaryW(pszString, cchString, pbBinary, pcbBinary,
835          pdwSkip, pdwFlags);
836     return ret;
837 }
838
839 BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString,
840  DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
841  DWORD *pdwSkip, DWORD *pdwFlags)
842 {
843     StringToBinaryWFunc decoder;
844     LONG ret;
845
846     TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_w(pszString),
847      cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
848
849     if (!pszString)
850     {
851         SetLastError(ERROR_INVALID_PARAMETER);
852         return FALSE;
853     }
854     /* Only the bottom byte contains valid types */
855     if (dwFlags & 0xfffffff0)
856     {
857         SetLastError(ERROR_INVALID_DATA);
858         return FALSE;
859     }
860     switch (dwFlags)
861     {
862     case CRYPT_STRING_BASE64_ANY:
863         decoder = Base64AnyToBinaryW;
864         break;
865     case CRYPT_STRING_BASE64:
866         decoder = Base64ToBinaryW;
867         break;
868     case CRYPT_STRING_BASE64HEADER:
869         decoder = Base64HeaderToBinaryW;
870         break;
871     case CRYPT_STRING_BASE64REQUESTHEADER:
872         decoder = Base64RequestHeaderToBinaryW;
873         break;
874     case CRYPT_STRING_BASE64X509CRLHEADER:
875         decoder = Base64X509HeaderToBinaryW;
876         break;
877     case CRYPT_STRING_BINARY:
878         decoder = DecodeBinaryToBinaryW;
879         break;
880     case CRYPT_STRING_ANY:
881         decoder = DecodeAnyW;
882         break;
883     case CRYPT_STRING_HEX:
884     case CRYPT_STRING_HEXASCII:
885     case CRYPT_STRING_HEXADDR:
886     case CRYPT_STRING_HEXASCIIADDR:
887         FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
888         /* fall through */
889     default:
890         SetLastError(ERROR_INVALID_PARAMETER);
891         return FALSE;
892     }
893     if (!cchString)
894         cchString = strlenW(pszString);
895     ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
896     if (ret)
897         SetLastError(ret);
898     return (ret == ERROR_SUCCESS) ? TRUE : FALSE;
899 }