1 /*! asn1hex-1.1.4.js (c) 2012-2013 Kenji Urushima | kjur.github.com/jsrsasign/license
  2  */
  3 /*
  4  * asn1hex.js - Hexadecimal represented ASN.1 string library
  5  *
  6  * Copyright (c) 2010-2013 Kenji Urushima (kenji.urushima@gmail.com)
  7  *
  8  * This software is licensed under the terms of the MIT License.
  9  * http://kjur.github.com/jsrsasign/license/
 10  *
 11  * The above copyright and license notice shall be 
 12  * included in all copies or substantial portions of the Software.
 13  */
 14 
 15 /**
 16  * @fileOverview
 17  * @name asn1hex-1.1.js
 18  * @author Kenji Urushima kenji.urushima@gmail.com
 19  * @version asn1hex 1.1.4 (2013-Oct-02)
 20  * @license <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a>
 21  */
 22 
 23 /*
 24  * MEMO:
 25  *   f('3082025b02...', 2) ... 82025b ... 3bytes
 26  *   f('020100', 2) ... 01 ... 1byte
 27  *   f('0203001...', 2) ... 03 ... 1byte
 28  *   f('02818003...', 2) ... 8180 ... 2bytes
 29  *   f('3080....0000', 2) ... 80 ... -1
 30  *
 31  *   Requirements:
 32  *   - ASN.1 type octet length MUST be 1. 
 33  *     (i.e. ASN.1 primitives like SET, SEQUENCE, INTEGER, OCTETSTRING ...)
 34  */
 35 
 36 /**
 37  * ASN.1 DER encoded hexadecimal string utility class
 38  * @name ASN1HEX
 39  * @class ASN.1 DER encoded hexadecimal string utility class
 40  * @since jsrsasign 1.1
 41  */
 42 var ASN1HEX = new function() {
 43     /**
 44      * get byte length for ASN.1 L(length) bytes
 45      * @name getByteLengthOfL_AtObj
 46      * @memberOf ASN1HEX
 47      * @function
 48      * @param {String} s hexadecimal string of ASN.1 DER encoded data
 49      * @param {Number} pos string index
 50      * @return byte length for ASN.1 L(length) bytes
 51      */
 52     this.getByteLengthOfL_AtObj = function(s, pos) {
 53 	if (s.substring(pos + 2, pos + 3) != '8') return 1;
 54 	var i = parseInt(s.substring(pos + 3, pos + 4));
 55 	if (i == 0) return -1; 		// length octet '80' indefinite length
 56 	if (0 < i && i < 10) return i + 1;	// including '8?' octet;
 57 	return -2;				// malformed format
 58     };
 59 
 60     /**
 61      * get hexadecimal string for ASN.1 L(length) bytes
 62      * @name getHexOfL_AtObj
 63      * @memberOf ASN1HEX
 64      * @function
 65      * @param {String} s hexadecimal string of ASN.1 DER encoded data
 66      * @param {Number} pos string index
 67      * @return {String} hexadecimal string for ASN.1 L(length) bytes
 68      */
 69     this.getHexOfL_AtObj = function(s, pos) {
 70 	var len = this.getByteLengthOfL_AtObj(s, pos);
 71 	if (len < 1) return '';
 72 	return s.substring(pos + 2, pos + 2 + len * 2);
 73     };
 74 
 75     //   getting ASN.1 length value at the position 'idx' of
 76     //   hexa decimal string 's'.
 77     //
 78     //   f('3082025b02...', 0) ... 82025b ... ???
 79     //   f('020100', 0) ... 01 ... 1
 80     //   f('0203001...', 0) ... 03 ... 3
 81     //   f('02818003...', 0) ... 8180 ... 128
 82     /**
 83      * get integer value of ASN.1 length for ASN.1 data
 84      * @name getIntOfL_AtObj
 85      * @memberOf ASN1HEX
 86      * @function
 87      * @param {String} s hexadecimal string of ASN.1 DER encoded data
 88      * @param {Number} pos string index
 89      * @return ASN.1 L(length) integer value
 90      */
 91     this.getIntOfL_AtObj = function(s, pos) {
 92 	var hLength = this.getHexOfL_AtObj(s, pos);
 93 	if (hLength == '') return -1;
 94 	var bi;
 95 	if (parseInt(hLength.substring(0, 1)) < 8) {
 96 	    bi = new BigInteger(hLength, 16);
 97 	} else {
 98 	    bi = new BigInteger(hLength.substring(2), 16);
 99 	}
100 	return bi.intValue();
101     };
102 
103     /**
104      * get ASN.1 value starting string position for ASN.1 object refered by index 'idx'.
105      * @name getStartPosOfV_AtObj
106      * @memberOf ASN1HEX
107      * @function
108      * @param {String} s hexadecimal string of ASN.1 DER encoded data
109      * @param {Number} pos string index
110      */
111     this.getStartPosOfV_AtObj = function(s, pos) {
112 	var l_len = this.getByteLengthOfL_AtObj(s, pos);
113 	if (l_len < 0) return l_len;
114 	return pos + (l_len + 1) * 2;
115     };
116 
117     /**
118      * get hexadecimal string of ASN.1 V(value)
119      * @name getHexOfV_AtObj
120      * @memberOf ASN1HEX
121      * @function
122      * @param {String} s hexadecimal string of ASN.1 DER encoded data
123      * @param {Number} pos string index
124      * @return {String} hexadecimal string of ASN.1 value.
125      */
126     this.getHexOfV_AtObj = function(s, pos) {
127 	var pos1 = this.getStartPosOfV_AtObj(s, pos);
128 	var len = this.getIntOfL_AtObj(s, pos);
129 	return s.substring(pos1, pos1 + len * 2);
130     };
131 
132     /**
133      * get hexadecimal string of ASN.1 TLV at
134      * @name getHexOfTLV_AtObj
135      * @memberOf ASN1HEX
136      * @function
137      * @param {String} s hexadecimal string of ASN.1 DER encoded data
138      * @param {Number} pos string index
139      * @return {String} hexadecimal string of ASN.1 TLV.
140      * @since 1.1
141      */
142     this.getHexOfTLV_AtObj = function(s, pos) {
143 	var hT = s.substr(pos, 2);
144 	var hL = this.getHexOfL_AtObj(s, pos);
145 	var hV = this.getHexOfV_AtObj(s, pos);
146 	return hT + hL + hV;
147     };
148 
149     /**
150      * get next sibling starting index for ASN.1 object string
151      * @name getPosOfNextSibling_AtObj
152      * @memberOf ASN1HEX
153      * @function
154      * @param {String} s hexadecimal string of ASN.1 DER encoded data
155      * @param {Number} pos string index
156      * @return next sibling starting index for ASN.1 object string
157      */
158     this.getPosOfNextSibling_AtObj = function(s, pos) {
159 	var pos1 = this.getStartPosOfV_AtObj(s, pos);
160 	var len = this.getIntOfL_AtObj(s, pos);
161 	return pos1 + len * 2;
162     };
163 
164     /**
165      * get array of indexes of child ASN.1 objects
166      * @name getPosArrayOfChildren_AtObj
167      * @memberOf ASN1HEX
168      * @function
169      * @param {String} s hexadecimal string of ASN.1 DER encoded data
170      * @param {Number} start string index of ASN.1 object
171      * @return {Array of Number} array of indexes for childen of ASN.1 objects
172      */
173     this.getPosArrayOfChildren_AtObj = function(h, pos) {
174 	var a = new Array();
175 	var p0 = this.getStartPosOfV_AtObj(h, pos);
176 	a.push(p0);
177 
178 	var len = this.getIntOfL_AtObj(h, pos);
179 	var p = p0;
180 	var k = 0;
181 	while (1) {
182 	    var pNext = this.getPosOfNextSibling_AtObj(h, p);
183 	    if (pNext == null || (pNext - p0  >= (len * 2))) break;
184 	    if (k >= 200) break;
185 	    
186 	    a.push(pNext);
187 	    p = pNext;
188 	    
189 	    k++;
190 	}
191 	
192 	return a;
193     };
194 
195     /**
196      * get string index of nth child object of ASN.1 object refered by h, idx
197      * @name getNthChildIndex_AtObj
198      * @memberOf ASN1HEX
199      * @function
200      * @param {String} h hexadecimal string of ASN.1 DER encoded data
201      * @param {Number} idx start string index of ASN.1 object
202      * @param {Number} nth for child
203      * @return {Number} string index of nth child.
204      * @since 1.1
205      */
206     this.getNthChildIndex_AtObj = function(h, idx, nth) {
207 	var a = this.getPosArrayOfChildren_AtObj(h, idx);
208 	return a[nth];
209     };
210 
211     // ========== decendant methods ==============================
212     /**
213      * get string index of nth child object of ASN.1 object refered by h, idx
214      * @name getDecendantIndexByNthList
215      * @memberOf ASN1HEX
216      * @function
217      * @param {String} h hexadecimal string of ASN.1 DER encoded data
218      * @param {Number} currentIndex start string index of ASN.1 object
219      * @param {Array of Number} nthList array list of nth
220      * @return {Number} string index refered by nthList
221      * @since 1.1
222      * @example
223      * The "nthList" is a index list of structured ASN.1 object
224      * reference. Here is a sample structure and "nthList"s which
225      * refers each objects.
226      *
227      * SQUENCE               - [0]
228      *   SEQUENCE            - [0, 0]
229      *     IA5STRING 000     - [0, 0, 0]
230      *     UTF8STRING 001    - [0, 0, 1]
231      *   SET                 - [0, 1]
232      *     IA5STRING 010     - [0, 1, 0]
233      *     UTF8STRING 011    - [0, 1, 1]
234      */
235     this.getDecendantIndexByNthList = function(h, currentIndex, nthList) {
236 	if (nthList.length == 0) {
237 	    return currentIndex;
238 	}
239 	var firstNth = nthList.shift();
240 	var a = this.getPosArrayOfChildren_AtObj(h, currentIndex);
241 	return this.getDecendantIndexByNthList(h, a[firstNth], nthList);
242     };
243 
244     /**
245      * get hexadecimal string of ASN.1 TLV refered by current index and nth index list.
246      * @name getDecendantHexTLVByNthList
247      * @memberOf ASN1HEX
248      * @function
249      * @param {String} h hexadecimal string of ASN.1 DER encoded data
250      * @param {Number} currentIndex start string index of ASN.1 object
251      * @param {Array of Number} nthList array list of nth
252      * @return {Number} hexadecimal string of ASN.1 TLV refered by nthList
253      * @since 1.1
254      */
255     this.getDecendantHexTLVByNthList = function(h, currentIndex, nthList) {
256 	var idx = this.getDecendantIndexByNthList(h, currentIndex, nthList);
257 	return this.getHexOfTLV_AtObj(h, idx);
258     };
259 
260     /**
261      * get hexadecimal string of ASN.1 V refered by current index and nth index list.
262      * @name getDecendantHexVByNthList
263      * @memberOf ASN1HEX
264      * @function
265      * @param {String} h hexadecimal string of ASN.1 DER encoded data
266      * @param {Number} currentIndex start string index of ASN.1 object
267      * @param {Array of Number} nthList array list of nth
268      * @return {Number} hexadecimal string of ASN.1 V refered by nthList
269      * @since 1.1
270      */
271     this.getDecendantHexVByNthList = function(h, currentIndex, nthList) {
272 	var idx = this.getDecendantIndexByNthList(h, currentIndex, nthList);
273 	return this.getHexOfV_AtObj(h, idx);
274     };
275 };
276 
277 /*
278  * @since asn1hex 1.1.4
279  */
280 ASN1HEX.getVbyList = function(h, currentIndex, nthList, checkingTag) {
281     var idx = this.getDecendantIndexByNthList(h, currentIndex, nthList);
282     if (idx === undefined) {
283 	throw "can't find nthList object";
284     }
285     if (checkingTag !== undefined) {
286 	if (h.substr(idx, 2) != checkingTag) {
287 	    throw "checking tag doesn't match: " + h.substr(idx,2) + "!=" + checkingTag;
288 	}
289     }
290     return this.getHexOfV_AtObj(h, idx);
291 };
292 
293