1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is the Netscape security libraries.
15 : *
16 : * The Initial Developer of the Original Code is
17 : * Netscape Communications Corporation.
18 : * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Javier Delgadillo <javi@netscape.com>
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 : #include "nsNSSASN1Object.h"
38 : #include "nsIComponentManager.h"
39 : #include "secasn1.h"
40 : #include "nsReadableUtils.h"
41 : #include "nsIMutableArray.h"
42 : #include "nsArrayUtils.h"
43 : #include "nsXPCOMCID.h"
44 :
45 0 : NS_IMPL_THREADSAFE_ISUPPORTS2(nsNSSASN1Sequence, nsIASN1Sequence,
46 : nsIASN1Object)
47 0 : NS_IMPL_THREADSAFE_ISUPPORTS2(nsNSSASN1PrintableItem, nsIASN1PrintableItem,
48 : nsIASN1Object)
49 :
50 : // This function is used to interpret an integer that
51 : // was encoded in a DER buffer. This function is used
52 : // when converting a DER buffer into a nsIASN1Object
53 : // structure. This interprets the buffer in data
54 : // as defined by the DER (Distinguised Encoding Rules) of
55 : // ASN1.
56 : static int
57 0 : getInteger256(unsigned char *data, unsigned int nb)
58 : {
59 : int val;
60 :
61 0 : switch (nb) {
62 : case 1:
63 0 : val = data[0];
64 0 : break;
65 : case 2:
66 0 : val = (data[0] << 8) | data[1];
67 0 : break;
68 : case 3:
69 0 : val = (data[0] << 16) | (data[1] << 8) | data[2];
70 0 : break;
71 : case 4:
72 0 : val = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
73 0 : break;
74 : default:
75 0 : return -1;
76 : }
77 :
78 0 : return val;
79 : }
80 :
81 : // This function is used to retrieve the lenght of a DER encoded
82 : // item. It looks to see if this a multibyte length and then
83 : // interprets the buffer accordingly to get the actual length value.
84 : // This funciton is used mostly while parsing the DER headers.
85 : //
86 : // A DER encoded item has the following structure:
87 : //
88 : // <tag><length<data consisting of lenght bytes>
89 : static PRInt32
90 0 : getDERItemLength(unsigned char *data, unsigned char *end,
91 : unsigned long *bytesUsed, bool *indefinite)
92 : {
93 0 : unsigned char lbyte = *data++;
94 0 : PRInt32 length = -1;
95 :
96 0 : *indefinite = false;
97 0 : if (lbyte >= 0x80) {
98 : // Multibyte length
99 0 : unsigned nb = (unsigned) (lbyte & 0x7f);
100 0 : if (nb > 4) {
101 0 : return -1;
102 : }
103 0 : if (nb > 0) {
104 :
105 0 : if ((data+nb) > end) {
106 0 : return -1;
107 : }
108 0 : length = getInteger256(data, nb);
109 0 : if (length < 0)
110 0 : return -1;
111 : } else {
112 0 : *indefinite = true;
113 0 : length = 0;
114 : }
115 0 : *bytesUsed = nb+1;
116 : } else {
117 0 : length = lbyte;
118 0 : *bytesUsed = 1;
119 : }
120 0 : return length;
121 : }
122 :
123 : static nsresult
124 0 : buildASN1ObjectFromDER(unsigned char *data,
125 : unsigned char *end,
126 : nsIASN1Sequence *parent)
127 : {
128 : nsresult rv;
129 0 : nsCOMPtr<nsIASN1Sequence> sequence;
130 0 : nsCOMPtr<nsIASN1PrintableItem> printableItem;
131 0 : nsCOMPtr<nsIASN1Object> asn1Obj;
132 0 : nsCOMPtr<nsIMutableArray> parentObjects;
133 :
134 0 : NS_ENSURE_ARG_POINTER(parent);
135 0 : if (data >= end)
136 0 : return NS_OK;
137 :
138 : unsigned char code, tagnum;
139 :
140 : // A DER item has the form of |tag|len|data
141 : // tag is one byte and describes the type of elment
142 : // we are dealing with.
143 : // len is a DER encoded int telling us how long the data is
144 : // data is a buffer that is len bytes long and has to be
145 : // interpreted according to its type.
146 : unsigned long bytesUsed;
147 : bool indefinite;
148 : PRInt32 len;
149 : PRUint32 type;
150 :
151 0 : rv = parent->GetASN1Objects(getter_AddRefs(parentObjects));
152 0 : if (NS_FAILED(rv) || parentObjects == nsnull)
153 0 : return NS_ERROR_FAILURE;
154 0 : while (data < end) {
155 0 : code = *data;
156 0 : tagnum = code & SEC_ASN1_TAGNUM_MASK;
157 :
158 : /*
159 : * NOTE: This code does not (yet) handle the high-tag-number form!
160 : */
161 0 : if (tagnum == SEC_ASN1_HIGH_TAG_NUMBER) {
162 0 : return NS_ERROR_FAILURE;
163 : }
164 0 : data++;
165 0 : len = getDERItemLength(data, end, &bytesUsed, &indefinite);
166 0 : data += bytesUsed;
167 0 : if ((len < 0) || ((data+len) > end))
168 0 : return NS_ERROR_FAILURE;
169 :
170 0 : if (code & SEC_ASN1_CONSTRUCTED) {
171 0 : if (len > 0 || indefinite) {
172 0 : sequence = new nsNSSASN1Sequence();
173 0 : switch (code & SEC_ASN1_CLASS_MASK) {
174 : case SEC_ASN1_UNIVERSAL:
175 0 : type = tagnum;
176 0 : break;
177 : case SEC_ASN1_APPLICATION:
178 0 : type = nsIASN1Object::ASN1_APPLICATION;
179 0 : break;
180 : case SEC_ASN1_CONTEXT_SPECIFIC:
181 0 : type = nsIASN1Object::ASN1_CONTEXT_SPECIFIC;
182 0 : break;
183 : case SEC_ASN1_PRIVATE:
184 0 : type = nsIASN1Object::ASN1_PRIVATE;
185 0 : break;
186 : default:
187 0 : NS_ERROR("Bad DER");
188 0 : return NS_ERROR_FAILURE;
189 : }
190 0 : sequence->SetTag(tagnum);
191 0 : sequence->SetType(type);
192 0 : rv = buildASN1ObjectFromDER(data, (len == 0) ? end : data + len,
193 0 : sequence);
194 0 : asn1Obj = sequence;
195 : }
196 : } else {
197 0 : printableItem = new nsNSSASN1PrintableItem();
198 :
199 0 : asn1Obj = printableItem;
200 0 : asn1Obj->SetType(tagnum);
201 0 : asn1Obj->SetTag(tagnum);
202 0 : printableItem->SetData((char*)data, len);
203 : }
204 0 : data += len;
205 0 : parentObjects->AppendElement(asn1Obj, false);
206 : }
207 :
208 0 : return NS_OK;
209 : }
210 :
211 : nsresult
212 0 : CreateFromDER(unsigned char *data,
213 : unsigned int len,
214 : nsIASN1Object **retval)
215 : {
216 0 : nsCOMPtr<nsIASN1Sequence> sequence = new nsNSSASN1Sequence;
217 0 : *retval = nsnull;
218 :
219 0 : nsresult rv = buildASN1ObjectFromDER(data, data+len, sequence);
220 :
221 0 : if (NS_SUCCEEDED(rv)) {
222 : // The actual object will be the first element inserted
223 : // into the sequence of the sequence variable we created.
224 0 : nsCOMPtr<nsIMutableArray> elements;
225 :
226 0 : sequence->GetASN1Objects(getter_AddRefs(elements));
227 0 : nsCOMPtr<nsIASN1Object> asn1Obj = do_QueryElementAt(elements, 0);
228 0 : *retval = asn1Obj;
229 0 : if (*retval == nsnull)
230 0 : return NS_ERROR_FAILURE;
231 :
232 0 : NS_ADDREF(*retval);
233 :
234 : }
235 0 : return rv;
236 : }
237 :
238 0 : nsNSSASN1Sequence::nsNSSASN1Sequence() : mType(0),
239 : mTag(0),
240 : mIsValidContainer(true),
241 0 : mIsExpanded(true)
242 : {
243 : /* member initializers and constructor code */
244 0 : }
245 :
246 0 : nsNSSASN1Sequence::~nsNSSASN1Sequence()
247 : {
248 : /* destructor code */
249 0 : }
250 :
251 : NS_IMETHODIMP
252 0 : nsNSSASN1Sequence::GetASN1Objects(nsIMutableArray * *aASN1Objects)
253 : {
254 0 : if (mASN1Objects == nsnull) {
255 0 : mASN1Objects = do_CreateInstance(NS_ARRAY_CONTRACTID);
256 : }
257 0 : *aASN1Objects = mASN1Objects;
258 0 : NS_IF_ADDREF(*aASN1Objects);
259 0 : return NS_OK;
260 : }
261 :
262 : NS_IMETHODIMP
263 0 : nsNSSASN1Sequence::SetASN1Objects(nsIMutableArray * aASN1Objects)
264 : {
265 0 : mASN1Objects = aASN1Objects;
266 0 : return NS_OK;
267 : }
268 :
269 : NS_IMETHODIMP
270 0 : nsNSSASN1Sequence::GetTag(PRUint32 *aTag)
271 : {
272 0 : *aTag = mTag;
273 0 : return NS_OK;
274 : }
275 :
276 : NS_IMETHODIMP
277 0 : nsNSSASN1Sequence::SetTag(PRUint32 aTag)
278 : {
279 0 : mTag = aTag;
280 0 : return NS_OK;
281 : }
282 :
283 : NS_IMETHODIMP
284 0 : nsNSSASN1Sequence::GetType(PRUint32 *aType)
285 : {
286 0 : *aType = mType;
287 0 : return NS_OK;
288 : }
289 :
290 : NS_IMETHODIMP
291 0 : nsNSSASN1Sequence::SetType(PRUint32 aType)
292 : {
293 0 : mType = aType;
294 0 : return NS_OK;
295 : }
296 :
297 : NS_IMETHODIMP
298 0 : nsNSSASN1Sequence::GetDisplayName(nsAString &aDisplayName)
299 : {
300 0 : aDisplayName = mDisplayName;
301 0 : return NS_OK;
302 : }
303 :
304 : NS_IMETHODIMP
305 0 : nsNSSASN1Sequence::SetDisplayName(const nsAString &aDisplayName)
306 : {
307 0 : mDisplayName = aDisplayName;
308 0 : return NS_OK;
309 : }
310 :
311 : NS_IMETHODIMP
312 0 : nsNSSASN1Sequence::GetDisplayValue(nsAString &aDisplayValue)
313 : {
314 0 : aDisplayValue = mDisplayValue;
315 0 : return NS_OK;
316 : }
317 :
318 : NS_IMETHODIMP
319 0 : nsNSSASN1Sequence::SetDisplayValue(const nsAString &aDisplayValue)
320 : {
321 0 : mDisplayValue = aDisplayValue;
322 0 : return NS_OK;
323 : }
324 :
325 : NS_IMETHODIMP
326 0 : nsNSSASN1Sequence::GetIsValidContainer(bool *aIsValidContainer)
327 : {
328 0 : NS_ENSURE_ARG_POINTER(aIsValidContainer);
329 0 : *aIsValidContainer = mIsValidContainer;
330 0 : return NS_OK;
331 : }
332 :
333 : NS_IMETHODIMP
334 0 : nsNSSASN1Sequence::SetIsValidContainer(bool aIsValidContainer)
335 : {
336 0 : mIsValidContainer = aIsValidContainer;
337 0 : SetIsExpanded(mIsValidContainer);
338 0 : return NS_OK;
339 : }
340 :
341 : NS_IMETHODIMP
342 0 : nsNSSASN1Sequence::GetIsExpanded(bool *aIsExpanded)
343 : {
344 0 : NS_ENSURE_ARG_POINTER(aIsExpanded);
345 0 : *aIsExpanded = mIsExpanded;
346 0 : return NS_OK;
347 : }
348 :
349 : NS_IMETHODIMP
350 0 : nsNSSASN1Sequence::SetIsExpanded(bool aIsExpanded)
351 : {
352 0 : mIsExpanded = aIsExpanded;
353 0 : return NS_OK;
354 : }
355 :
356 :
357 0 : nsNSSASN1PrintableItem::nsNSSASN1PrintableItem() : mType(0),
358 : mTag(0),
359 : mData(nsnull),
360 0 : mLen(0)
361 : {
362 : /* member initializers and constructor code */
363 0 : }
364 :
365 0 : nsNSSASN1PrintableItem::~nsNSSASN1PrintableItem()
366 : {
367 : /* destructor code */
368 0 : if (mData)
369 0 : nsMemory::Free(mData);
370 0 : }
371 :
372 : /* readonly attribute wstring value; */
373 : NS_IMETHODIMP
374 0 : nsNSSASN1PrintableItem::GetDisplayValue(nsAString &aValue)
375 : {
376 0 : aValue = mValue;
377 0 : return NS_OK;
378 : }
379 :
380 : NS_IMETHODIMP
381 0 : nsNSSASN1PrintableItem::SetDisplayValue(const nsAString &aValue)
382 : {
383 0 : mValue = aValue;
384 0 : return NS_OK;
385 : }
386 :
387 : NS_IMETHODIMP
388 0 : nsNSSASN1PrintableItem::GetTag(PRUint32 *aTag)
389 : {
390 0 : *aTag = mTag;
391 0 : return NS_OK;
392 : }
393 :
394 : NS_IMETHODIMP
395 0 : nsNSSASN1PrintableItem::SetTag(PRUint32 aTag)
396 : {
397 0 : mTag = aTag;
398 0 : return NS_OK;
399 : }
400 :
401 : NS_IMETHODIMP
402 0 : nsNSSASN1PrintableItem::GetType(PRUint32 *aType)
403 : {
404 0 : *aType = mType;
405 0 : return NS_OK;
406 : }
407 :
408 : NS_IMETHODIMP
409 0 : nsNSSASN1PrintableItem::SetType(PRUint32 aType)
410 : {
411 0 : mType = aType;
412 0 : return NS_OK;
413 : }
414 :
415 : NS_IMETHODIMP
416 0 : nsNSSASN1PrintableItem::SetData(char *data, PRUint32 len)
417 : {
418 0 : if (len > 0) {
419 0 : if (mLen < len) {
420 0 : unsigned char* newData = (unsigned char*)nsMemory::Realloc(mData, len);
421 0 : if (!newData)
422 0 : return NS_ERROR_OUT_OF_MEMORY;
423 :
424 0 : mData = newData;
425 : }
426 :
427 0 : memcpy(mData, data, len);
428 0 : } else if (len == 0) {
429 0 : if (mData) {
430 0 : nsMemory::Free(mData);
431 0 : mData = nsnull;
432 : }
433 : }
434 0 : mLen = len;
435 0 : return NS_OK;
436 : }
437 :
438 : NS_IMETHODIMP
439 0 : nsNSSASN1PrintableItem::GetData(char **outData, PRUint32 *outLen)
440 : {
441 0 : NS_ENSURE_ARG_POINTER(outData);
442 0 : NS_ENSURE_ARG_POINTER(outLen);
443 :
444 0 : *outData = (char*)mData;
445 0 : *outLen = mLen;
446 0 : return NS_OK;
447 : }
448 :
449 : /* attribute wstring displayName; */
450 : NS_IMETHODIMP
451 0 : nsNSSASN1PrintableItem::GetDisplayName(nsAString &aDisplayName)
452 : {
453 0 : aDisplayName = mDisplayName;
454 0 : return NS_OK;
455 : }
456 :
457 : NS_IMETHODIMP
458 0 : nsNSSASN1PrintableItem::SetDisplayName(const nsAString &aDisplayName)
459 : {
460 0 : mDisplayName = aDisplayName;
461 0 : return NS_OK;
462 : }
463 :
|