JavaScript generic ASN.1 parser (mirror)
at github-7 7.1 kB view raw
1// ASN.1 JavaScript decoder 2// Copyright (c) 2008-2014 Lapo Luchini <lapo@lapo.it> 3 4// Permission to use, copy, modify, and/or distribute this software for any 5// purpose with or without fee is hereby granted, provided that the above 6// copyright notice and this permission notice appear in all copies. 7// 8// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 16/*jshint browser: true, strict: true, immed: true, latedef: true, undef: true, regexdash: false */ 17/*global oids, ASN1 */ 18(function (undefined) { 19"use strict"; 20 21var ASN1 = (typeof module !== 'undefined') ? require('./asn1.js') : window.ASN1, 22 lineLength = 80, 23 contentLength = 8 * lineLength, 24 DOM = { 25 ellipsis: "\u2026", 26 tag: function (tagName, className) { 27 var t = document.createElement(tagName); 28 t.className = className; 29 return t; 30 }, 31 text: function (str) { 32 return document.createTextNode(str); 33 }, 34 breakLines: function (str, length) { 35 var lines = str.split(/\r?\n/), 36 o = ''; 37 for (var i = 0; i < lines.length; ++i) { 38 var line = lines[i]; 39 if (i > 0) o += "\n"; 40 while (line.length > length) { 41 o += line.substring(0, length); 42 o += "\n"; 43 line = line.substring(length); 44 } 45 o += line; 46 } 47 return o; 48 } 49 }; 50 51ASN1.prototype.toDOM = function () { 52 var node = DOM.tag("div", "node"); 53 node.asn1 = this; 54 var head = DOM.tag("div", "head"); 55 var s = this.typeName().replace(/_/g, " "); 56 head.innerHTML = s; 57 var content = this.content(contentLength); 58 if (content !== null) { 59 var preview = DOM.tag("span", "preview"), 60 shortContent; 61 content = String(content); // it might be a number 62 shortContent = (content.length > lineLength) ? content.substring(0, lineLength) + DOM.ellipsis : content; 63 preview.appendChild(DOM.text(shortContent)); 64 head.appendChild(preview); 65 content = DOM.breakLines(content, lineLength); 66 content = content.replace(/</g, "&lt;"); 67 content = content.replace(/\n/g, "<br>"); 68 } 69 node.appendChild(head); 70 this.node = node; 71 this.head = head; 72 var value = DOM.tag("div", "value"); 73 s = "Offset: " + this.stream.pos + "<br>"; 74 s += "Length: " + this.header + "+"; 75 if (this.length >= 0) 76 s += this.length; 77 else 78 s += (-this.length) + " (undefined)"; 79 if (this.tag.tagConstructed) 80 s += "<br>(constructed)"; 81 else if ((this.tag.isUniversal() && ((this.tag.tagNumber == 0x03) || (this.tag.tagNumber == 0x04))) && (this.sub !== null)) 82 s += "<br>(encapsulates)"; 83 //TODO if (this.tag.isUniversal() && this.tag.tagNumber == 0x03) s += "Unused bits: " 84 if (content !== null) { 85 s += "<br>Value:<br><b>" + content + "</b>"; 86 if ((typeof oids === 'object') && (this.tag.isUniversal() && (this.tag.tagNumber == 0x06))) { 87 var oid = oids[content]; 88 if (oid) { 89 if (oid.d) s += "<br>" + oid.d; 90 if (oid.c) s += "<br>" + oid.c; 91 if (oid.w) s += "<br>(warning!)"; 92 } 93 } 94 } 95 value.innerHTML = s; 96 node.appendChild(value); 97 var sub = DOM.tag("div", "sub"); 98 if (this.sub !== null) { 99 for (var i = 0, max = this.sub.length; i < max; ++i) 100 sub.appendChild(this.sub[i].toDOM()); 101 } 102 node.appendChild(sub); 103 head.onclick = function () { 104 node.className = (node.className == "node collapsed") ? "node" : "node collapsed"; 105 }; 106 return node; 107}; 108ASN1.prototype.fakeHover = function (current) { 109 this.node.className += " hover"; 110 if (current) 111 this.head.className += " hover"; 112}; 113ASN1.prototype.fakeOut = function (current) { 114 var re = / ?hover/; 115 this.node.className = this.node.className.replace(re, ""); 116 if (current) 117 this.head.className = this.head.className.replace(re, ""); 118}; 119ASN1.prototype.toHexDOM_sub = function (node, className, stream, start, end) { 120 if (start >= end) 121 return; 122 var sub = DOM.tag("span", className); 123 sub.appendChild(DOM.text( 124 stream.hexDump(start, end))); 125 node.appendChild(sub); 126}; 127ASN1.prototype.toHexDOM = function (root) { 128 var node = DOM.tag("span", "hex"); 129 if (root === undefined) root = node; 130 this.head.hexNode = node; 131 this.head.onmouseover = function () { this.hexNode.className = "hexCurrent"; }; 132 this.head.onmouseout = function () { this.hexNode.className = "hex"; }; 133 node.asn1 = this; 134 node.onmouseover = function () { 135 var current = !root.selected; 136 if (current) { 137 root.selected = this.asn1; 138 this.className = "hexCurrent"; 139 } 140 this.asn1.fakeHover(current); 141 }; 142 node.onmouseout = function () { 143 var current = (root.selected == this.asn1); 144 this.asn1.fakeOut(current); 145 if (current) { 146 root.selected = null; 147 this.className = "hex"; 148 } 149 }; 150 this.toHexDOM_sub(node, "tag", this.stream, this.posStart(), this.posStart() + 1); 151 this.toHexDOM_sub(node, (this.length >= 0) ? "dlen" : "ulen", this.stream, this.posStart() + 1, this.posContent()); 152 if (this.sub === null) { 153 var start = this.posContent(); 154 var end = this.posEnd(); 155 if (end - start < 10 * 16) 156 node.appendChild(DOM.text( 157 this.stream.hexDump(start, end))); 158 else { 159 var end1 = start + 5 * 16 - (start & 0xF); 160 var start2 = end - 16 - (end & 0xF); 161 node.appendChild(DOM.text( 162 this.stream.hexDump(start, end1))); 163 var sub = DOM.tag("span", "skip"); 164 sub.appendChild(DOM.text("\u2026 skipping " + (start2 - end1) + " bytes \u2026\n")); 165 node.appendChild(sub); 166 node.appendChild(DOM.text( 167 this.stream.hexDump(start2, end))); 168 } 169 } else if (this.sub.length > 0) { 170 var first = this.sub[0]; 171 var last = this.sub[this.sub.length - 1]; 172 this.toHexDOM_sub(node, "intro", this.stream, this.posContent(), first.posStart()); 173 for (var i = 0, max = this.sub.length; i < max; ++i) 174 node.appendChild(this.sub[i].toHexDOM(root)); 175 this.toHexDOM_sub(node, "outro", this.stream, last.posEnd(), this.posEnd()); 176 } else 177 this.toHexDOM_sub(node, "outro", this.stream, this.posContent(), this.posEnd()); 178 return node; 179}; 180 181})();