1 /* 2 * Copyright 2007 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) || 296 (c & 0x80) || (d & 0x80)) 297 return (-1); 298 l = ((((unsigned long)a)<<18L)| 299 (((unsigned long)b)<<12L)| 300 (((unsigned long)c)<< 6L)| 301 (((unsigned long)d))); 302 *(t++) = (unsigned char)(l>>16L)&0xff; 303 *(t++) = (unsigned char)(l>> 8L)&0xff; 304 *(t++) = (unsigned char)(l)&0xff; 305 ret += 3; 306 } 307 return (ret); 308 } 309 310 void 311 PEM_DecodeInit(PEM_ENCODE_CTX *ctx) 312 { 313 ctx->length = 30; 314 ctx->num = 0; 315 ctx->line_num = 0; 316 ctx->expect_nl = 0; 317 } 318 319 /* 320 * -1 for error 321 * 0 for last line 322 * 1 for full line 323 */ 324 int 325 PEM_DecodeUpdate(PEM_ENCODE_CTX *ctx, unsigned char *out, int *outl, 326 unsigned char *in, int inl) 327 { 328 int seof = -1, eof = 0, rv = -1, ret = 0; 329 int i, v, tmp, n, ln, exp_nl; 330 unsigned char *d; 331 332 n = ctx->num; 333 d = ctx->enc_data; 334 ln = ctx->line_num; 335 exp_nl = ctx->expect_nl; 336 337 /* last line of input. */ 338 if ((inl == 0) || ((n == 0) && (conv_ascii2bin(in[0]) == B64_EOF))) { 339 rv = 0; 340 goto end; 341 } 342 343 /* We parse the input data */ 344 for (i = 0; i < inl; i++) { 345 /* If the current line is > 80 characters, scream alot */ 346 if (ln >= 80) { 347 rv = -1; 348 goto end; 349 } 350 351 /* Get char and put it into the buffer */ 352 tmp = *(in++); 353 v = conv_ascii2bin(tmp); 354 /* only save the good data :-) */ 355 if (!B64_NOT_BASE64(v)) { 356 d[n++] = tmp; 357 ln++; 358 } else if (v == B64_ERROR) { 359 rv = -1; 360 goto end; 361 } 362 363 /* 364 * have we seen a '=' which is 'definitly' the last 365 * input line. seof will point to the character that 366 * holds it. and eof will hold how many characters to 367 * chop off. 368 */ 369 if (tmp == '=') { 370 if (seof == -1) seof = n; 371 eof++; 372 } 373 374 if (v == B64_CR) { 375 ln = 0; 376 if (exp_nl) 377 continue; 378 } 379 380 /* eoln */ 381 if (v == B64_EOLN) { 382 ln = 0; 383 if (exp_nl) { 384 exp_nl = 0; 385 continue; 386 } 387 } 388 exp_nl = 0; 389 390 /* 391 * If we are at the end of input and it looks like a 392 * line, process it. 393 */ 394 if (((i+1) == inl) && (((n&3) == 0) || eof)) { 395 v = B64_EOF; 396 /* 397 * In case things were given us in really small 398 * records (so two '=' were given in separate 399 * updates), eof may contain the incorrect number 400 * of ending bytes to skip, so let's redo the count 401 */ 402 eof = 0; 403 if (d[n-1] == '=') eof++; 404 if (d[n-2] == '=') eof++; 405 /* There will never be more than two '=' */ 406 } 407 408 if ((v == B64_EOF) || (n >= 64)) { 409 /* 410 * This is needed to work correctly on 64 byte input 411 * lines. We process the line and then need to 412 * accept the '\n' 413 */ 414 if ((v != B64_EOF) && (n >= 64)) 415 exp_nl = 1; 416 if (n > 0) { 417 v = PEM_DecodeBlock(out, d, n); 418 if (v < 0) { 419 rv = 0; 420 goto end; 421 } 422 n = 0; 423 ret += (v-eof); 424 } else { 425 eof = 1; 426 v = 0; 427 } 428 429 /* 430 * This is the case where we have had a short 431 * but valid input line 432 */ 433 if ((v < ctx->length) && eof) { 434 rv = 0; 435 goto end; 436 } else 437 ctx->length = v; 438 439 if (seof >= 0) { 440 rv = 0; 441 goto end; 442 } 443 out += v; 444 } 445 } 446 rv = 1; 447 end: 448 *outl = ret; 449 ctx->num = n; 450 ctx->line_num = ln; 451 ctx->expect_nl = exp_nl; 452 return (rv); 453 } 454 455 int 456 PEM_DecodeFinal(PEM_ENCODE_CTX *ctx, unsigned char *out, int *outl) 457 { 458 int i; 459 460 *outl = 0; 461 if (ctx->num != 0) { 462 i = PEM_DecodeBlock(out, ctx->enc_data, ctx->num); 463 if (i < 0) 464 return (-1); 465 ctx->num = 0; 466 *outl = i; 467 return (1); 468 } else 469 return (1); 470 } 471 472 static int 473 get_line(unsigned char *in, char *buf) 474 { 475 476 int i = 0; 477 int len = 0; 478 479 while ((in[i] != '\n')) { 480 buf[i] = in[i]; 481 i++; 482 len++; 483 } 484 485 return (len); 486 } 487 488 KMF_RETURN 489 Pem2Der(unsigned char *in, int inlen, 490 unsigned char **out, int *outlen) 491 { 492 int kmf_rv = 0; 493 PEM_ENCODE_CTX ctx; 494 int i, k, bl = 0; 495 char buf[2048]; 496 char *nameB; 497 unsigned char *dataB; 498 int total = 0; 499 500 if (in == NULL || inlen == 0 || out == NULL) 501 return (KMF_ERR_BAD_PARAMETER); 502 503 (void) memset(buf, 0, sizeof (buf)); 504 505 for (;;) { 506 /* 507 * get a line (ended at '\n'), which returns 508 * number of bytes in the line 509 */ 510 i = get_line(in, buf); 511 if (i <= 0) { 512 kmf_rv = KMF_ERR_ENCODING; 513 goto err; 514 } 515 516 while ((i >= 0) && (buf[i] <= ' ')) i--; 517 buf[++i] = '\n'; 518 buf[++i] = '\0'; 519 total += i; 520 521 if (strncmp(buf, "-----BEGIN ", 11) == 0) { 522 i = strlen(&(buf[11])); 523 if (strncmp(&(buf[11+i-6]), "-----\n", 6) != 0) { 524 continue; 525 } 526 527 if ((nameB = malloc(i+9)) == NULL) { 528 kmf_rv = KMF_ERR_MEMORY; 529 goto err; 530 } 531 532 (void) memcpy(nameB, &(buf[11]), i-6); 533 nameB[i-6] = '\0'; 534 break; 535 } 536 } 537 538 bl = 0; 539 if ((dataB = malloc(2048)) == NULL) { 540 kmf_rv = KMF_ERR_MEMORY; 541 goto err; 542 } 543 544 dataB[0] = '\0'; 545 546 for (;;) { 547 (void) memset(buf, 0, 1024); 548 i = get_line(in+total, buf); 549 550 if (i <= 0) break; 551 552 while ((i >= 0) && (buf[i] <= ' ')) 553 i--; 554 555 buf[++i] = '\n'; 556 buf[++i] = '\0'; 557 total += i; 558 559 if (buf[0] == '\n') break; 560 if ((dataB = realloc(dataB, bl+i+9)) == NULL) { 561 kmf_rv = KMF_ERR_MEMORY; 562 goto err; 563 } 564 565 if (strncmp(buf, "-----END ", 9) == 0) { 566 break; 567 } 568 569 (void) memcpy(&(dataB[bl]), buf, i); 570 dataB[bl+i] = '\0'; 571 bl += i; 572 } 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 free(nameB); 604 if (kmf_rv != KMF_OK) 605 free(dataB); 606 607 return (kmf_rv); 608 } 609