1 /*
2  * Unit test suite for crypt32.dll's CryptStringToBinary and CryptBinaryToString
3  * functions.
4  *
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 #include <stdio.h>
22 #include <stdarg.h>
23 #include <windef.h>
24 #include <winbase.h>
25 #include <winerror.h>
26 #include <wincrypt.h>
27 
28 #include "wine/test.h"
29 
30 #define CERT_HEADER               "-----BEGIN CERTIFICATE-----\r\n"
31 #define ALT_CERT_HEADER           "-----BEGIN This is some arbitrary text that goes on and on-----\r\n"
32 #define CERT_TRAILER              "-----END CERTIFICATE-----\r\n"
33 #define ALT_CERT_TRAILER          "-----END More arbitrary text------\r\n"
34 #define CERT_REQUEST_HEADER       "-----BEGIN NEW CERTIFICATE REQUEST-----\r\n"
35 #define CERT_REQUEST_TRAILER      "-----END NEW CERTIFICATE REQUEST-----\r\n"
36 #define X509_HEADER               "-----BEGIN X509 CRL-----\r\n"
37 #define X509_TRAILER              "-----END X509 CRL-----\r\n"
38 #define CERT_HEADER_NOCR          "-----BEGIN CERTIFICATE-----\n"
39 #define CERT_TRAILER_NOCR         "-----END CERTIFICATE-----\n"
40 #define CERT_REQUEST_HEADER_NOCR  "-----BEGIN NEW CERTIFICATE REQUEST-----\n"
41 #define CERT_REQUEST_TRAILER_NOCR "-----END NEW CERTIFICATE REQUEST-----\n"
42 #define X509_HEADER_NOCR          "-----BEGIN X509 CRL-----\n"
43 #define X509_TRAILER_NOCR         "-----END X509 CRL-----\n"
44 
45 struct BinTests
46 {
47     const BYTE *toEncode;
48     DWORD       toEncodeLen;
49     const char *base64;
50 };
51 
52 static const BYTE toEncode1[] = { 0 };
53 static const BYTE toEncode2[] = { 1,2 };
54 /* static const BYTE toEncode3[] = { 1,2,3 }; */
55 static const BYTE toEncode4[] =
56  "abcdefghijlkmnopqrstuvwxyz01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890"
57  "abcdefghijlkmnopqrstuvwxyz01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890"
58  "abcdefghijlkmnopqrstuvwxyz01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890";
59 
60 static const struct BinTests tests[] = {
61  { toEncode1, sizeof(toEncode1), "AA==\r\n", },
62  { toEncode2, sizeof(toEncode2), "AQI=\r\n", },
63  /* { toEncode3, sizeof(toEncode3), "AQID\r\n", },  This test fails on Vista. */
64  { toEncode4, sizeof(toEncode4),
65    "YWJjZGVmZ2hpamxrbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5MEFCQ0RFRkdISUpL\r\n"
66    "TE1OT1BRUlNUVVZXWFlaMDEyMzQ1Njc4OTBhYmNkZWZnaGlqbGttbm9wcXJzdHV2\r\n"
67    "d3h5ejAxMjM0NTY3ODkwQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU2\r\n"
68    "Nzg5MGFiY2RlZmdoaWpsa21ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OTBBQkNERUZH\r\n"
69    "SElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NTY3ODkwAA==\r\n" },
70 };
71 
72 static const struct BinTests testsNoCR[] = {
73  { toEncode1, sizeof(toEncode1), "AA==\n", },
74  { toEncode2, sizeof(toEncode2), "AQI=\n", },
75  /* { toEncode3, sizeof(toEncode3), "AQID\n", },  This test fails on Vista. */
76  { toEncode4, sizeof(toEncode4),
77    "YWJjZGVmZ2hpamxrbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5MEFCQ0RFRkdISUpL\n"
78    "TE1OT1BRUlNUVVZXWFlaMDEyMzQ1Njc4OTBhYmNkZWZnaGlqbGttbm9wcXJzdHV2\n"
79    "d3h5ejAxMjM0NTY3ODkwQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU2\n"
80    "Nzg5MGFiY2RlZmdoaWpsa21ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OTBBQkNERUZH\n"
81    "SElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NTY3ODkwAA==\n" },
82 };
83 
84 static void encodeAndCompareBase64_A(const BYTE *toEncode, DWORD toEncodeLen,
85  DWORD format, const char *expected, const char *header, const char *trailer)
86 {
87     DWORD strLen = 0;
88     LPSTR str = NULL;
89     BOOL ret;
90 
91     ret = CryptBinaryToStringA(toEncode, toEncodeLen, format, NULL, &strLen);
92     ok(ret, "CryptBinaryToStringA failed: %d\n", GetLastError());
93     str = HeapAlloc(GetProcessHeap(), 0, strLen);
94     if (str)
95     {
96         DWORD strLen2 = strLen;
97         LPCSTR ptr = str;
98 
99         ret = CryptBinaryToStringA(toEncode, toEncodeLen, format, str,
100          &strLen2);
101         ok(ret, "CryptBinaryToStringA failed: %d\n", GetLastError());
102         ok(strLen2 == strLen - 1, "Expected length %d, got %d\n",
103          strLen - 1, strLen);
104         if (header)
105         {
106             ok(!strncmp(header, ptr, strlen(header)),
107              "Expected header %s, got %s\n", header, ptr);
108             ptr += strlen(header);
109         }
110         ok(!strncmp(expected, ptr, strlen(expected)),
111          "Expected %s, got %s\n", expected, ptr);
112         ptr += strlen(expected);
113         if (trailer)
114             ok(!strncmp(trailer, ptr, strlen(trailer)),
115              "Expected trailer %s, got %s\n", trailer, ptr);
116         HeapFree(GetProcessHeap(), 0, str);
117     }
118 }
119 
120 static void testBinaryToStringA(void)
121 {
122     BOOL ret;
123     DWORD strLen = 0, i;
124 
125     ret = CryptBinaryToStringA(NULL, 0, 0, NULL, NULL);
126     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
127      "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
128     ret = CryptBinaryToStringA(NULL, 0, 0, NULL, &strLen);
129     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
130      "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
131     for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++)
132     {
133         DWORD strLen = 0;
134         LPSTR str = NULL;
135         BOOL ret;
136 
137         ret = CryptBinaryToStringA(tests[i].toEncode, tests[i].toEncodeLen,
138          CRYPT_STRING_BINARY, NULL, &strLen);
139         ok(ret, "CryptBinaryToStringA failed: %d\n", GetLastError());
140         str = HeapAlloc(GetProcessHeap(), 0, strLen);
141         if (str)
142         {
143             DWORD strLen2 = strLen;
144 
145             ret = CryptBinaryToStringA(tests[i].toEncode, tests[i].toEncodeLen,
146              CRYPT_STRING_BINARY, str, &strLen2);
147             ok(ret, "CryptBinaryToStringA failed: %d\n", GetLastError());
148             ok(strLen == strLen2, "Expected length %d, got %d\n", strLen,
149              strLen2);
150             ok(!memcmp(str, tests[i].toEncode, tests[i].toEncodeLen),
151              "Unexpected value\n");
152             HeapFree(GetProcessHeap(), 0, str);
153         }
154         encodeAndCompareBase64_A(tests[i].toEncode, tests[i].toEncodeLen,
155          CRYPT_STRING_BASE64, tests[i].base64, NULL, NULL);
156         encodeAndCompareBase64_A(tests[i].toEncode, tests[i].toEncodeLen,
157          CRYPT_STRING_BASE64HEADER, tests[i].base64, CERT_HEADER,
158          CERT_TRAILER);
159         encodeAndCompareBase64_A(tests[i].toEncode, tests[i].toEncodeLen,
160          CRYPT_STRING_BASE64REQUESTHEADER, tests[i].base64,
161          CERT_REQUEST_HEADER, CERT_REQUEST_TRAILER);
162         encodeAndCompareBase64_A(tests[i].toEncode, tests[i].toEncodeLen,
163          CRYPT_STRING_BASE64X509CRLHEADER, tests[i].base64, X509_HEADER,
164          X509_TRAILER);
165     }
166     for (i = 0; i < sizeof(testsNoCR) / sizeof(testsNoCR[0]); i++)
167     {
168         DWORD strLen = 0;
169         LPSTR str = NULL;
170         BOOL ret;
171 
172         ret = CryptBinaryToStringA(testsNoCR[i].toEncode,
173          testsNoCR[i].toEncodeLen, CRYPT_STRING_BINARY | CRYPT_STRING_NOCR,
174          NULL, &strLen);
175         ok(ret, "CryptBinaryToStringA failed: %d\n", GetLastError());
176         str = HeapAlloc(GetProcessHeap(), 0, strLen);
177         if (str)
178         {
179             DWORD strLen2 = strLen;
180 
181             ret = CryptBinaryToStringA(testsNoCR[i].toEncode,
182              testsNoCR[i].toEncodeLen, CRYPT_STRING_BINARY | CRYPT_STRING_NOCR,
183              str, &strLen2);
184             ok(ret, "CryptBinaryToStringA failed: %d\n", GetLastError());
185             ok(strLen == strLen2, "Expected length %d, got %d\n", strLen,
186              strLen2);
187             ok(!memcmp(str, testsNoCR[i].toEncode, testsNoCR[i].toEncodeLen),
188              "Unexpected value\n");
189             HeapFree(GetProcessHeap(), 0, str);
190         }
191         encodeAndCompareBase64_A(testsNoCR[i].toEncode,
192          testsNoCR[i].toEncodeLen, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCR,
193          testsNoCR[i].base64, NULL, NULL);
194         encodeAndCompareBase64_A(testsNoCR[i].toEncode,
195          testsNoCR[i].toEncodeLen,
196          CRYPT_STRING_BASE64HEADER | CRYPT_STRING_NOCR, testsNoCR[i].base64,
197          CERT_HEADER_NOCR, CERT_TRAILER_NOCR);
198         encodeAndCompareBase64_A(testsNoCR[i].toEncode,
199          testsNoCR[i].toEncodeLen,
200          CRYPT_STRING_BASE64REQUESTHEADER | CRYPT_STRING_NOCR,
201          testsNoCR[i].base64, CERT_REQUEST_HEADER_NOCR,
202          CERT_REQUEST_TRAILER_NOCR);
203         encodeAndCompareBase64_A(testsNoCR[i].toEncode,
204          testsNoCR[i].toEncodeLen,
205          CRYPT_STRING_BASE64X509CRLHEADER | CRYPT_STRING_NOCR,
206          testsNoCR[i].base64, X509_HEADER_NOCR, X509_TRAILER_NOCR);
207     }
208 }
209 
210 static void decodeAndCompareBase64_A(LPCSTR toDecode, LPCSTR header,
211  LPCSTR trailer, DWORD useFormat, DWORD expectedFormat, const BYTE *expected,
212  DWORD expectedLen)
213 {
214     static const char garbage[] = "garbage\r\n";
215     LPSTR str;
216     DWORD len = strlen(toDecode) + strlen(garbage) + 1;
217 
218     if (header)
219         len += strlen(header);
220     if (trailer)
221         len += strlen(trailer);
222     str = HeapAlloc(GetProcessHeap(), 0, len);
223     if (str)
224     {
225         LPBYTE buf;
226         DWORD bufLen = 0;
227         BOOL ret;
228 
229         if (header)
230             strcpy(str, header);
231         else
232             *str = 0;
233         strcat(str, toDecode);
234         if (trailer)
235             strcat(str, trailer);
236         ret = CryptStringToBinaryA(str, 0, useFormat, NULL, &bufLen, NULL,
237          NULL);
238         ok(ret, "CryptStringToBinaryA failed: %d\n", GetLastError());
239         buf = HeapAlloc(GetProcessHeap(), 0, bufLen);
240         if (buf)
241         {
242             DWORD skipped, usedFormat;
243 
244             /* check as normal, make sure last two parameters are optional */
245             ret = CryptStringToBinaryA(str, 0, useFormat, buf, &bufLen, NULL,
246              NULL);
247             ok(ret, "CryptStringToBinaryA failed: %d\n", GetLastError());
248             ok(bufLen == expectedLen,
249              "Expected length %d, got %d\n", expectedLen, bufLen);
250             ok(!memcmp(buf, expected, bufLen), "Unexpected value\n");
251             /* check last two params */
252             ret = CryptStringToBinaryA(str, 0, useFormat, buf, &bufLen,
253              &skipped, &usedFormat);
254             ok(ret, "CryptStringToBinaryA failed: %d\n", GetLastError());
255             ok(skipped == 0, "Expected skipped 0, got %d\n", skipped);
256             ok(usedFormat == expectedFormat, "Expected format %d, got %d\n",
257              expectedFormat, usedFormat);
258             HeapFree(GetProcessHeap(), 0, buf);
259         }
260 
261         /* Check again, but with garbage up front */
262         strcpy(str, garbage);
263         if (header)
264             strcat(str, header);
265         strcat(str, toDecode);
266         if (trailer)
267             strcat(str, trailer);
268         ret = CryptStringToBinaryA(str, 0, useFormat, NULL, &bufLen, NULL,
269          NULL);
270         /* expect failure with no header, and success with one */
271         if (header)
272             ok(ret, "CryptStringToBinaryA failed: %d\n", GetLastError());
273         else
274             ok(!ret && GetLastError() == ERROR_INVALID_DATA,
275              "Expected !ret and last error ERROR_INVALID_DATA, got ret=%d, error=%d\n", ret, GetLastError());
276         if (ret)
277         {
278             buf = HeapAlloc(GetProcessHeap(), 0, bufLen);
279             if (buf)
280             {
281                 DWORD skipped, usedFormat;
282 
283                 ret = CryptStringToBinaryA(str, 0, useFormat, buf, &bufLen,
284                  &skipped, &usedFormat);
285                 ok(ret, "CryptStringToBinaryA failed: %d\n", GetLastError());
286                 ok(skipped == strlen(garbage),
287                  "Expected %d characters of \"%s\" skipped when trying format %08x, got %d (used format is %08x)\n",
288                  lstrlenA(garbage), str, useFormat, skipped, usedFormat);
289                 HeapFree(GetProcessHeap(), 0, buf);
290             }
291         }
292         HeapFree(GetProcessHeap(), 0, str);
293     }
294 }
295 
296 static void decodeBase64WithLenFmtW(LPCSTR strA, int len, DWORD fmt, BOOL retA,
297  const BYTE *bufA, DWORD bufLenA, DWORD fmtUsedA)
298 {
299     BYTE buf[8] = {0};
300     DWORD bufLen = sizeof(buf)-1, fmtUsed = 0xdeadbeef;
301     BOOL ret;
302     WCHAR strW[64];
303     int i;
304     for (i = 0; (strW[i] = strA[i]) != 0; ++i);
305     ret = CryptStringToBinaryW(strW, len, fmt, buf, &bufLen, NULL, &fmtUsed);
306     ok(ret == retA && bufLen == bufLenA && memcmp(bufA, buf, bufLen) == 0
307      && fmtUsed == fmtUsedA, "base64 \"%s\" len %d: W and A differ\n", strA, len);
308 }
309 
310 static void decodeBase64WithLenFmt(LPCSTR str, int len, DWORD fmt, LPCSTR expected, int le, BOOL isBroken)
311 {
312     BYTE buf[8] = {0};
313     DWORD bufLen = sizeof(buf)-1, fmtUsed = 0xdeadbeef;
314     BOOL ret;
315     SetLastError(0xdeadbeef);
316     ret = CryptStringToBinaryA(str, len, fmt, buf, &bufLen, NULL, &fmtUsed);
317     buf[bufLen] = 0;
318     if (expected) {
319         BOOL correct = ret && strcmp(expected, (char*)buf) == 0;
320         ok(correct || (isBroken && broken(!ret)),
321          "base64 \"%s\" len %d: expected \"%s\", got \"%s\" (ret %d, le %d)\n",
322          str, len, expected, (char*)buf, ret, GetLastError());
323         if (correct)
324             ok(fmtUsed == fmt, "base64 \"%s\" len %d: expected fmt %d, used %d\n",
325              str, len, fmt, fmtUsed);
326     } else {
327         ok(!ret && GetLastError() == le,
328          "base64 \"%s\" len %d: expected failure, got \"%s\" (ret %d, le %d)\n",
329          str, len, (char*)buf, ret, GetLastError());
330     }
331 
332     decodeBase64WithLenFmtW(str, len, fmt, ret, buf, bufLen, fmtUsed);
333 }
334 
335 static void decodeBase64WithLenBroken(LPCSTR str, int len, LPCSTR expected, int le)
336 {
337     decodeBase64WithLenFmt(str, len, CRYPT_STRING_BASE64, expected, le, TRUE);
338 }
339 
340 static void decodeBase64WithLen(LPCSTR str, int len, LPCSTR expected, int le)
341 {
342     decodeBase64WithLenFmt(str, len, CRYPT_STRING_BASE64, expected, le, FALSE);
343 }
344 
345 static void decodeBase64WithFmt(LPCSTR str, DWORD fmt, LPCSTR expected, int le)
346 {
347     decodeBase64WithLenFmt(str, 0, fmt, expected, le, FALSE);
348 }
349 
350 struct BadString
351 {
352     const char *str;
353     DWORD       format;
354 };
355 
356 static const struct BadString badStrings[] = {
357  { "-----BEGIN X509 CRL-----\r\nAA==\r\n", CRYPT_STRING_BASE64X509CRLHEADER },
358 };
359 
360 static void testStringToBinaryA(void)
361 {
362     BOOL ret;
363     DWORD bufLen = 0, i;
364     BYTE buf[8];
365 
366     ret = CryptStringToBinaryA(NULL, 0, 0, NULL, NULL, NULL, NULL);
367     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
368      "Expected ERROR_INVALID_PARAMETER, got ret=%d le=%u\n", ret, GetLastError());
369     ret = CryptStringToBinaryA(NULL, 0, 0, NULL, &bufLen, NULL, NULL);
370     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
371      "Expected ERROR_INVALID_PARAMETER, got ret=%d le=%u\n", ret, GetLastError());
372     /* Bogus format */
373     ret = CryptStringToBinaryA(tests[0].base64, 0, 0, NULL, &bufLen, NULL,
374      NULL);
375     ok(!ret && GetLastError() == ERROR_INVALID_DATA,
376      "Expected ERROR_INVALID_DATA, got ret=%d le=%u\n", ret, GetLastError());
377     /* Decoding doesn't expect the NOCR flag to be specified */
378     ret = CryptStringToBinaryA(tests[0].base64, 1,
379      CRYPT_STRING_BASE64 | CRYPT_STRING_NOCR, NULL, &bufLen, NULL, NULL);
380     ok(!ret && GetLastError() == ERROR_INVALID_DATA,
381      "Expected ERROR_INVALID_DATA, got ret=%d le=%u\n", ret, GetLastError());
382     /* Bad strings */
383     for (i = 0; i < sizeof(badStrings) / sizeof(badStrings[0]); i++)
384     {
385         bufLen = 0;
386         ret = CryptStringToBinaryA(badStrings[i].str, 0, badStrings[i].format,
387          NULL, &bufLen, NULL, NULL);
388         ok(!ret && GetLastError() == ERROR_INVALID_DATA,
389            "%d: Expected ERROR_INVALID_DATA, got ret=%d le=%u\n", i, ret, GetLastError());
390     }
391     /* Weird base64 strings (invalid padding, extra white-space etc.) */
392     decodeBase64WithLen("V=", 0, 0, ERROR_INVALID_DATA);
393     decodeBase64WithLen("VV=", 0, 0, ERROR_INVALID_DATA);
394     decodeBase64WithLen("V==", 0, 0, ERROR_INVALID_DATA);
395     decodeBase64WithLen("V=", 2, 0, ERROR_INVALID_DATA);
396     decodeBase64WithLen("VV=", 3, 0, ERROR_INVALID_DATA);
397     decodeBase64WithLen("V==", 3, 0, ERROR_INVALID_DATA);
398     decodeBase64WithLenBroken("V", 0, "T", 0);
399     decodeBase64WithLenBroken("VV", 0, "U", 0);
400     decodeBase64WithLenBroken("VVV", 0, "UU", 0);
401     decodeBase64WithLen("V", 1, "T", 0);
402     decodeBase64WithLen("VV", 2, "U", 0);
403     decodeBase64WithLen("VVV", 3, "UU", 0);
404     decodeBase64WithLen("V===", 0, "T", 0);
405     decodeBase64WithLen("V========", 0, "T", 0);
406     decodeBase64WithLen("V===", 4, "T", 0);
407     decodeBase64WithLen("V\nVVV", 0, "UUU", 0);
408     decodeBase64WithLen("VV\nVV", 0, "UUU", 0);
409     decodeBase64WithLen("VVV\nV", 0, "UUU", 0);
410     decodeBase64WithLen("V\nVVV", 5, "UUU", 0);
411     decodeBase64WithLen("VV\nVV", 5, "UUU", 0);
412     decodeBase64WithLen("VVV\nV", 5, "UUU", 0);
413     decodeBase64WithLen("VV    VV", 0, "UUU", 0);
414     decodeBase64WithLen("V===VVVV", 0, "T", 0);
415     decodeBase64WithLen("VV==VVVV", 0, "U", 0);
416     decodeBase64WithLen("VVV=VVVV", 0, "UU", 0);
417     decodeBase64WithLen("VVVV=VVVV", 0, "UUU", 0);
418     decodeBase64WithLen("V===VVVV", 8, "T", 0);
419     decodeBase64WithLen("VV==VVVV", 8, "U", 0);
420     decodeBase64WithLen("VVV=VVVV", 8, "UU", 0);
421     decodeBase64WithLen("VVVV=VVVV", 8, "UUU", 0);
422 
423     decodeBase64WithFmt("-----BEGIN-----VVVV-----END-----", CRYPT_STRING_BASE64HEADER, 0, ERROR_INVALID_DATA);
424     decodeBase64WithFmt("-----BEGIN-----VVVV-----END -----", CRYPT_STRING_BASE64HEADER, 0, ERROR_INVALID_DATA);
425     decodeBase64WithFmt("-----BEGIN -----VVVV-----END-----", CRYPT_STRING_BASE64HEADER, 0, ERROR_INVALID_DATA);
426     decodeBase64WithFmt("-----BEGIN -----VVVV-----END -----", CRYPT_STRING_BASE64HEADER, "UUU", 0);
427 
428     decodeBase64WithFmt("-----BEGIN -----V-----END -----", CRYPT_STRING_BASE64HEADER, "T", 0);
429     decodeBase64WithFmt("-----BEGIN foo-----V-----END -----", CRYPT_STRING_BASE64HEADER, "T", 0);
430     decodeBase64WithFmt("-----BEGIN foo-----V-----END foo-----", CRYPT_STRING_BASE64HEADER, "T", 0);
431     decodeBase64WithFmt("-----BEGIN -----V-----END foo-----", CRYPT_STRING_BASE64HEADER, "T", 0);
432     decodeBase64WithFmt("-----BEGIN -----V-----END -----", CRYPT_STRING_BASE64X509CRLHEADER, "T", 0);
433     decodeBase64WithFmt("-----BEGIN foo-----V-----END -----", CRYPT_STRING_BASE64X509CRLHEADER, "T", 0);
434     decodeBase64WithFmt("-----BEGIN foo-----V-----END foo-----", CRYPT_STRING_BASE64X509CRLHEADER, "T", 0);
435     decodeBase64WithFmt("-----BEGIN -----V-----END foo-----", CRYPT_STRING_BASE64X509CRLHEADER, "T", 0);
436     decodeBase64WithFmt("-----BEGIN -----V-----END -----", CRYPT_STRING_BASE64REQUESTHEADER, "T", 0);
437     decodeBase64WithFmt("-----BEGIN foo-----V-----END -----", CRYPT_STRING_BASE64REQUESTHEADER, "T", 0);
438     decodeBase64WithFmt("-----BEGIN foo-----V-----END foo-----", CRYPT_STRING_BASE64REQUESTHEADER, "T", 0);
439     decodeBase64WithFmt("-----BEGIN -----V-----END foo-----", CRYPT_STRING_BASE64REQUESTHEADER, "T", 0);
440 
441     /* Too small buffer */
442     buf[0] = 0;
443     bufLen = 4;
444     ret = CryptStringToBinaryA("VVVVVVVV", 8, CRYPT_STRING_BASE64, (BYTE*)buf, &bufLen, NULL, NULL);
445     ok(!ret && bufLen == 4 && buf[0] == 0,
446      "Expected ret 0, bufLen 4, buf[0] '\\0', got ret %d, bufLen %d, buf[0] '%c'\n",
447      ret, bufLen, buf[0]);
448 
449     /* Good strings */
450     for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++)
451     {
452         bufLen = 0;
453         /* Bogus length--oddly enough, that succeeds, even though it's not
454          * properly padded.
455          */
456         ret = CryptStringToBinaryA(tests[i].base64, 1, CRYPT_STRING_BASE64,
457          NULL, &bufLen, NULL, NULL);
458         ok(ret, "CryptStringToBinaryA failed: %d\n", GetLastError());
459         /* Check with the precise format */
460         decodeAndCompareBase64_A(tests[i].base64, NULL, NULL,
461          CRYPT_STRING_BASE64, CRYPT_STRING_BASE64, tests[i].toEncode,
462          tests[i].toEncodeLen);
463         decodeAndCompareBase64_A(tests[i].base64, CERT_HEADER, CERT_TRAILER,
464          CRYPT_STRING_BASE64HEADER, CRYPT_STRING_BASE64HEADER,
465          tests[i].toEncode, tests[i].toEncodeLen);
466         decodeAndCompareBase64_A(tests[i].base64, ALT_CERT_HEADER, ALT_CERT_TRAILER,
467          CRYPT_STRING_BASE64HEADER, CRYPT_STRING_BASE64HEADER,
468          tests[i].toEncode, tests[i].toEncodeLen);
469         decodeAndCompareBase64_A(tests[i].base64, CERT_REQUEST_HEADER,
470          CERT_REQUEST_TRAILER, CRYPT_STRING_BASE64REQUESTHEADER,
471          CRYPT_STRING_BASE64REQUESTHEADER, tests[i].toEncode,
472          tests[i].toEncodeLen);
473         decodeAndCompareBase64_A(tests[i].base64, X509_HEADER, X509_TRAILER,
474          CRYPT_STRING_BASE64X509CRLHEADER, CRYPT_STRING_BASE64X509CRLHEADER,
475          tests[i].toEncode, tests[i].toEncodeLen);
476         /* And check with the "any" formats */
477         decodeAndCompareBase64_A(tests[i].base64, NULL, NULL,
478          CRYPT_STRING_BASE64_ANY, CRYPT_STRING_BASE64, tests[i].toEncode,
479          tests[i].toEncodeLen);
480         /* Don't check with no header and the string_any format, that'll
481          * always succeed.
482          */
483         decodeAndCompareBase64_A(tests[i].base64, CERT_HEADER, CERT_TRAILER,
484          CRYPT_STRING_BASE64_ANY, CRYPT_STRING_BASE64HEADER, tests[i].toEncode,
485          tests[i].toEncodeLen);
486         decodeAndCompareBase64_A(tests[i].base64, CERT_HEADER, CERT_TRAILER,
487          CRYPT_STRING_ANY, CRYPT_STRING_BASE64HEADER, tests[i].toEncode,
488          tests[i].toEncodeLen);
489         /* oddly, these seem to decode using the wrong format
490         decodeAndCompareBase64_A(tests[i].base64, CERT_REQUEST_HEADER,
491          CERT_REQUEST_TRAILER, CRYPT_STRING_BASE64_ANY,
492          CRYPT_STRING_BASE64REQUESTHEADER, tests[i].toEncode,
493          tests[i].toEncodeLen);
494         decodeAndCompareBase64_A(tests[i].base64, CERT_REQUEST_HEADER,
495          CERT_REQUEST_TRAILER, CRYPT_STRING_ANY,
496          CRYPT_STRING_BASE64REQUESTHEADER, tests[i].toEncode,
497          tests[i].toEncodeLen);
498         decodeAndCompareBase64_A(tests[i].base64, X509_HEADER, X509_TRAILER,
499          CRYPT_STRING_BASE64_ANY, CRYPT_STRING_BASE64X509CRLHEADER,
500          tests[i].toEncode, tests[i].toEncodeLen);
501         decodeAndCompareBase64_A(tests[i].base64, X509_HEADER, X509_TRAILER,
502          CRYPT_STRING_ANY, CRYPT_STRING_BASE64X509CRLHEADER, tests[i].toEncode,
503          tests[i].toEncodeLen);
504          */
505     }
506     /* And again, with no CR--decoding handles this automatically */
507     for (i = 0; i < sizeof(testsNoCR) / sizeof(testsNoCR[0]); i++)
508     {
509         bufLen = 0;
510         /* Bogus length--oddly enough, that succeeds, even though it's not
511          * properly padded.
512          */
513         ret = CryptStringToBinaryA(testsNoCR[i].base64, 1, CRYPT_STRING_BASE64,
514          NULL, &bufLen, NULL, NULL);
515         ok(ret, "CryptStringToBinaryA failed: %d\n", GetLastError());
516         /* Check with the precise format */
517         decodeAndCompareBase64_A(testsNoCR[i].base64, NULL, NULL,
518          CRYPT_STRING_BASE64, CRYPT_STRING_BASE64, testsNoCR[i].toEncode,
519          testsNoCR[i].toEncodeLen);
520         decodeAndCompareBase64_A(testsNoCR[i].base64, CERT_HEADER, CERT_TRAILER,
521          CRYPT_STRING_BASE64HEADER, CRYPT_STRING_BASE64HEADER,
522          testsNoCR[i].toEncode, testsNoCR[i].toEncodeLen);
523         decodeAndCompareBase64_A(testsNoCR[i].base64, CERT_REQUEST_HEADER,
524          CERT_REQUEST_TRAILER, CRYPT_STRING_BASE64REQUESTHEADER,
525          CRYPT_STRING_BASE64REQUESTHEADER, testsNoCR[i].toEncode,
526          testsNoCR[i].toEncodeLen);
527         decodeAndCompareBase64_A(testsNoCR[i].base64, X509_HEADER, X509_TRAILER,
528          CRYPT_STRING_BASE64X509CRLHEADER, CRYPT_STRING_BASE64X509CRLHEADER,
529          testsNoCR[i].toEncode, testsNoCR[i].toEncodeLen);
530         /* And check with the "any" formats */
531         decodeAndCompareBase64_A(testsNoCR[i].base64, NULL, NULL,
532          CRYPT_STRING_BASE64_ANY, CRYPT_STRING_BASE64, testsNoCR[i].toEncode,
533          testsNoCR[i].toEncodeLen);
534         /* Don't check with no header and the string_any format, that'll
535          * always succeed.
536          */
537         decodeAndCompareBase64_A(testsNoCR[i].base64, CERT_HEADER, CERT_TRAILER,
538          CRYPT_STRING_BASE64_ANY, CRYPT_STRING_BASE64HEADER,
539          testsNoCR[i].toEncode, testsNoCR[i].toEncodeLen);
540         decodeAndCompareBase64_A(testsNoCR[i].base64, CERT_HEADER, CERT_TRAILER,
541          CRYPT_STRING_ANY, CRYPT_STRING_BASE64HEADER, testsNoCR[i].toEncode,
542          testsNoCR[i].toEncodeLen);
543     }
544 }
545 
546 START_TEST(base64)
547 {
548     testBinaryToStringA();
549     testStringToBinaryA();
550 }
551