1 /* 2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 10 * All rights reserved. 11 * 12 * This package is an SSL implementation written 13 * by Eric Young (eay@cryptsoft.com). 14 * The implementation was written so as to conform with Netscapes SSL. 15 * 16 * This library is free for commercial and non-commercial use as long as 17 * the following conditions are aheared to. The following conditions 18 * apply to all code found in this distribution, be it the RC4, RSA, 19 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 20 * included with this distribution is covered by the same copyright terms 21 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 22 * 23 * Copyright remains Eric Young's, and as such any Copyright notices in 24 * the code are not to be removed. 25 * If this package is used in a product, Eric Young should be given attribution 26 * as the author of the parts of the library used. 27 * This can be in the form of a textual message at program startup or 28 * in documentation (online or textual) provided with the package. 29 * 30 * Redistribution and use in source and binary forms, with or without 31 * modification, are permitted provided that the following conditions 32 * are met: 33 * 1. Redistributions of source code must retain the copyright 34 * notice, this list of conditions and the following disclaimer. 35 * 2. Redistributions in binary form must reproduce the above copyright 36 * notice, this list of conditions and the following disclaimer in the 37 * documentation and/or other materials provided with the distribution. 38 * 3. All advertising materials mentioning features or use of this software 39 * must display the following acknowledgement: 40 * "This product includes cryptographic software written by 41 * Eric Young (eay@cryptsoft.com)" 42 * The word 'cryptographic' can be left out if the rouines from the library 43 * being used are not cryptographic related :-). 44 * 4. If you include any Windows specific code (or a derivative thereof) from 45 * the apps directory (application code) you must include an acknowledgement: 46 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 47 * 48 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 * 60 * The licence and distribution terms for any publically available version or 61 * derivative of this code cannot be changed. i.e. this code cannot simply be 62 * copied and put under another distribution licence 63 * [including the GNU Public Licence.] 64 */ 65 66 /* pem_encode.c - PEM encoding routines */ 67 68 #include <stdlib.h> 69 #include <strings.h> 70 #include <sys/types.h> 71 #include <kmfapi.h> 72 #include <pem_encode.h> 73 74 static unsigned char data_bin2ascii[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\ 75 abcdefghijklmnopqrstuvwxyz0123456789+/"; 76 77 static unsigned char data_ascii2bin[128] = { 78 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 79 0xFF, 0xE0, 0xF0, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 80 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 81 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 82 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 83 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xF2, 0xFF, 0x3F, 84 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 85 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 86 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 87 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 88 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 89 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 90 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 91 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 92 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 93 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 94 }; 95 96 #define conv_bin2ascii(a) (data_bin2ascii[(a)&0x3f]) 97 #define conv_ascii2bin(a) (data_ascii2bin[(a)&0x7f]) 98 99 100 void 101 PEM_EncodeInit(PEM_ENCODE_CTX *ctx) 102 { 103 ctx->length = 48; 104 ctx->num = 0; 105 ctx->line_num = 0; 106 } 107 108 int 109 PEM_EncodeBlock(unsigned char *t, const unsigned char *f, int dlen) 110 { 111 int i, ret = 0; 112 unsigned long l; 113 114 for (i = dlen; i > 0; i -= 3) { 115 if (i >= 3) { 116 l = (((unsigned long)f[0])<<16L)| 117 (((unsigned long)f[1])<< 8L)|f[2]; 118 *(t++) = conv_bin2ascii(l>>18L); 119 *(t++) = conv_bin2ascii(l>>12L); 120 *(t++) = conv_bin2ascii(l>> 6L); 121 *(t++) = conv_bin2ascii(l); 122 } else { 123 l = ((unsigned long)f[0])<<16L; 124 if (i == 2) 125 l |= ((unsigned long)f[1]<<8L); 126 127 *(t++) = conv_bin2ascii(l>>18L); 128 *(t++) = conv_bin2ascii(l>>12L); 129 *(t++) = (i == 1)?'=':conv_bin2ascii(l>> 6L); 130 *(t++) = '='; 131 } 132 ret += 4; 133 f += 3; 134 } 135 136 *t = '\0'; 137 return (ret); 138 } 139 140 void 141 PEM_EncodeUpdate(PEM_ENCODE_CTX *ctx, unsigned char *out, int *outl, 142 unsigned char *in, int inl) 143 { 144 int i, j; 145 unsigned int total = 0; 146 147 *outl = 0; 148 if (inl == 0) 149 return; 150 if ((ctx->num+inl) < ctx->length) { 151 (void) memcpy(&(ctx->enc_data[ctx->num]), in, inl); 152 ctx->num += inl; 153 return; 154 } 155 if (ctx->num != 0) { 156 i = ctx->length-ctx->num; 157 (void) memcpy(&(ctx->enc_data[ctx->num]), in, i); 158 in += i; 159 inl -= i; 160 j = PEM_EncodeBlock(out, ctx->enc_data, ctx->length); 161 ctx->num = 0; 162 out += j; 163 *(out++) = '\n'; 164 *out = '\0'; 165 total = j+1; 166 } 167 168 while (inl >= ctx->length) { 169 j = PEM_EncodeBlock(out, in, ctx->length); 170 in += ctx->length; 171 inl -= ctx->length; 172 out += j; 173 *(out++) = '\n'; 174 *out = '\0'; 175 total += j+1; 176 } 177 178 if (inl != 0) 179 (void) memcpy(&(ctx->enc_data[0]), in, inl); 180 ctx->num = inl; 181 *outl = total; 182 } 183 184 void 185 PEM_EncodeFinal(PEM_ENCODE_CTX *ctx, unsigned char *out, int *outl) 186 { 187 unsigned int ret = 0; 188 189 if (ctx->num != 0) { 190 ret = PEM_EncodeBlock(out, ctx->enc_data, ctx->num); 191 out[ret++] = '\n'; 192 out[ret] = '\0'; 193 ctx->num = 0; 194 } 195 *outl = ret; 196 } 197 198 KMF_RETURN 199 Der2Pem(KMF_OBJECT_TYPE type, unsigned char *data, 200 int len, unsigned char **out, int *outlen) 201 { 202 203 204 int nlen, n, i, j, outl; 205 unsigned char *buf = NULL, *p = NULL; 206 PEM_ENCODE_CTX ctx; 207 char *name = NULL; 208 209 if (data == NULL || len == 0 || out == NULL || outlen == NULL) 210 return (KMF_ERR_BAD_PARAMETER); 211 212 if (type == KMF_CERT) 213 name = PEM_STRING_X509; 214 else if (type == KMF_CSR) 215 name = PEM_STRING_X509_REQ; 216 else if (type == KMF_CRL) 217 name = PEM_STRING_X509_CRL; 218 else 219 return (KMF_ERR_BAD_OBJECT_TYPE); 220 221 222 PEM_EncodeInit(&ctx); 223 nlen = strlen(name); 224 225 buf = malloc(PEM_BUFSIZE*8); 226 if (buf == NULL) { 227 return (KMF_ERR_MEMORY); 228 } 229 230 p = buf; 231 (void) memcpy(p, "-----BEGIN ", 11); 232 p += 11; 233 (void) memcpy(p, name, nlen); 234 p += nlen; 235 (void) memcpy(p, "-----\n", 6); 236 p += 6; 237 238 i = j = 0; 239 while (len > 0) { 240 n = (int)((len > (PEM_BUFSIZE*5))?(PEM_BUFSIZE*5):len); 241 PEM_EncodeUpdate(&ctx, p, &outl, &(data[j]), n); 242 i += outl; 243 len -= n; 244 j += n; 245 p += outl; 246 } 247 248 PEM_EncodeFinal(&ctx, p, &outl); 249 250 if (outl > 0) 251 p += outl; 252 253 (void) memcpy(p, "-----END ", 9); 254 p += 9; 255 (void) memcpy(p, name, nlen); 256 p += nlen; 257 (void) memcpy(p, "-----\n", 6); 258 p += 6; 259 260 *out = buf; 261 *outlen = i+outl+nlen*2+11+6+9+6; 262 263 return (KMF_OK); 264 265 } 266 267 int 268 PEM_DecodeBlock(unsigned char *t, const unsigned char *f, int n) 269 { 270 int i, ret = 0, a, b, c, d; 271 unsigned long l; 272 273 /* trim white space from the start of the line. */ 274 while ((conv_ascii2bin(*f) == B64_WS) && (n > 0)) { 275 f++; 276 n--; 277 } 278 279 /* 280 * strip off stuff at the end of the line 281 * ascii2bin values B64_WS, B64_EOLN, B64_EOLN and B64_EOF 282 */ 283 while ((n > 3) && (B64_NOT_BASE64(conv_ascii2bin(f[n-1])))) 284 n--; 285 286 if (n%4 != 0) { 287 return (-1); 288 } 289 290 for (i = 0; i < n; i += 4) { 291 a = conv_ascii2bin(*(f++)); 292 b = conv_ascii2bin(*(f++)); 293 c = conv_ascii2bin(*(f++)); 294 d = conv_ascii2bin(*(f++)); 295 if ((a & 0x80) || (b & 0x80) || (c & 0x80) || (d & 0x80)) 296 return (-1); 297 l = ((((unsigned long)a)<<18L) | (((unsigned long)b)<<12L) | 298 (((unsigned long)c)<< 6L) | (((unsigned long)d))); 299 *(t++) = (unsigned char)(l>>16L)&0xff; 300 *(t++) = (unsigned char)(l>> 8L)&0xff; 301 *(t++) = (unsigned char)(l)&0xff; 302 ret += 3; 303 } 304 return (ret); 305 } 306 307 void 308 PEM_DecodeInit(PEM_ENCODE_CTX *ctx) 309 { 310 ctx->length = 30; 311 ctx->num = 0; 312 ctx->line_num = 0; 313 ctx->expect_nl = 0; 314 } 315 316 /* 317 * -1 for error 318 * 0 for last line 319 * 1 for full line 320 */ 321 int 322 PEM_DecodeUpdate(PEM_ENCODE_CTX *ctx, unsigned char *out, int *outl, 323 unsigned char *in, int inl) 324 { 325 int seof = -1, eof = 0, rv = -1, ret = 0; 326 int i, v, tmp, n, ln, exp_nl; 327 unsigned char *d; 328 329 n = ctx->num; 330 d = ctx->enc_data; 331 ln = ctx->line_num; 332 exp_nl = ctx->expect_nl; 333 334 /* last line of input. */ 335 if ((inl == 0) || ((n == 0) && (conv_ascii2bin(in[0]) == B64_EOF))) { 336 rv = 0; 337 goto end; 338 } 339 340 /* We parse the input data */ 341 for (i = 0; i < inl; i++) { 342 /* If the current line is > 80 characters, scream alot */ 343 if (ln >= 80) { 344 rv = -1; 345 goto end; 346 } 347 348 /* Get char and put it into the buffer */ 349 tmp = *(in++); 350 v = conv_ascii2bin(tmp); 351 /* only save the good data :-) */ 352 if (!B64_NOT_BASE64(v)) { 353 d[n++] = tmp; 354 ln++; 355 } else if (v == B64_ERROR) { 356 rv = -1; 357 goto end; 358 } 359 360 /* 361 * have we seen a '=' which is 'definitly' the last 362 * input line. seof will point to the character that 363 * holds it. and eof will hold how many characters to 364 * chop off. 365 */ 366 if (tmp == '=') { 367 if (seof == -1) seof = n; 368 eof++; 369 } 370 371 if (v == B64_CR) { 372 ln = 0; 373 if (exp_nl) 374 continue; 375 } 376 377 /* eoln */ 378 if (v == B64_EOLN) { 379 ln = 0; 380 if (exp_nl) { 381 exp_nl = 0; 382 continue; 383 } 384 } 385 exp_nl = 0; 386 387 /* 388 * If we are at the end of input and it looks like a 389 * line, process it. 390 */ 391 if (((i+1) == inl) && (((n&3) == 0) || eof)) { 392 v = B64_EOF; 393 /* 394 * In case things were given us in really small 395 * records (so two '=' were given in separate 396 * updates), eof may contain the incorrect number 397 * of ending bytes to skip, so let's redo the count 398 */ 399 eof = 0; 400 if (d[n-1] == '=') eof++; 401 if (d[n-2] == '=') eof++; 402 /* There will never be more than two '=' */ 403 } 404 405 if ((v == B64_EOF) || (n >= 64)) { 406 /* 407 * This is needed to work correctly on 64 byte input 408 * lines. We process the line and then need to 409 * accept the '\n' 410 */ 411 if ((v != B64_EOF) && (n >= 64)) 412 exp_nl = 1; 413 if (n > 0) { 414 v = PEM_DecodeBlock(out, d, n); 415 if (v < 0) { 416 rv = 0; 417 goto end; 418 } 419 n = 0; 420 ret += (v-eof); 421 } else { 422 eof = 1; 423 v = 0; 424 } 425 426 /* 427 * This is the case where we have had a short 428 * but valid input line 429 */ 430 if ((v < ctx->length) && eof) { 431 rv = 0; 432 goto end; 433 } else 434 ctx->length = v; 435 436 if (seof >= 0) { 437 rv = 0; 438 goto end; 439 } 440 out += v; 441 } 442 } 443 rv = 1; 444 end: 445 *outl = ret; 446 ctx->num = n; 447 ctx->line_num = ln; 448 ctx->expect_nl = exp_nl; 449 return (rv); 450 } 451 452 int 453 PEM_DecodeFinal(PEM_ENCODE_CTX *ctx, unsigned char *out, int *outl) 454 { 455 int i; 456 457 *outl = 0; 458 if (ctx->num != 0) { 459 i = PEM_DecodeBlock(out, ctx->enc_data, ctx->num); 460 if (i < 0) 461 return (-1); 462 ctx->num = 0; 463 *outl = i; 464 return (1); 465 } else 466 return (1); 467 } 468 469 static int 470 get_line(unsigned char *in, int inlen, char *buf, int buflen) 471 { 472 int i = 0; 473 474 while ((i < inlen) && (i < buflen) && (in[i] != '\n')) { 475 buf[i] = in[i]; 476 i++; 477 } 478 479 return (i); 480 } 481 482 KMF_RETURN 483 Pem2Der(unsigned char *in, int inlen, 484 unsigned char **out, int *outlen) 485 { 486 int kmf_rv = 0; 487 PEM_ENCODE_CTX ctx; 488 int i, j, k, bl = 0; 489 char buf[2048]; 490 char *nameB = NULL; 491 unsigned char *dataB = NULL; 492 int total = 0; 493 494 if (in == NULL || inlen == 0 || out == NULL) 495 return (KMF_ERR_BAD_PARAMETER); 496 497 (void) memset(buf, 0, sizeof (buf)); 498 499 while (total < inlen) { 500 /* 501 * get a line (ended at '\n'), which returns 502 * number of bytes in the line 503 */ 504 i = get_line(in + total, inlen - total, buf, sizeof (buf)); 505 if (i == 0) { 506 kmf_rv = KMF_ERR_ENCODING; 507 goto err; 508 } 509 510 j = i; 511 while ((j >= 0) && (buf[j] <= ' ')) j--; 512 buf[++j] = '\n'; 513 buf[++j] = '\0'; 514 515 total += i + 1; 516 517 if (strncmp(buf, "-----BEGIN ", 11) == 0) { 518 i = strlen(&(buf[11])); 519 if (strncmp(&(buf[11+i-6]), "-----\n", 6) != 0) { 520 continue; 521 } 522 523 if ((nameB = malloc(i+9)) == NULL) { 524 kmf_rv = KMF_ERR_MEMORY; 525 goto err; 526 } 527 528 (void) memcpy(nameB, &(buf[11]), i-6); 529 nameB[i-6] = '\0'; 530 break; 531 } 532 } 533 534 bl = 0; 535 if ((dataB = malloc(2048)) == NULL) { 536 kmf_rv = KMF_ERR_MEMORY; 537 goto err; 538 } 539 540 dataB[0] = '\0'; 541 542 while (total < inlen) { 543 (void) memset(buf, 0, 1024); 544 i = get_line(in+total, inlen - total, buf, sizeof (buf)); 545 546 if (i == 0) break; 547 548 j = i; 549 while ((j >= 0) && (buf[j] <= ' ')) 550 j--; 551 552 buf[++j] = '\n'; 553 buf[++j] = '\0'; 554 total += i + 1; 555 556 if (buf[0] == '\n') break; 557 if ((dataB = realloc(dataB, bl+j+9)) == NULL) { 558 kmf_rv = KMF_ERR_MEMORY; 559 goto err; 560 } 561 562 if (strncmp(buf, "-----END ", 9) == 0) { 563 break; 564 } 565 566 (void) memcpy(&(dataB[bl]), buf, j); 567 dataB[bl+j] = '\0'; 568 bl += j; 569 } 570 571 if (nameB == NULL) 572 goto err; 573 574 i = strlen(nameB); 575 if ((strncmp(buf, "-----END ", 9) != 0) || 576 (strncmp(nameB, &(buf[9]), i) != 0) || 577 (strncmp(&(buf[9+i]), "-----", 5) != 0)) { 578 kmf_rv = KMF_ERR_ENCODING; 579 goto err; 580 } 581 582 PEM_DecodeInit(&ctx); 583 i = PEM_DecodeUpdate(&ctx, 584 (unsigned char *)dataB, &bl, (unsigned char *)dataB, bl); 585 586 if (i < 0) { 587 kmf_rv = KMF_ERR_ENCODING; 588 goto err; 589 } 590 591 i = PEM_DecodeFinal(&ctx, (unsigned char *)&(dataB[bl]), &k); 592 if (i < 0) { 593 kmf_rv = KMF_ERR_ENCODING; 594 goto err; 595 } 596 bl += k; 597 598 if (bl == 0) goto err; 599 *out = (unsigned char *)dataB; 600 *outlen = bl; 601 602 err: 603 if (nameB != NULL) 604 free(nameB); 605 if (kmf_rv != KMF_OK && dataB != NULL) 606 free(dataB); 607 608 return (kmf_rv); 609 } 610