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 (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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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