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