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