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