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 } 1014