1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/cmd/lib/derprint.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,590 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +#include "secutil.h" 1.8 +#include "secoid.h" 1.9 + 1.10 +#ifdef __sun 1.11 +extern int fprintf(FILE *strm, const char *format, .../* args */); 1.12 +extern int fflush(FILE *stream); 1.13 +#endif 1.14 + 1.15 +#define RIGHT_MARGIN 24 1.16 +/*#define RAW_BYTES 1 */ 1.17 + 1.18 +static int prettyColumn = 0; 1.19 + 1.20 +static int 1.21 +getInteger256(const unsigned char *data, unsigned int nb) 1.22 +{ 1.23 + int val; 1.24 + 1.25 + switch (nb) { 1.26 + case 1: 1.27 + val = data[0]; 1.28 + break; 1.29 + case 2: 1.30 + val = (data[0] << 8) | data[1]; 1.31 + break; 1.32 + case 3: 1.33 + val = (data[0] << 16) | (data[1] << 8) | data[2]; 1.34 + break; 1.35 + case 4: 1.36 + val = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; 1.37 + break; 1.38 + default: 1.39 + PORT_SetError(SEC_ERROR_BAD_DER); 1.40 + return -1; 1.41 + } 1.42 + 1.43 + return val; 1.44 +} 1.45 + 1.46 +static int 1.47 +prettyNewline(FILE *out) 1.48 +{ 1.49 + int rv; 1.50 + 1.51 + if (prettyColumn != -1) { 1.52 + rv = fprintf(out, "\n"); 1.53 + prettyColumn = -1; 1.54 + if (rv < 0) { 1.55 + PORT_SetError(SEC_ERROR_IO); 1.56 + return rv; 1.57 + } 1.58 + } 1.59 + return 0; 1.60 +} 1.61 + 1.62 +static int 1.63 +prettyIndent(FILE *out, unsigned level) 1.64 +{ 1.65 + unsigned int i; 1.66 + int rv; 1.67 + 1.68 + if (prettyColumn == -1) { 1.69 + prettyColumn = level; 1.70 + for (i = 0; i < level; i++) { 1.71 + rv = fprintf(out, " "); 1.72 + if (rv < 0) { 1.73 + PORT_SetError(SEC_ERROR_IO); 1.74 + return rv; 1.75 + } 1.76 + } 1.77 + } 1.78 + 1.79 + return 0; 1.80 +} 1.81 + 1.82 +static int 1.83 +prettyPrintByte(FILE *out, unsigned char item, unsigned int level) 1.84 +{ 1.85 + int rv; 1.86 + 1.87 + rv = prettyIndent(out, level); 1.88 + if (rv < 0) 1.89 + return rv; 1.90 + 1.91 + rv = fprintf(out, "%02x ", item); 1.92 + if (rv < 0) { 1.93 + PORT_SetError(SEC_ERROR_IO); 1.94 + return rv; 1.95 + } 1.96 + 1.97 + prettyColumn++; 1.98 + if (prettyColumn >= RIGHT_MARGIN) { 1.99 + return prettyNewline(out); 1.100 + } 1.101 + 1.102 + return 0; 1.103 +} 1.104 + 1.105 +static int 1.106 +prettyPrintLeaf(FILE *out, const unsigned char *data, 1.107 + unsigned int len, unsigned int lv) 1.108 +{ 1.109 + unsigned int i; 1.110 + int rv; 1.111 + 1.112 + for (i = 0; i < len; i++) { 1.113 + rv = prettyPrintByte(out, *data++, lv); 1.114 + if (rv < 0) 1.115 + return rv; 1.116 + } 1.117 + return prettyNewline(out); 1.118 +} 1.119 + 1.120 +static int 1.121 +prettyPrintStringStart(FILE *out, const unsigned char *str, 1.122 + unsigned int len, unsigned int level) 1.123 +{ 1.124 +#define BUF_SIZE 100 1.125 + unsigned char buf[BUF_SIZE]; 1.126 + int rv; 1.127 + 1.128 + if (len >= BUF_SIZE) 1.129 + len = BUF_SIZE - 1; 1.130 + 1.131 + rv = prettyNewline(out); 1.132 + if (rv < 0) 1.133 + return rv; 1.134 + 1.135 + rv = prettyIndent(out, level); 1.136 + if (rv < 0) 1.137 + return rv; 1.138 + 1.139 + memcpy(buf, str, len); 1.140 + buf[len] = '\000'; 1.141 + 1.142 + rv = fprintf(out, "\"%s\"", buf); 1.143 + if (rv < 0) { 1.144 + PORT_SetError(SEC_ERROR_IO); 1.145 + return rv; 1.146 + } 1.147 + 1.148 + return 0; 1.149 +#undef BUF_SIZE 1.150 +} 1.151 + 1.152 +static int 1.153 +prettyPrintString(FILE *out, const unsigned char *str, 1.154 + unsigned int len, unsigned int level, PRBool raw) 1.155 +{ 1.156 + int rv; 1.157 + 1.158 + rv = prettyPrintStringStart(out, str, len, level); 1.159 + if (rv < 0) 1.160 + return rv; 1.161 + 1.162 + rv = prettyNewline(out); 1.163 + if (rv < 0) 1.164 + return rv; 1.165 + 1.166 + if (raw) { 1.167 + rv = prettyPrintLeaf(out, str, len, level); 1.168 + if (rv < 0) 1.169 + return rv; 1.170 + } 1.171 + 1.172 + return 0; 1.173 +} 1.174 + 1.175 +static int 1.176 +prettyPrintTime(FILE *out, const unsigned char *str, 1.177 + unsigned int len, unsigned int level, PRBool raw, PRBool utc) 1.178 +{ 1.179 + SECItem time_item; 1.180 + int rv; 1.181 + 1.182 + rv = prettyPrintStringStart(out, str, len, level); 1.183 + if (rv < 0) 1.184 + return rv; 1.185 + 1.186 + time_item.data = (unsigned char *)str; 1.187 + time_item.len = len; 1.188 + 1.189 + rv = fprintf(out, " ("); 1.190 + if (rv < 0) { 1.191 + PORT_SetError(SEC_ERROR_IO); 1.192 + return rv; 1.193 + } 1.194 + 1.195 + if (utc) 1.196 + SECU_PrintUTCTime(out, &time_item, NULL, 0); 1.197 + else 1.198 + SECU_PrintGeneralizedTime(out, &time_item, NULL, 0); 1.199 + 1.200 + rv = fprintf(out, ")"); 1.201 + if (rv < 0) { 1.202 + PORT_SetError(SEC_ERROR_IO); 1.203 + return rv; 1.204 + } 1.205 + 1.206 + rv = prettyNewline(out); 1.207 + if (rv < 0) 1.208 + return rv; 1.209 + 1.210 + if (raw) { 1.211 + rv = prettyPrintLeaf(out, str, len, level); 1.212 + if (rv < 0) 1.213 + return rv; 1.214 + } 1.215 + 1.216 + return 0; 1.217 +} 1.218 + 1.219 +static int 1.220 +prettyPrintObjectID(FILE *out, const unsigned char *data, 1.221 + unsigned int len, unsigned int level, PRBool raw) 1.222 +{ 1.223 + SECOidData *oiddata; 1.224 + SECItem oiditem; 1.225 + unsigned int i; 1.226 + unsigned long val; 1.227 + int rv; 1.228 + 1.229 + 1.230 + /* 1.231 + * First print the Object Id in numeric format 1.232 + */ 1.233 + 1.234 + rv = prettyIndent(out, level); 1.235 + if (rv < 0) 1.236 + return rv; 1.237 + 1.238 + val = data[0]; 1.239 + i = val % 40; 1.240 + val = val / 40; 1.241 + rv = fprintf(out, "%lu %u ", val, i); 1.242 + if (rv < 0) { 1.243 + PORT_SetError(SEC_ERROR_IO); 1.244 + return rv; 1.245 + } 1.246 + 1.247 + val = 0; 1.248 + for (i = 1; i < len; ++i) { 1.249 + unsigned long j; 1.250 + 1.251 + j = data[i]; 1.252 + val = (val << 7) | (j & 0x7f); 1.253 + if (j & 0x80) 1.254 + continue; 1.255 + rv = fprintf(out, "%lu ", val); 1.256 + if (rv < 0) { 1.257 + PORT_SetError(SEC_ERROR_IO); 1.258 + return rv; 1.259 + } 1.260 + val = 0; 1.261 + } 1.262 + 1.263 + /* 1.264 + * Now try to look it up and print a symbolic version. 1.265 + */ 1.266 + oiditem.data = (unsigned char *)data; 1.267 + oiditem.len = len; 1.268 + oiddata = SECOID_FindOID(&oiditem); 1.269 + if (oiddata != NULL) { 1.270 + i = PORT_Strlen(oiddata->desc); 1.271 + if ((prettyColumn + 1 + (i / 3)) > RIGHT_MARGIN) { 1.272 + rv = prettyNewline(out); 1.273 + if (rv < 0) 1.274 + return rv; 1.275 + } 1.276 + 1.277 + rv = prettyIndent(out, level); 1.278 + if (rv < 0) 1.279 + return rv; 1.280 + 1.281 + rv = fprintf(out, "(%s)", oiddata->desc); 1.282 + if (rv < 0) { 1.283 + PORT_SetError(SEC_ERROR_IO); 1.284 + return rv; 1.285 + } 1.286 + } 1.287 + 1.288 + /* 1.289 + * Finally, on a new line, print the raw bytes (if requested). 1.290 + */ 1.291 + if (raw) { 1.292 + rv = prettyNewline(out); 1.293 + if (rv < 0) { 1.294 + PORT_SetError(SEC_ERROR_IO); 1.295 + return rv; 1.296 + } 1.297 + 1.298 + for (i = 0; i < len; i++) { 1.299 + rv = prettyPrintByte(out, *data++, level); 1.300 + if (rv < 0) 1.301 + return rv; 1.302 + } 1.303 + } 1.304 + 1.305 + return prettyNewline(out); 1.306 +} 1.307 + 1.308 +static char *prettyTagType [32] = { 1.309 + "End of Contents", 1.310 + "Boolean", 1.311 + "Integer", 1.312 + "Bit String", 1.313 + "Octet String", 1.314 + "NULL", 1.315 + "Object Identifier", 1.316 + "0x07", 1.317 + "0x08", 1.318 + "0x09", 1.319 + "Enumerated", 1.320 + "0x0B", 1.321 + "UTF8 String", 1.322 + "0x0D", 1.323 + "0x0E", 1.324 + "0x0F", 1.325 + "Sequence", 1.326 + "Set", 1.327 + "0x12", 1.328 + "Printable String", 1.329 + "T61 String", 1.330 + "0x15", 1.331 + "IA5 String", 1.332 + "UTC Time", 1.333 + "Generalized Time", 1.334 + "0x19", 1.335 + "Visible String", 1.336 + "0x1B", 1.337 + "Universal String", 1.338 + "0x1D", 1.339 + "BMP String", 1.340 + "High-Tag-Number" 1.341 +}; 1.342 + 1.343 +static int 1.344 +prettyPrintTag(FILE *out, const unsigned char *src, const unsigned char *end, 1.345 + unsigned char *codep, unsigned int level, PRBool raw) 1.346 +{ 1.347 + int rv; 1.348 + unsigned char code, tagnum; 1.349 + 1.350 + if (src >= end) { 1.351 + PORT_SetError(SEC_ERROR_BAD_DER); 1.352 + return -1; 1.353 + } 1.354 + 1.355 + code = *src; 1.356 + tagnum = code & SEC_ASN1_TAGNUM_MASK; 1.357 + 1.358 + /* 1.359 + * NOTE: This code does not (yet) handle the high-tag-number form! 1.360 + */ 1.361 + if (tagnum == SEC_ASN1_HIGH_TAG_NUMBER) { 1.362 + PORT_SetError(SEC_ERROR_BAD_DER); 1.363 + return -1; 1.364 + } 1.365 + 1.366 + if (raw) 1.367 + rv = prettyPrintByte(out, code, level); 1.368 + else 1.369 + rv = prettyIndent(out, level); 1.370 + 1.371 + if (rv < 0) 1.372 + return rv; 1.373 + 1.374 + if (code & SEC_ASN1_CONSTRUCTED) { 1.375 + rv = fprintf(out, "C-"); 1.376 + if (rv < 0) { 1.377 + PORT_SetError(SEC_ERROR_IO); 1.378 + return rv; 1.379 + } 1.380 + } 1.381 + 1.382 + switch (code & SEC_ASN1_CLASS_MASK) { 1.383 + case SEC_ASN1_UNIVERSAL: 1.384 + rv = fprintf(out, "%s ", prettyTagType[tagnum]); 1.385 + break; 1.386 + case SEC_ASN1_APPLICATION: 1.387 + rv = fprintf(out, "Application: %d ", tagnum); 1.388 + break; 1.389 + case SEC_ASN1_CONTEXT_SPECIFIC: 1.390 + rv = fprintf(out, "[%d] ", tagnum); 1.391 + break; 1.392 + case SEC_ASN1_PRIVATE: 1.393 + rv = fprintf(out, "Private: %d ", tagnum); 1.394 + break; 1.395 + } 1.396 + 1.397 + if (rv < 0) { 1.398 + PORT_SetError(SEC_ERROR_IO); 1.399 + return rv; 1.400 + } 1.401 + 1.402 + *codep = code; 1.403 + 1.404 + return 1; 1.405 +} 1.406 + 1.407 +static int 1.408 +prettyPrintLength(FILE *out, const unsigned char *data, const unsigned char *end, 1.409 + int *lenp, PRBool *indefinitep, unsigned int lv, PRBool raw) 1.410 +{ 1.411 + unsigned char lbyte; 1.412 + int lenLen; 1.413 + int rv; 1.414 + 1.415 + if (data >= end) { 1.416 + PORT_SetError(SEC_ERROR_BAD_DER); 1.417 + return -1; 1.418 + } 1.419 + 1.420 + rv = fprintf(out, " "); 1.421 + if (rv < 0) { 1.422 + PORT_SetError(SEC_ERROR_IO); 1.423 + return rv; 1.424 + } 1.425 + 1.426 + *indefinitep = PR_FALSE; 1.427 + 1.428 + lbyte = *data++; 1.429 + if (lbyte >= 0x80) { 1.430 + /* Multibyte length */ 1.431 + unsigned nb = (unsigned) (lbyte & 0x7f); 1.432 + if (nb > 4) { 1.433 + PORT_SetError(SEC_ERROR_BAD_DER); 1.434 + return -1; 1.435 + } 1.436 + if (nb > 0) { 1.437 + int il; 1.438 + 1.439 + if ((data + nb) > end) { 1.440 + PORT_SetError(SEC_ERROR_BAD_DER); 1.441 + return -1; 1.442 + } 1.443 + il = getInteger256(data, nb); 1.444 + if (il < 0) return -1; 1.445 + *lenp = (unsigned) il; 1.446 + } else { 1.447 + *lenp = 0; 1.448 + *indefinitep = PR_TRUE; 1.449 + } 1.450 + lenLen = nb + 1; 1.451 + if (raw) { 1.452 + int i; 1.453 + 1.454 + rv = prettyPrintByte(out, lbyte, lv); 1.455 + if (rv < 0) 1.456 + return rv; 1.457 + for (i = 0; i < nb; i++) { 1.458 + rv = prettyPrintByte(out, data[i], lv); 1.459 + if (rv < 0) 1.460 + return rv; 1.461 + } 1.462 + } 1.463 + } else { 1.464 + *lenp = lbyte; 1.465 + lenLen = 1; 1.466 + if (raw) { 1.467 + rv = prettyPrintByte(out, lbyte, lv); 1.468 + if (rv < 0) 1.469 + return rv; 1.470 + } 1.471 + } 1.472 + if (*indefinitep) 1.473 + rv = fprintf(out, "(indefinite)\n"); 1.474 + else 1.475 + rv = fprintf(out, "(%d)\n", *lenp); 1.476 + if (rv < 0) { 1.477 + PORT_SetError(SEC_ERROR_IO); 1.478 + return rv; 1.479 + } 1.480 + 1.481 + prettyColumn = -1; 1.482 + return lenLen; 1.483 +} 1.484 + 1.485 +static int 1.486 +prettyPrintItem(FILE *out, const unsigned char *data, const unsigned char *end, 1.487 + unsigned int lv, PRBool raw) 1.488 +{ 1.489 + int slen; 1.490 + int lenLen; 1.491 + const unsigned char *orig = data; 1.492 + int rv; 1.493 + 1.494 + while (data < end) { 1.495 + unsigned char code; 1.496 + PRBool indefinite; 1.497 + 1.498 + slen = prettyPrintTag(out, data, end, &code, lv, raw); 1.499 + if (slen < 0) 1.500 + return slen; 1.501 + data += slen; 1.502 + 1.503 + lenLen = prettyPrintLength(out, data, end, &slen, &indefinite, lv, raw); 1.504 + if (lenLen < 0) 1.505 + return lenLen; 1.506 + data += lenLen; 1.507 + 1.508 + /* 1.509 + * Just quit now if slen more bytes puts us off the end. 1.510 + */ 1.511 + if ((data + slen) > end) { 1.512 + PORT_SetError(SEC_ERROR_BAD_DER); 1.513 + return -1; 1.514 + } 1.515 + 1.516 + if (code & SEC_ASN1_CONSTRUCTED) { 1.517 + if (slen > 0 || indefinite) { 1.518 + slen = prettyPrintItem(out, data, 1.519 + slen == 0 ? end : data + slen, 1.520 + lv+1, raw); 1.521 + if (slen < 0) 1.522 + return slen; 1.523 + data += slen; 1.524 + } 1.525 + } else if (code == 0) { 1.526 + if (slen != 0 || lenLen != 1) { 1.527 + PORT_SetError(SEC_ERROR_BAD_DER); 1.528 + return -1; 1.529 + } 1.530 + break; 1.531 + } else { 1.532 + switch (code) { 1.533 + case SEC_ASN1_PRINTABLE_STRING: 1.534 + case SEC_ASN1_IA5_STRING: 1.535 + case SEC_ASN1_VISIBLE_STRING: 1.536 + rv = prettyPrintString(out, data, slen, lv+1, raw); 1.537 + if (rv < 0) 1.538 + return rv; 1.539 + break; 1.540 + case SEC_ASN1_UTC_TIME: 1.541 + rv = prettyPrintTime(out, data, slen, lv+1, raw, PR_TRUE); 1.542 + if (rv < 0) 1.543 + return rv; 1.544 + break; 1.545 + case SEC_ASN1_GENERALIZED_TIME: 1.546 + rv = prettyPrintTime(out, data, slen, lv+1, raw, PR_FALSE); 1.547 + if (rv < 0) 1.548 + return rv; 1.549 + break; 1.550 + case SEC_ASN1_OBJECT_ID: 1.551 + rv = prettyPrintObjectID(out, data, slen, lv+1, raw); 1.552 + if (rv < 0) 1.553 + return rv; 1.554 + break; 1.555 + case SEC_ASN1_BOOLEAN: /* could do nicer job */ 1.556 + case SEC_ASN1_INTEGER: /* could do nicer job */ 1.557 + case SEC_ASN1_BIT_STRING: /* could do nicer job */ 1.558 + case SEC_ASN1_OCTET_STRING: 1.559 + case SEC_ASN1_NULL: 1.560 + case SEC_ASN1_ENUMERATED: /* could do nicer job, as INTEGER */ 1.561 + case SEC_ASN1_UTF8_STRING: 1.562 + case SEC_ASN1_T61_STRING: /* print as printable string? */ 1.563 + case SEC_ASN1_UNIVERSAL_STRING: 1.564 + case SEC_ASN1_BMP_STRING: 1.565 + default: 1.566 + rv = prettyPrintLeaf(out, data, slen, lv+1); 1.567 + if (rv < 0) 1.568 + return rv; 1.569 + break; 1.570 + } 1.571 + data += slen; 1.572 + } 1.573 + } 1.574 + 1.575 + rv = prettyNewline(out); 1.576 + if (rv < 0) 1.577 + return rv; 1.578 + 1.579 + return data - orig; 1.580 +} 1.581 + 1.582 +SECStatus 1.583 +DER_PrettyPrint(FILE *out, const SECItem *it, PRBool raw) 1.584 +{ 1.585 + int rv; 1.586 + 1.587 + prettyColumn = -1; 1.588 + 1.589 + rv = prettyPrintItem(out, it->data, it->data + it->len, 0, raw); 1.590 + if (rv < 0) 1.591 + return SECFailure; 1.592 + return SECSuccess; 1.593 +}