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