security/nss/cmd/lib/derprint.c

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     4 #include "secutil.h"
     5 #include "secoid.h"
     7 #ifdef __sun
     8 extern int fprintf(FILE *strm, const char *format, .../* args */);
     9 extern int fflush(FILE *stream);
    10 #endif
    12 #define RIGHT_MARGIN	24
    13 /*#define RAW_BYTES 1 */
    15 static int prettyColumn = 0;
    17 static int
    18 getInteger256(const unsigned char *data, unsigned int nb)
    19 {
    20     int val;
    22     switch (nb) {
    23       case 1:
    24 	val = data[0];
    25 	break;
    26       case 2:
    27 	val = (data[0] << 8) | data[1];
    28 	break;
    29       case 3:
    30 	val = (data[0] << 16) | (data[1] << 8) | data[2];
    31 	break;
    32       case 4:
    33 	val = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
    34 	break;
    35       default:
    36 	PORT_SetError(SEC_ERROR_BAD_DER);
    37 	return -1;
    38     }
    40     return val;
    41 }
    43 static int
    44 prettyNewline(FILE *out)
    45 {
    46     int rv;
    48     if (prettyColumn != -1) {
    49 	rv = fprintf(out, "\n");
    50 	prettyColumn = -1;
    51 	if (rv < 0) {
    52 	    PORT_SetError(SEC_ERROR_IO);
    53 	    return rv;
    54 	}
    55     }
    56     return 0;
    57 }
    59 static int
    60 prettyIndent(FILE *out, unsigned level)
    61 {
    62     unsigned int i;
    63     int rv;
    65     if (prettyColumn == -1) {
    66 	prettyColumn = level;
    67 	for (i = 0; i < level; i++) {
    68 	    rv = fprintf(out, "   ");
    69 	    if (rv < 0) {
    70 		PORT_SetError(SEC_ERROR_IO);
    71 		return rv;
    72 	    }
    73 	}
    74     }
    76     return 0;
    77 }
    79 static int
    80 prettyPrintByte(FILE *out, unsigned char item, unsigned int level)
    81 {
    82     int rv;
    84     rv = prettyIndent(out, level);
    85     if (rv < 0)
    86 	return rv;
    88     rv = fprintf(out, "%02x ", item);
    89     if (rv < 0) {
    90 	PORT_SetError(SEC_ERROR_IO);
    91 	return rv;
    92     }
    94     prettyColumn++;
    95     if (prettyColumn >= RIGHT_MARGIN) {
    96 	return prettyNewline(out);
    97     }
    99     return 0;
   100 }
   102 static int
   103 prettyPrintLeaf(FILE *out, const unsigned char *data,
   104 		unsigned int len, unsigned int lv)
   105 {
   106     unsigned int i;
   107     int rv;
   109     for (i = 0; i < len; i++) {
   110 	rv = prettyPrintByte(out, *data++, lv);
   111 	if (rv < 0)
   112 	    return rv;
   113     }
   114     return prettyNewline(out);
   115 }
   117 static int
   118 prettyPrintStringStart(FILE *out, const unsigned char *str,
   119 		       unsigned int len, unsigned int level)
   120 {
   121 #define BUF_SIZE 100
   122     unsigned char buf[BUF_SIZE];
   123     int rv;
   125     if (len >= BUF_SIZE)
   126 	len = BUF_SIZE - 1;
   128     rv = prettyNewline(out);
   129     if (rv < 0)
   130 	return rv;
   132     rv = prettyIndent(out, level);
   133     if (rv < 0)
   134 	return rv;
   136     memcpy(buf, str, len);
   137     buf[len] = '\000';
   139     rv = fprintf(out, "\"%s\"", buf);
   140     if (rv < 0) {
   141 	PORT_SetError(SEC_ERROR_IO);
   142 	return rv;
   143     }
   145     return 0;
   146 #undef BUF_SIZE
   147 }
   149 static int
   150 prettyPrintString(FILE *out, const unsigned char *str,
   151 		  unsigned int len, unsigned int level, PRBool raw)
   152 {
   153     int rv;
   155     rv = prettyPrintStringStart(out, str, len, level);
   156     if (rv < 0)
   157 	return rv;
   159     rv = prettyNewline(out);
   160     if (rv < 0)
   161 	return rv;
   163     if (raw) {
   164 	rv = prettyPrintLeaf(out, str, len, level);
   165 	if (rv < 0)
   166 	    return rv;
   167     }
   169     return 0;
   170 }
   172 static int
   173 prettyPrintTime(FILE *out, const unsigned char *str,
   174 		unsigned int len, unsigned int level, PRBool raw, PRBool utc)
   175 {
   176     SECItem time_item;
   177     int rv;
   179     rv = prettyPrintStringStart(out, str, len, level);
   180     if (rv < 0)
   181 	return rv;
   183     time_item.data = (unsigned char *)str;
   184     time_item.len = len;
   186     rv = fprintf(out, " (");
   187     if (rv < 0) {
   188 	PORT_SetError(SEC_ERROR_IO);
   189 	return rv;
   190     }
   192     if (utc)
   193 	SECU_PrintUTCTime(out, &time_item, NULL, 0);
   194     else
   195 	SECU_PrintGeneralizedTime(out, &time_item, NULL, 0);
   197     rv = fprintf(out, ")");
   198     if (rv < 0) {
   199 	PORT_SetError(SEC_ERROR_IO);
   200 	return rv;
   201     }
   203     rv = prettyNewline(out);
   204     if (rv < 0)
   205 	return rv;
   207     if (raw) {
   208 	rv = prettyPrintLeaf(out, str, len, level);
   209 	if (rv < 0)
   210 	    return rv;
   211     }
   213     return 0;
   214 }
   216 static int
   217 prettyPrintObjectID(FILE *out, const unsigned char *data,
   218 		    unsigned int len, unsigned int level, PRBool raw)
   219 {
   220     SECOidData *oiddata;
   221     SECItem oiditem;
   222     unsigned int i;
   223     unsigned long val;
   224     int rv;
   227     /*
   228      * First print the Object Id in numeric format
   229      */
   231     rv = prettyIndent(out, level);
   232     if (rv < 0)
   233 	return rv;
   235     val = data[0];
   236     i   = val % 40;
   237     val = val / 40;
   238     rv = fprintf(out, "%lu %u ", val, i);
   239     if (rv < 0) {
   240 	PORT_SetError(SEC_ERROR_IO);
   241 	return rv;
   242     }
   244     val = 0;
   245     for (i = 1; i < len; ++i) {
   246         unsigned long j;
   248 	j = data[i];
   249 	val = (val << 7) | (j & 0x7f);
   250 	if (j & 0x80) 
   251 	    continue;
   252 	rv = fprintf(out, "%lu ", val);
   253 	if (rv < 0) {
   254 	    PORT_SetError(SEC_ERROR_IO);
   255 	    return rv;
   256 	}
   257 	val = 0;
   258     }
   260     /*
   261      * Now try to look it up and print a symbolic version.
   262      */
   263     oiditem.data = (unsigned char *)data;
   264     oiditem.len = len;
   265     oiddata = SECOID_FindOID(&oiditem);
   266     if (oiddata != NULL) {
   267 	i = PORT_Strlen(oiddata->desc);
   268 	if ((prettyColumn + 1 + (i / 3)) > RIGHT_MARGIN) {
   269 	    rv = prettyNewline(out);
   270 	    if (rv < 0)
   271 		return rv;
   272 	}
   274 	rv = prettyIndent(out, level);
   275 	if (rv < 0)
   276 	    return rv;
   278 	rv = fprintf(out, "(%s)", oiddata->desc);
   279 	if (rv < 0) {
   280 	    PORT_SetError(SEC_ERROR_IO);
   281 	    return rv;
   282 	}
   283     }
   285     /*
   286      * Finally, on a new line, print the raw bytes (if requested).
   287      */
   288     if (raw) {
   289 	rv = prettyNewline(out);
   290 	if (rv < 0) {
   291 	    PORT_SetError(SEC_ERROR_IO);
   292 	    return rv;
   293 	}
   295 	for (i = 0; i < len; i++) {
   296 	    rv = prettyPrintByte(out, *data++, level);
   297 	    if (rv < 0)
   298 		return rv;
   299 	}
   300     }
   302     return prettyNewline(out);
   303 }
   305 static char *prettyTagType [32] = {
   306   "End of Contents",
   307   "Boolean",
   308   "Integer",
   309   "Bit String",
   310   "Octet String",
   311   "NULL",
   312   "Object Identifier",
   313   "0x07",
   314   "0x08",
   315   "0x09",
   316   "Enumerated",
   317   "0x0B",
   318   "UTF8 String",
   319   "0x0D",
   320   "0x0E",
   321   "0x0F",
   322   "Sequence",
   323   "Set",
   324   "0x12",
   325   "Printable String",
   326   "T61 String",
   327   "0x15",
   328   "IA5 String",
   329   "UTC Time",
   330   "Generalized Time",
   331   "0x19",
   332   "Visible String",
   333   "0x1B",
   334   "Universal String",
   335   "0x1D",
   336   "BMP String",
   337   "High-Tag-Number"
   338 };
   340 static int
   341 prettyPrintTag(FILE *out, const unsigned char *src, const unsigned char *end,
   342 	       unsigned char *codep, unsigned int level, PRBool raw)
   343 {
   344     int rv;
   345     unsigned char code, tagnum;
   347     if (src >= end) {
   348 	PORT_SetError(SEC_ERROR_BAD_DER);
   349 	return -1;
   350     }
   352     code = *src;
   353     tagnum = code & SEC_ASN1_TAGNUM_MASK;
   355     /*
   356      * NOTE: This code does not (yet) handle the high-tag-number form!
   357      */
   358     if (tagnum == SEC_ASN1_HIGH_TAG_NUMBER) {
   359         PORT_SetError(SEC_ERROR_BAD_DER);
   360 	return -1;
   361     }
   363     if (raw)
   364 	rv = prettyPrintByte(out, code, level);
   365     else
   366 	rv = prettyIndent(out, level);
   368     if (rv < 0)
   369 	return rv;
   371     if (code & SEC_ASN1_CONSTRUCTED) {
   372         rv = fprintf(out, "C-");
   373 	if (rv < 0) {
   374 	    PORT_SetError(SEC_ERROR_IO);
   375 	    return rv;
   376 	}
   377     }
   379     switch (code & SEC_ASN1_CLASS_MASK) {
   380     case SEC_ASN1_UNIVERSAL:
   381         rv = fprintf(out, "%s ", prettyTagType[tagnum]);
   382 	break;
   383     case SEC_ASN1_APPLICATION:
   384         rv = fprintf(out, "Application: %d ", tagnum);
   385 	break;
   386     case SEC_ASN1_CONTEXT_SPECIFIC:
   387         rv = fprintf(out, "[%d] ", tagnum);
   388 	break;
   389     case SEC_ASN1_PRIVATE:
   390         rv = fprintf(out, "Private: %d ", tagnum);
   391 	break;
   392     }
   394     if (rv < 0) {
   395         PORT_SetError(SEC_ERROR_IO);
   396 	return rv;
   397     }
   399     *codep = code;
   401     return 1;
   402 }
   404 static int
   405 prettyPrintLength(FILE *out, const unsigned char *data, const unsigned char *end,
   406 		  int *lenp, PRBool *indefinitep, unsigned int lv, PRBool raw)
   407 {
   408     unsigned char lbyte;
   409     int lenLen;
   410     int rv;
   412     if (data >= end) {
   413 	PORT_SetError(SEC_ERROR_BAD_DER);
   414 	return -1;
   415     }
   417     rv = fprintf(out, " ");
   418     if (rv < 0) {
   419         PORT_SetError(SEC_ERROR_IO);
   420 	return rv;
   421     }
   423     *indefinitep = PR_FALSE;
   425     lbyte = *data++;
   426     if (lbyte >= 0x80) {
   427 	/* Multibyte length */
   428 	unsigned nb = (unsigned) (lbyte & 0x7f);
   429 	if (nb > 4) {
   430 	    PORT_SetError(SEC_ERROR_BAD_DER);
   431 	    return -1;
   432 	}
   433 	if (nb > 0) {
   434 	    int il;
   436 	    if ((data + nb) > end) {
   437 		PORT_SetError(SEC_ERROR_BAD_DER);
   438 		return -1;
   439 	    }
   440 	    il = getInteger256(data, nb);
   441 	    if (il < 0) return -1;
   442 	    *lenp = (unsigned) il;
   443 	} else {
   444 	    *lenp = 0;
   445 	    *indefinitep = PR_TRUE;
   446 	}
   447 	lenLen = nb + 1;
   448 	if (raw) {
   449 	    int i;
   451 	    rv = prettyPrintByte(out, lbyte, lv);
   452 	    if (rv < 0)
   453 		return rv;
   454 	    for (i = 0; i < nb; i++) {
   455 		rv = prettyPrintByte(out, data[i], lv);
   456 		if (rv < 0)
   457 		    return rv;
   458 	    }
   459 	}
   460     } else {
   461 	*lenp = lbyte;
   462 	lenLen = 1;
   463 	if (raw) {
   464 	    rv = prettyPrintByte(out, lbyte, lv);
   465 	    if (rv < 0)
   466 		return rv;
   467 	}
   468     }
   469     if (*indefinitep)
   470 	rv = fprintf(out, "(indefinite)\n");
   471     else
   472 	rv = fprintf(out, "(%d)\n", *lenp);
   473     if (rv < 0) {
   474         PORT_SetError(SEC_ERROR_IO);
   475 	return rv;
   476     }
   478     prettyColumn = -1;
   479     return lenLen;
   480 }
   482 static int
   483 prettyPrintItem(FILE *out, const unsigned char *data, const unsigned char *end,
   484 		unsigned int lv, PRBool raw)
   485 {
   486     int slen;
   487     int lenLen;
   488     const unsigned char *orig = data;
   489     int rv;
   491     while (data < end) {
   492         unsigned char code;
   493 	PRBool indefinite;
   495 	slen = prettyPrintTag(out, data, end, &code, lv, raw);
   496 	if (slen < 0)
   497 	    return slen;
   498 	data += slen;
   500 	lenLen = prettyPrintLength(out, data, end, &slen, &indefinite, lv, raw);
   501 	if (lenLen < 0)
   502 	    return lenLen;
   503 	data += lenLen;
   505 	/*
   506 	 * Just quit now if slen more bytes puts us off the end.
   507 	 */
   508 	if ((data + slen) > end) {
   509 	    PORT_SetError(SEC_ERROR_BAD_DER);
   510 	    return -1;
   511 	}
   513         if (code & SEC_ASN1_CONSTRUCTED) {
   514 	    if (slen > 0 || indefinite) {
   515 		slen = prettyPrintItem(out, data,
   516 				       slen == 0 ? end : data + slen,
   517 				       lv+1, raw);
   518 		if (slen < 0)
   519 		    return slen;
   520 		data += slen;
   521 	    }
   522 	} else if (code == 0) {
   523 	    if (slen != 0 || lenLen != 1) {
   524 		PORT_SetError(SEC_ERROR_BAD_DER);
   525 		return -1;
   526 	    }
   527 	    break;
   528 	} else {
   529 	    switch (code) {
   530 	      case SEC_ASN1_PRINTABLE_STRING:
   531 	      case SEC_ASN1_IA5_STRING:
   532 	      case SEC_ASN1_VISIBLE_STRING:
   533 	        rv = prettyPrintString(out, data, slen, lv+1, raw);
   534 		if (rv < 0)
   535 		    return rv;
   536 		break;
   537 	      case SEC_ASN1_UTC_TIME:
   538 	        rv = prettyPrintTime(out, data, slen, lv+1, raw, PR_TRUE);
   539 		if (rv < 0)
   540 		    return rv;
   541 		break;
   542 	      case SEC_ASN1_GENERALIZED_TIME:
   543 	        rv = prettyPrintTime(out, data, slen, lv+1, raw, PR_FALSE);
   544 		if (rv < 0)
   545 		    return rv;
   546 		break;
   547 	      case SEC_ASN1_OBJECT_ID:
   548 	        rv = prettyPrintObjectID(out, data, slen, lv+1, raw);
   549 		if (rv < 0)
   550 		    return rv;
   551 		break;
   552 	      case SEC_ASN1_BOOLEAN:	/* could do nicer job */
   553 	      case SEC_ASN1_INTEGER:	/* could do nicer job */
   554 	      case SEC_ASN1_BIT_STRING:	/* could do nicer job */
   555 	      case SEC_ASN1_OCTET_STRING:
   556 	      case SEC_ASN1_NULL:
   557 	      case SEC_ASN1_ENUMERATED:	/* could do nicer job, as INTEGER */
   558 	      case SEC_ASN1_UTF8_STRING:
   559 	      case SEC_ASN1_T61_STRING:	/* print as printable string? */
   560 	      case SEC_ASN1_UNIVERSAL_STRING:
   561 	      case SEC_ASN1_BMP_STRING:
   562 	      default:
   563 	        rv = prettyPrintLeaf(out, data, slen, lv+1);
   564 		if (rv < 0)
   565 		    return rv;
   566 		break;
   567 	    }
   568 	    data += slen;
   569 	}
   570     }
   572     rv = prettyNewline(out);
   573     if (rv < 0)
   574 	return rv;
   576     return data - orig;
   577 }
   579 SECStatus
   580 DER_PrettyPrint(FILE *out, const SECItem *it, PRBool raw)
   581 {
   582     int rv;
   584     prettyColumn = -1;
   586     rv = prettyPrintItem(out, it->data, it->data + it->len, 0, raw);
   587     if (rv < 0)
   588 	return SECFailure;
   589     return SECSuccess;
   590 }

mercurial