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