Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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 "nsNSSASN1Object.h"
5 #include "nsIComponentManager.h"
6 #include "secasn1.h"
7 #include "nsReadableUtils.h"
8 #include "nsIMutableArray.h"
9 #include "nsArrayUtils.h"
10 #include "nsXPCOMCID.h"
12 NS_IMPL_ISUPPORTS(nsNSSASN1Sequence, nsIASN1Sequence, nsIASN1Object)
13 NS_IMPL_ISUPPORTS(nsNSSASN1PrintableItem, nsIASN1PrintableItem, nsIASN1Object)
15 // This function is used to interpret an integer that
16 // was encoded in a DER buffer. This function is used
17 // when converting a DER buffer into a nsIASN1Object
18 // structure. This interprets the buffer in data
19 // as defined by the DER (Distinguised Encoding Rules) of
20 // ASN1.
21 static int
22 getInteger256(unsigned char *data, unsigned int nb)
23 {
24 int val;
26 switch (nb) {
27 case 1:
28 val = data[0];
29 break;
30 case 2:
31 val = (data[0] << 8) | data[1];
32 break;
33 case 3:
34 val = (data[0] << 16) | (data[1] << 8) | data[2];
35 break;
36 case 4:
37 val = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
38 break;
39 default:
40 return -1;
41 }
43 return val;
44 }
46 // This function is used to retrieve the lenght of a DER encoded
47 // item. It looks to see if this a multibyte length and then
48 // interprets the buffer accordingly to get the actual length value.
49 // This funciton is used mostly while parsing the DER headers.
50 //
51 // A DER encoded item has the following structure:
52 //
53 // <tag><length<data consisting of lenght bytes>
54 static int32_t
55 getDERItemLength(unsigned char *data, unsigned char *end,
56 unsigned long *bytesUsed, bool *indefinite)
57 {
58 unsigned char lbyte = *data++;
59 int32_t length = -1;
61 *indefinite = false;
62 if (lbyte >= 0x80) {
63 // Multibyte length
64 unsigned nb = (unsigned) (lbyte & 0x7f);
65 if (nb > 4) {
66 return -1;
67 }
68 if (nb > 0) {
70 if ((data+nb) > end) {
71 return -1;
72 }
73 length = getInteger256(data, nb);
74 if (length < 0)
75 return -1;
76 } else {
77 *indefinite = true;
78 length = 0;
79 }
80 *bytesUsed = nb+1;
81 } else {
82 length = lbyte;
83 *bytesUsed = 1;
84 }
85 return length;
86 }
88 static nsresult
89 buildASN1ObjectFromDER(unsigned char *data,
90 unsigned char *end,
91 nsIASN1Sequence *parent)
92 {
93 nsresult rv;
94 nsCOMPtr<nsIASN1Sequence> sequence;
95 nsCOMPtr<nsIASN1PrintableItem> printableItem;
96 nsCOMPtr<nsIASN1Object> asn1Obj;
97 nsCOMPtr<nsIMutableArray> parentObjects;
99 NS_ENSURE_ARG_POINTER(parent);
100 if (data >= end)
101 return NS_OK;
103 unsigned char code, tagnum;
105 // A DER item has the form of |tag|len|data
106 // tag is one byte and describes the type of element
107 // we are dealing with.
108 // len is a DER encoded int telling us how long the data is
109 // data is a buffer that is len bytes long and has to be
110 // interpreted according to its type.
111 unsigned long bytesUsed;
112 bool indefinite;
113 int32_t len;
114 uint32_t type;
116 rv = parent->GetASN1Objects(getter_AddRefs(parentObjects));
117 if (NS_FAILED(rv) || !parentObjects)
118 return NS_ERROR_FAILURE;
119 while (data < end) {
120 code = *data;
121 tagnum = code & SEC_ASN1_TAGNUM_MASK;
123 /*
124 * NOTE: This code does not (yet) handle the high-tag-number form!
125 */
126 if (tagnum == SEC_ASN1_HIGH_TAG_NUMBER) {
127 return NS_ERROR_FAILURE;
128 }
129 data++;
130 len = getDERItemLength(data, end, &bytesUsed, &indefinite);
131 data += bytesUsed;
132 if ((len < 0) || ((data+len) > end))
133 return NS_ERROR_FAILURE;
135 if (code & SEC_ASN1_CONSTRUCTED) {
136 if (len > 0 || indefinite) {
137 sequence = new nsNSSASN1Sequence();
138 switch (code & SEC_ASN1_CLASS_MASK) {
139 case SEC_ASN1_UNIVERSAL:
140 type = tagnum;
141 break;
142 case SEC_ASN1_APPLICATION:
143 type = nsIASN1Object::ASN1_APPLICATION;
144 break;
145 case SEC_ASN1_CONTEXT_SPECIFIC:
146 type = nsIASN1Object::ASN1_CONTEXT_SPECIFIC;
147 break;
148 case SEC_ASN1_PRIVATE:
149 type = nsIASN1Object::ASN1_PRIVATE;
150 break;
151 default:
152 NS_ERROR("Bad DER");
153 return NS_ERROR_FAILURE;
154 }
155 sequence->SetTag(tagnum);
156 sequence->SetType(type);
157 rv = buildASN1ObjectFromDER(data, (len == 0) ? end : data + len,
158 sequence);
159 asn1Obj = sequence;
160 }
161 } else {
162 printableItem = new nsNSSASN1PrintableItem();
164 asn1Obj = printableItem;
165 asn1Obj->SetType(tagnum);
166 asn1Obj->SetTag(tagnum);
167 printableItem->SetData((char*)data, len);
168 }
169 data += len;
170 parentObjects->AppendElement(asn1Obj, false);
171 }
173 return NS_OK;
174 }
176 nsresult
177 CreateFromDER(unsigned char *data,
178 unsigned int len,
179 nsIASN1Object **retval)
180 {
181 nsCOMPtr<nsIASN1Sequence> sequence = new nsNSSASN1Sequence;
182 *retval = nullptr;
184 nsresult rv = buildASN1ObjectFromDER(data, data+len, sequence);
186 if (NS_SUCCEEDED(rv)) {
187 // The actual object will be the first element inserted
188 // into the sequence of the sequence variable we created.
189 nsCOMPtr<nsIMutableArray> elements;
191 sequence->GetASN1Objects(getter_AddRefs(elements));
192 nsCOMPtr<nsIASN1Object> asn1Obj = do_QueryElementAt(elements, 0);
193 *retval = asn1Obj;
194 if (!*retval)
195 return NS_ERROR_FAILURE;
197 NS_ADDREF(*retval);
199 }
200 return rv;
201 }
203 nsNSSASN1Sequence::nsNSSASN1Sequence() : mType(0),
204 mTag(0),
205 mIsValidContainer(true),
206 mIsExpanded(true)
207 {
208 /* member initializers and constructor code */
209 }
211 nsNSSASN1Sequence::~nsNSSASN1Sequence()
212 {
213 /* destructor code */
214 }
216 NS_IMETHODIMP
217 nsNSSASN1Sequence::GetASN1Objects(nsIMutableArray * *aASN1Objects)
218 {
219 if (!mASN1Objects) {
220 mASN1Objects = do_CreateInstance(NS_ARRAY_CONTRACTID);
221 }
222 *aASN1Objects = mASN1Objects;
223 NS_IF_ADDREF(*aASN1Objects);
224 return NS_OK;
225 }
227 NS_IMETHODIMP
228 nsNSSASN1Sequence::SetASN1Objects(nsIMutableArray * aASN1Objects)
229 {
230 mASN1Objects = aASN1Objects;
231 return NS_OK;
232 }
234 NS_IMETHODIMP
235 nsNSSASN1Sequence::GetTag(uint32_t *aTag)
236 {
237 *aTag = mTag;
238 return NS_OK;
239 }
241 NS_IMETHODIMP
242 nsNSSASN1Sequence::SetTag(uint32_t aTag)
243 {
244 mTag = aTag;
245 return NS_OK;
246 }
248 NS_IMETHODIMP
249 nsNSSASN1Sequence::GetType(uint32_t *aType)
250 {
251 *aType = mType;
252 return NS_OK;
253 }
255 NS_IMETHODIMP
256 nsNSSASN1Sequence::SetType(uint32_t aType)
257 {
258 mType = aType;
259 return NS_OK;
260 }
262 NS_IMETHODIMP
263 nsNSSASN1Sequence::GetDisplayName(nsAString &aDisplayName)
264 {
265 aDisplayName = mDisplayName;
266 return NS_OK;
267 }
269 NS_IMETHODIMP
270 nsNSSASN1Sequence::SetDisplayName(const nsAString &aDisplayName)
271 {
272 mDisplayName = aDisplayName;
273 return NS_OK;
274 }
276 NS_IMETHODIMP
277 nsNSSASN1Sequence::GetDisplayValue(nsAString &aDisplayValue)
278 {
279 aDisplayValue = mDisplayValue;
280 return NS_OK;
281 }
283 NS_IMETHODIMP
284 nsNSSASN1Sequence::SetDisplayValue(const nsAString &aDisplayValue)
285 {
286 mDisplayValue = aDisplayValue;
287 return NS_OK;
288 }
290 NS_IMETHODIMP
291 nsNSSASN1Sequence::GetIsValidContainer(bool *aIsValidContainer)
292 {
293 NS_ENSURE_ARG_POINTER(aIsValidContainer);
294 *aIsValidContainer = mIsValidContainer;
295 return NS_OK;
296 }
298 NS_IMETHODIMP
299 nsNSSASN1Sequence::SetIsValidContainer(bool aIsValidContainer)
300 {
301 mIsValidContainer = aIsValidContainer;
302 SetIsExpanded(mIsValidContainer);
303 return NS_OK;
304 }
306 NS_IMETHODIMP
307 nsNSSASN1Sequence::GetIsExpanded(bool *aIsExpanded)
308 {
309 NS_ENSURE_ARG_POINTER(aIsExpanded);
310 *aIsExpanded = mIsExpanded;
311 return NS_OK;
312 }
314 NS_IMETHODIMP
315 nsNSSASN1Sequence::SetIsExpanded(bool aIsExpanded)
316 {
317 mIsExpanded = aIsExpanded;
318 return NS_OK;
319 }
322 nsNSSASN1PrintableItem::nsNSSASN1PrintableItem() : mType(0),
323 mTag(0),
324 mData(nullptr),
325 mLen(0)
326 {
327 /* member initializers and constructor code */
328 }
330 nsNSSASN1PrintableItem::~nsNSSASN1PrintableItem()
331 {
332 /* destructor code */
333 if (mData)
334 nsMemory::Free(mData);
335 }
337 /* readonly attribute wstring value; */
338 NS_IMETHODIMP
339 nsNSSASN1PrintableItem::GetDisplayValue(nsAString &aValue)
340 {
341 aValue = mValue;
342 return NS_OK;
343 }
345 NS_IMETHODIMP
346 nsNSSASN1PrintableItem::SetDisplayValue(const nsAString &aValue)
347 {
348 mValue = aValue;
349 return NS_OK;
350 }
352 NS_IMETHODIMP
353 nsNSSASN1PrintableItem::GetTag(uint32_t *aTag)
354 {
355 *aTag = mTag;
356 return NS_OK;
357 }
359 NS_IMETHODIMP
360 nsNSSASN1PrintableItem::SetTag(uint32_t aTag)
361 {
362 mTag = aTag;
363 return NS_OK;
364 }
366 NS_IMETHODIMP
367 nsNSSASN1PrintableItem::GetType(uint32_t *aType)
368 {
369 *aType = mType;
370 return NS_OK;
371 }
373 NS_IMETHODIMP
374 nsNSSASN1PrintableItem::SetType(uint32_t aType)
375 {
376 mType = aType;
377 return NS_OK;
378 }
380 NS_IMETHODIMP
381 nsNSSASN1PrintableItem::SetData(char *data, uint32_t len)
382 {
383 if (len > 0) {
384 if (mLen < len) {
385 unsigned char* newData = (unsigned char*)nsMemory::Realloc(mData, len);
386 if (!newData)
387 return NS_ERROR_OUT_OF_MEMORY;
389 mData = newData;
390 }
392 memcpy(mData, data, len);
393 } else if (len == 0) {
394 if (mData) {
395 nsMemory::Free(mData);
396 mData = nullptr;
397 }
398 }
399 mLen = len;
400 return NS_OK;
401 }
403 NS_IMETHODIMP
404 nsNSSASN1PrintableItem::GetData(char **outData, uint32_t *outLen)
405 {
406 NS_ENSURE_ARG_POINTER(outData);
407 NS_ENSURE_ARG_POINTER(outLen);
409 *outData = (char*)mData;
410 *outLen = mLen;
411 return NS_OK;
412 }
414 /* attribute wstring displayName; */
415 NS_IMETHODIMP
416 nsNSSASN1PrintableItem::GetDisplayName(nsAString &aDisplayName)
417 {
418 aDisplayName = mDisplayName;
419 return NS_OK;
420 }
422 NS_IMETHODIMP
423 nsNSSASN1PrintableItem::SetDisplayName(const nsAString &aDisplayName)
424 {
425 mDisplayName = aDisplayName;
426 return NS_OK;
427 }