|
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" |
|
11 |
|
12 NS_IMPL_ISUPPORTS(nsNSSASN1Sequence, nsIASN1Sequence, nsIASN1Object) |
|
13 NS_IMPL_ISUPPORTS(nsNSSASN1PrintableItem, nsIASN1PrintableItem, nsIASN1Object) |
|
14 |
|
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; |
|
25 |
|
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 } |
|
42 |
|
43 return val; |
|
44 } |
|
45 |
|
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; |
|
60 |
|
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) { |
|
69 |
|
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 } |
|
87 |
|
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; |
|
98 |
|
99 NS_ENSURE_ARG_POINTER(parent); |
|
100 if (data >= end) |
|
101 return NS_OK; |
|
102 |
|
103 unsigned char code, tagnum; |
|
104 |
|
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; |
|
115 |
|
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; |
|
122 |
|
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; |
|
134 |
|
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(); |
|
163 |
|
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 } |
|
172 |
|
173 return NS_OK; |
|
174 } |
|
175 |
|
176 nsresult |
|
177 CreateFromDER(unsigned char *data, |
|
178 unsigned int len, |
|
179 nsIASN1Object **retval) |
|
180 { |
|
181 nsCOMPtr<nsIASN1Sequence> sequence = new nsNSSASN1Sequence; |
|
182 *retval = nullptr; |
|
183 |
|
184 nsresult rv = buildASN1ObjectFromDER(data, data+len, sequence); |
|
185 |
|
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; |
|
190 |
|
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; |
|
196 |
|
197 NS_ADDREF(*retval); |
|
198 |
|
199 } |
|
200 return rv; |
|
201 } |
|
202 |
|
203 nsNSSASN1Sequence::nsNSSASN1Sequence() : mType(0), |
|
204 mTag(0), |
|
205 mIsValidContainer(true), |
|
206 mIsExpanded(true) |
|
207 { |
|
208 /* member initializers and constructor code */ |
|
209 } |
|
210 |
|
211 nsNSSASN1Sequence::~nsNSSASN1Sequence() |
|
212 { |
|
213 /* destructor code */ |
|
214 } |
|
215 |
|
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 } |
|
226 |
|
227 NS_IMETHODIMP |
|
228 nsNSSASN1Sequence::SetASN1Objects(nsIMutableArray * aASN1Objects) |
|
229 { |
|
230 mASN1Objects = aASN1Objects; |
|
231 return NS_OK; |
|
232 } |
|
233 |
|
234 NS_IMETHODIMP |
|
235 nsNSSASN1Sequence::GetTag(uint32_t *aTag) |
|
236 { |
|
237 *aTag = mTag; |
|
238 return NS_OK; |
|
239 } |
|
240 |
|
241 NS_IMETHODIMP |
|
242 nsNSSASN1Sequence::SetTag(uint32_t aTag) |
|
243 { |
|
244 mTag = aTag; |
|
245 return NS_OK; |
|
246 } |
|
247 |
|
248 NS_IMETHODIMP |
|
249 nsNSSASN1Sequence::GetType(uint32_t *aType) |
|
250 { |
|
251 *aType = mType; |
|
252 return NS_OK; |
|
253 } |
|
254 |
|
255 NS_IMETHODIMP |
|
256 nsNSSASN1Sequence::SetType(uint32_t aType) |
|
257 { |
|
258 mType = aType; |
|
259 return NS_OK; |
|
260 } |
|
261 |
|
262 NS_IMETHODIMP |
|
263 nsNSSASN1Sequence::GetDisplayName(nsAString &aDisplayName) |
|
264 { |
|
265 aDisplayName = mDisplayName; |
|
266 return NS_OK; |
|
267 } |
|
268 |
|
269 NS_IMETHODIMP |
|
270 nsNSSASN1Sequence::SetDisplayName(const nsAString &aDisplayName) |
|
271 { |
|
272 mDisplayName = aDisplayName; |
|
273 return NS_OK; |
|
274 } |
|
275 |
|
276 NS_IMETHODIMP |
|
277 nsNSSASN1Sequence::GetDisplayValue(nsAString &aDisplayValue) |
|
278 { |
|
279 aDisplayValue = mDisplayValue; |
|
280 return NS_OK; |
|
281 } |
|
282 |
|
283 NS_IMETHODIMP |
|
284 nsNSSASN1Sequence::SetDisplayValue(const nsAString &aDisplayValue) |
|
285 { |
|
286 mDisplayValue = aDisplayValue; |
|
287 return NS_OK; |
|
288 } |
|
289 |
|
290 NS_IMETHODIMP |
|
291 nsNSSASN1Sequence::GetIsValidContainer(bool *aIsValidContainer) |
|
292 { |
|
293 NS_ENSURE_ARG_POINTER(aIsValidContainer); |
|
294 *aIsValidContainer = mIsValidContainer; |
|
295 return NS_OK; |
|
296 } |
|
297 |
|
298 NS_IMETHODIMP |
|
299 nsNSSASN1Sequence::SetIsValidContainer(bool aIsValidContainer) |
|
300 { |
|
301 mIsValidContainer = aIsValidContainer; |
|
302 SetIsExpanded(mIsValidContainer); |
|
303 return NS_OK; |
|
304 } |
|
305 |
|
306 NS_IMETHODIMP |
|
307 nsNSSASN1Sequence::GetIsExpanded(bool *aIsExpanded) |
|
308 { |
|
309 NS_ENSURE_ARG_POINTER(aIsExpanded); |
|
310 *aIsExpanded = mIsExpanded; |
|
311 return NS_OK; |
|
312 } |
|
313 |
|
314 NS_IMETHODIMP |
|
315 nsNSSASN1Sequence::SetIsExpanded(bool aIsExpanded) |
|
316 { |
|
317 mIsExpanded = aIsExpanded; |
|
318 return NS_OK; |
|
319 } |
|
320 |
|
321 |
|
322 nsNSSASN1PrintableItem::nsNSSASN1PrintableItem() : mType(0), |
|
323 mTag(0), |
|
324 mData(nullptr), |
|
325 mLen(0) |
|
326 { |
|
327 /* member initializers and constructor code */ |
|
328 } |
|
329 |
|
330 nsNSSASN1PrintableItem::~nsNSSASN1PrintableItem() |
|
331 { |
|
332 /* destructor code */ |
|
333 if (mData) |
|
334 nsMemory::Free(mData); |
|
335 } |
|
336 |
|
337 /* readonly attribute wstring value; */ |
|
338 NS_IMETHODIMP |
|
339 nsNSSASN1PrintableItem::GetDisplayValue(nsAString &aValue) |
|
340 { |
|
341 aValue = mValue; |
|
342 return NS_OK; |
|
343 } |
|
344 |
|
345 NS_IMETHODIMP |
|
346 nsNSSASN1PrintableItem::SetDisplayValue(const nsAString &aValue) |
|
347 { |
|
348 mValue = aValue; |
|
349 return NS_OK; |
|
350 } |
|
351 |
|
352 NS_IMETHODIMP |
|
353 nsNSSASN1PrintableItem::GetTag(uint32_t *aTag) |
|
354 { |
|
355 *aTag = mTag; |
|
356 return NS_OK; |
|
357 } |
|
358 |
|
359 NS_IMETHODIMP |
|
360 nsNSSASN1PrintableItem::SetTag(uint32_t aTag) |
|
361 { |
|
362 mTag = aTag; |
|
363 return NS_OK; |
|
364 } |
|
365 |
|
366 NS_IMETHODIMP |
|
367 nsNSSASN1PrintableItem::GetType(uint32_t *aType) |
|
368 { |
|
369 *aType = mType; |
|
370 return NS_OK; |
|
371 } |
|
372 |
|
373 NS_IMETHODIMP |
|
374 nsNSSASN1PrintableItem::SetType(uint32_t aType) |
|
375 { |
|
376 mType = aType; |
|
377 return NS_OK; |
|
378 } |
|
379 |
|
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; |
|
388 |
|
389 mData = newData; |
|
390 } |
|
391 |
|
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 } |
|
402 |
|
403 NS_IMETHODIMP |
|
404 nsNSSASN1PrintableItem::GetData(char **outData, uint32_t *outLen) |
|
405 { |
|
406 NS_ENSURE_ARG_POINTER(outData); |
|
407 NS_ENSURE_ARG_POINTER(outLen); |
|
408 |
|
409 *outData = (char*)mData; |
|
410 *outLen = mLen; |
|
411 return NS_OK; |
|
412 } |
|
413 |
|
414 /* attribute wstring displayName; */ |
|
415 NS_IMETHODIMP |
|
416 nsNSSASN1PrintableItem::GetDisplayName(nsAString &aDisplayName) |
|
417 { |
|
418 aDisplayName = mDisplayName; |
|
419 return NS_OK; |
|
420 } |
|
421 |
|
422 NS_IMETHODIMP |
|
423 nsNSSASN1PrintableItem::SetDisplayName(const nsAString &aDisplayName) |
|
424 { |
|
425 mDisplayName = aDisplayName; |
|
426 return NS_OK; |
|
427 } |
|
428 |