PageRenderTime 38ms CodeModel.GetById 14ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 0ms

/flash-src/third-party/com/hurlant/util/der/DER.as

http://github.com/gimite/web-socket-js
ActionScript | 210 lines | 163 code | 7 blank | 40 comment | 26 complexity | 346d733225a2c57a680b24f060381ce9 MD5 | raw file
  1/**
  2 * DER
  3 * 
  4 * A basic class to parse DER structures.
  5 * It is very incomplete, but sufficient to extract whatever data we need so far.
  6 * Copyright (c) 2007 Henri Torgemane
  7 * 
  8 * See LICENSE.txt for full license information.
  9 */
 10package com.hurlant.util.der
 11{
 12	import com.hurlant.math.BigInteger;
 13	
 14	import flash.utils.ByteArray;
 15	import com.hurlant.util.der.Sequence;
 16	import com.hurlant.util.Hex;
 17	
 18	// goal 1: to be able to parse an RSA Private Key PEM file.
 19	// goal 2: to parse an X509v3 cert. kinda.
 20	
 21	/**
 22	 * DER for dummies:
 23	 * http://luca.ntop.org/Teaching/Appunti/asn1.html
 24	 * 
 25	 * This class does the bare minimum to get by. if that.
 26	 */
 27	public class DER
 28	{
 29		public static var indent:String = "";
 30		
 31		public static function parse(der:ByteArray, structure:*=null):IAsn1Type {
 32/* 			if (der.position==0) {
 33				trace("DER.parse: "+Hex.fromArray(der));
 34			}
 35 */			// type
 36			var type:int = der.readUnsignedByte();
 37			var constructed:Boolean = (type&0x20)!=0;
 38			type &=0x1F;
 39			// length
 40			var len:int = der.readUnsignedByte();
 41			if (len>=0x80) {
 42				// long form of length
 43				var count:int = len & 0x7f;
 44				len = 0;
 45				while (count>0) {
 46					len = (len<<8) | der.readUnsignedByte();
 47					count--;
 48				}
 49			}
 50			// data
 51			var b:ByteArray
 52			switch (type) {
 53				case 0x00: // WHAT IS THIS THINGY? (seen as 0xa0)
 54					// (note to self: read a spec someday.)
 55					// for now, treat as a sequence.
 56				case 0x10: // SEQUENCE/SEQUENCE OF. whatever
 57					// treat as an array
 58					var p:int = der.position;
 59					var o:Sequence = new Sequence(type, len);
 60					var arrayStruct:Array = structure as Array;
 61					if (arrayStruct!=null) {
 62						// copy the array, as we destroy it later.
 63						arrayStruct = arrayStruct.concat();
 64					}
 65					while (der.position < p+len) {
 66						var tmpStruct:Object = null
 67						if (arrayStruct!=null) {
 68							tmpStruct = arrayStruct.shift();
 69						}
 70						if (tmpStruct!=null) {
 71							while (tmpStruct && tmpStruct.optional) {
 72								// make sure we have something that looks reasonable. XXX I'm winging it here..
 73								var wantConstructed:Boolean = (tmpStruct.value is Array);
 74								var isConstructed:Boolean = isConstructedType(der);
 75								if (wantConstructed!=isConstructed) {
 76									// not found. put default stuff, or null
 77									o.push(tmpStruct.defaultValue);
 78									o[tmpStruct.name] = tmpStruct.defaultValue;
 79									// try the next thing
 80									tmpStruct = arrayStruct.shift();
 81								} else {
 82									break;
 83								}
 84							}
 85						}
 86						if (tmpStruct!=null) {
 87							var name:String = tmpStruct.name;
 88							var value:* = tmpStruct.value;
 89							if (tmpStruct.extract) {
 90								// we need to keep a binary copy of this element
 91								var size:int = getLengthOfNextElement(der);
 92								var ba:ByteArray = new ByteArray;
 93								ba.writeBytes(der, der.position, size);
 94								o[name+"_bin"] = ba;
 95							}
 96							var obj:IAsn1Type = DER.parse(der, value);
 97							o.push(obj);
 98							o[name] = obj;
 99						} else {
100							o.push(DER.parse(der));
101						}
102					}
103					return o;
104				case 0x11: // SET/SET OF
105					p = der.position;
106					var s:Set = new Set(type, len);
107					while (der.position < p+len) {
108						s.push(DER.parse(der));
109					}
110					return s;
111				case 0x02: // INTEGER
112					// put in a BigInteger
113					b = new ByteArray;
114					der.readBytes(b,0,len);
115					b.position=0;
116					return new Integer(type, len, b);
117				case 0x06: // OBJECT IDENTIFIER:
118					b = new ByteArray;
119					der.readBytes(b,0,len);
120					b.position=0;
121					return new ObjectIdentifier(type, len, b);
122				default:
123					trace("I DONT KNOW HOW TO HANDLE DER stuff of TYPE "+type);
124					// fall through
125				case 0x03: // BIT STRING
126					if (der[der.position]==0) {
127						//trace("Horrible Bit String pre-padding removal hack."); // I wish I had the patience to find a spec for this.
128						der.position++;
129						len--;
130					}
131				case 0x04: // OCTET STRING
132					// stuff in a ByteArray for now.
133					var bs:ByteString = new ByteString(type, len);
134					der.readBytes(bs,0,len);
135					return bs;
136				case 0x05: // NULL
137					// if len!=0, something's horribly wrong.
138					// should I check?
139					return null;
140				case 0x13: // PrintableString
141					var ps:PrintableString = new PrintableString(type, len);
142					ps.setString(der.readMultiByte(len, "US-ASCII"));
143					return ps;
144				case 0x22: // XXX look up what this is. openssl uses this to store my email.
145				case 0x14: // T61String - an horrible format we don't even pretend to support correctly
146					ps = new PrintableString(type, len);
147					ps.setString(der.readMultiByte(len, "latin1"));
148					return ps;
149				case 0x17: // UTCTime
150					var ut:UTCTime = new UTCTime(type, len);
151					ut.setUTCTime(der.readMultiByte(len, "US-ASCII"));
152					return ut;
153			}
154		}
155		
156		private static function getLengthOfNextElement(b:ByteArray):int {
157			var p:uint = b.position;
158			// length
159			b.position++;
160			var len:int = b.readUnsignedByte();
161			if (len>=0x80) {
162				// long form of length
163				var count:int = len & 0x7f;
164				len = 0;
165				while (count>0) {
166					len = (len<<8) | b.readUnsignedByte();
167					count--;
168				}
169			}
170			len += b.position-p; // length of length
171			b.position = p;
172			return len;
173		}
174		private static function isConstructedType(b:ByteArray):Boolean {
175			var type:int = b[b.position];
176			return (type&0x20)!=0;
177		}
178		
179		public static function wrapDER(type:int, data:ByteArray):ByteArray {
180			var d:ByteArray = new ByteArray;
181			d.writeByte(type);
182			var len:int = data.length;
183			if (len<128) {
184				d.writeByte(len);
185			} else if (len<256) {
186				d.writeByte(1 | 0x80);
187				d.writeByte(len);
188			} else if (len<65536) {
189				d.writeByte(2 | 0x80);
190				d.writeByte(len>>8);
191				d.writeByte(len);
192			} else if (len<65536*256) {
193				d.writeByte(3 | 0x80);
194				d.writeByte(len>>16);
195				d.writeByte(len>>8);
196				d.writeByte(len);
197			} else {
198				d.writeByte(4 | 0x80);
199				d.writeByte(len>>24);
200				d.writeByte(len>>16);
201				d.writeByte(len>>8);
202				d.writeByte(len);
203			}
204			d.writeBytes(data);
205			d.position=0;
206			return d;
207			
208		}
209	}
210}