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