PageRenderTime 44ms CodeModel.GetById 16ms app.highlight 24ms RepoModel.GetById 1ms app.codeStats 0ms

/security/manager/ssl/src/nsNSSASN1Object.cpp

http://github.com/zpao/v8monkey
C++ | 463 lines | 340 code | 55 blank | 68 comment | 36 complexity | 5eef80c97a73d43043375712aab69e2a MD5 | raw file
  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
 45NS_IMPL_THREADSAFE_ISUPPORTS2(nsNSSASN1Sequence, nsIASN1Sequence, 
 46                                                 nsIASN1Object)
 47NS_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.
 56static int
 57getInteger256(unsigned char *data, unsigned int nb)
 58{
 59    int val;
 60
 61    switch (nb) {
 62      case 1:
 63        val = data[0];
 64        break;
 65      case 2:
 66        val = (data[0] << 8) | data[1];
 67        break;
 68      case 3:
 69        val = (data[0] << 16) | (data[1] << 8) | data[2];
 70        break;
 71      case 4:
 72        val = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
 73        break;
 74      default:
 75        return -1;
 76    }
 77
 78    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>
 89static PRInt32
 90getDERItemLength(unsigned char *data, unsigned char *end,
 91                 unsigned long *bytesUsed, bool *indefinite)
 92{
 93  unsigned char lbyte = *data++;
 94  PRInt32 length = -1;
 95  
 96  *indefinite = false;
 97  if (lbyte >= 0x80) {
 98    // Multibyte length
 99    unsigned nb = (unsigned) (lbyte & 0x7f);
100    if (nb > 4) {
101      return -1;
102    }
103    if (nb > 0) {
104    
105      if ((data+nb) > end) {
106        return -1;
107      }
108      length = getInteger256(data, nb);
109      if (length < 0)
110        return -1;
111    } else {
112      *indefinite = true;
113      length = 0;
114    }
115    *bytesUsed = nb+1;
116  } else {
117    length = lbyte;
118    *bytesUsed = 1; 
119  }
120  return length;
121}
122
123static nsresult
124buildASN1ObjectFromDER(unsigned char *data,
125                       unsigned char *end,
126                       nsIASN1Sequence *parent)
127{
128  nsresult rv;
129  nsCOMPtr<nsIASN1Sequence> sequence;
130  nsCOMPtr<nsIASN1PrintableItem> printableItem;
131  nsCOMPtr<nsIASN1Object> asn1Obj;
132  nsCOMPtr<nsIMutableArray> parentObjects;
133
134  NS_ENSURE_ARG_POINTER(parent);
135  if (data >= end)
136    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  rv = parent->GetASN1Objects(getter_AddRefs(parentObjects));
152  if (NS_FAILED(rv) || parentObjects == nsnull)
153    return NS_ERROR_FAILURE;
154  while (data < end) {
155    code = *data;
156    tagnum = code & SEC_ASN1_TAGNUM_MASK;
157
158    /*
159     * NOTE: This code does not (yet) handle the high-tag-number form!
160     */
161    if (tagnum == SEC_ASN1_HIGH_TAG_NUMBER) {
162      return NS_ERROR_FAILURE;
163    }
164    data++;
165    len = getDERItemLength(data, end, &bytesUsed, &indefinite);
166    data += bytesUsed;
167    if ((len < 0) || ((data+len) > end))
168      return NS_ERROR_FAILURE;
169
170    if (code & SEC_ASN1_CONSTRUCTED) {
171      if (len > 0 || indefinite) {
172        sequence = new nsNSSASN1Sequence();
173        switch (code & SEC_ASN1_CLASS_MASK) {
174        case SEC_ASN1_UNIVERSAL:
175          type = tagnum;
176          break;
177        case SEC_ASN1_APPLICATION:
178          type = nsIASN1Object::ASN1_APPLICATION;
179          break;
180        case SEC_ASN1_CONTEXT_SPECIFIC:
181          type = nsIASN1Object::ASN1_CONTEXT_SPECIFIC;
182          break;
183        case SEC_ASN1_PRIVATE:
184          type = nsIASN1Object::ASN1_PRIVATE;
185          break;
186        default:
187          NS_ERROR("Bad DER");
188          return NS_ERROR_FAILURE;
189        }
190        sequence->SetTag(tagnum);
191        sequence->SetType(type);
192        rv = buildASN1ObjectFromDER(data, (len == 0) ? end : data + len, 
193                                    sequence);
194        asn1Obj = sequence;
195      }
196    } else {
197      printableItem = new nsNSSASN1PrintableItem();
198
199      asn1Obj = printableItem;
200      asn1Obj->SetType(tagnum);
201      asn1Obj->SetTag(tagnum); 
202      printableItem->SetData((char*)data, len);
203    }
204    data += len;
205    parentObjects->AppendElement(asn1Obj, false);
206  }
207
208  return NS_OK;
209}
210
211nsresult
212CreateFromDER(unsigned char *data,
213              unsigned int   len,
214              nsIASN1Object **retval)
215{
216  nsCOMPtr<nsIASN1Sequence> sequence = new nsNSSASN1Sequence;
217  *retval = nsnull;
218  
219  nsresult rv =  buildASN1ObjectFromDER(data, data+len, sequence);
220
221  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    nsCOMPtr<nsIMutableArray> elements;
225
226    sequence->GetASN1Objects(getter_AddRefs(elements));
227    nsCOMPtr<nsIASN1Object> asn1Obj = do_QueryElementAt(elements, 0);
228    *retval = asn1Obj;
229    if (*retval == nsnull)
230      return NS_ERROR_FAILURE;
231
232    NS_ADDREF(*retval);
233      
234  }
235  return rv; 
236}
237
238nsNSSASN1Sequence::nsNSSASN1Sequence() : mType(0),
239                                         mTag(0),
240                                         mIsValidContainer(true),
241                                         mIsExpanded(true)
242{
243  /* member initializers and constructor code */
244}
245
246nsNSSASN1Sequence::~nsNSSASN1Sequence()
247{
248  /* destructor code */
249}
250
251NS_IMETHODIMP 
252nsNSSASN1Sequence::GetASN1Objects(nsIMutableArray * *aASN1Objects)
253{
254  if (mASN1Objects == nsnull) {
255    mASN1Objects = do_CreateInstance(NS_ARRAY_CONTRACTID);
256  }
257  *aASN1Objects = mASN1Objects;
258  NS_IF_ADDREF(*aASN1Objects);
259  return NS_OK;
260}
261
262NS_IMETHODIMP 
263nsNSSASN1Sequence::SetASN1Objects(nsIMutableArray * aASN1Objects)
264{
265  mASN1Objects = aASN1Objects;
266  return NS_OK;
267}
268
269NS_IMETHODIMP 
270nsNSSASN1Sequence::GetTag(PRUint32 *aTag)
271{
272  *aTag = mTag;
273  return NS_OK;
274}
275
276NS_IMETHODIMP 
277nsNSSASN1Sequence::SetTag(PRUint32 aTag)
278{
279  mTag = aTag;
280  return NS_OK;
281}
282
283NS_IMETHODIMP 
284nsNSSASN1Sequence::GetType(PRUint32 *aType)
285{
286  *aType = mType;
287  return NS_OK;
288}
289
290NS_IMETHODIMP 
291nsNSSASN1Sequence::SetType(PRUint32 aType)
292{
293  mType = aType;
294  return NS_OK;
295}
296
297NS_IMETHODIMP 
298nsNSSASN1Sequence::GetDisplayName(nsAString &aDisplayName)
299{
300  aDisplayName = mDisplayName;
301  return NS_OK;
302}
303
304NS_IMETHODIMP 
305nsNSSASN1Sequence::SetDisplayName(const nsAString &aDisplayName)
306{
307  mDisplayName = aDisplayName;
308  return NS_OK;
309}
310
311NS_IMETHODIMP 
312nsNSSASN1Sequence::GetDisplayValue(nsAString &aDisplayValue)
313{
314  aDisplayValue = mDisplayValue;
315  return NS_OK;
316}
317
318NS_IMETHODIMP 
319nsNSSASN1Sequence::SetDisplayValue(const nsAString &aDisplayValue)
320{
321  mDisplayValue = aDisplayValue;
322  return NS_OK;
323}
324
325NS_IMETHODIMP 
326nsNSSASN1Sequence::GetIsValidContainer(bool *aIsValidContainer)
327{
328  NS_ENSURE_ARG_POINTER(aIsValidContainer);
329  *aIsValidContainer = mIsValidContainer;
330  return NS_OK;
331}
332
333NS_IMETHODIMP
334nsNSSASN1Sequence::SetIsValidContainer(bool aIsValidContainer)
335{
336  mIsValidContainer = aIsValidContainer;
337  SetIsExpanded(mIsValidContainer);
338  return NS_OK;
339}
340
341NS_IMETHODIMP 
342nsNSSASN1Sequence::GetIsExpanded(bool *aIsExpanded)
343{
344  NS_ENSURE_ARG_POINTER(aIsExpanded);
345  *aIsExpanded = mIsExpanded;
346  return NS_OK;
347}
348
349NS_IMETHODIMP 
350nsNSSASN1Sequence::SetIsExpanded(bool aIsExpanded)
351{
352  mIsExpanded = aIsExpanded;
353  return NS_OK;
354}
355
356
357nsNSSASN1PrintableItem::nsNSSASN1PrintableItem() : mType(0),
358                                                   mTag(0),
359                                                   mData(nsnull),
360                                                   mLen(0)
361{
362  /* member initializers and constructor code */
363}
364
365nsNSSASN1PrintableItem::~nsNSSASN1PrintableItem()
366{
367  /* destructor code */
368  if (mData)
369    nsMemory::Free(mData);
370}
371
372/* readonly attribute wstring value; */
373NS_IMETHODIMP 
374nsNSSASN1PrintableItem::GetDisplayValue(nsAString &aValue)
375{
376  aValue = mValue;
377  return NS_OK;
378}
379
380NS_IMETHODIMP 
381nsNSSASN1PrintableItem::SetDisplayValue(const nsAString &aValue)
382{
383  mValue = aValue;
384  return NS_OK;
385}
386
387NS_IMETHODIMP 
388nsNSSASN1PrintableItem::GetTag(PRUint32 *aTag)
389{
390  *aTag = mTag;
391  return NS_OK;
392}
393
394NS_IMETHODIMP 
395nsNSSASN1PrintableItem::SetTag(PRUint32 aTag)
396{
397  mTag = aTag;
398  return NS_OK;
399}
400
401NS_IMETHODIMP 
402nsNSSASN1PrintableItem::GetType(PRUint32 *aType)
403{
404  *aType = mType;
405  return NS_OK;
406}
407
408NS_IMETHODIMP 
409nsNSSASN1PrintableItem::SetType(PRUint32 aType)
410{
411  mType = aType;
412  return NS_OK;
413}
414
415NS_IMETHODIMP 
416nsNSSASN1PrintableItem::SetData(char *data, PRUint32 len)
417{
418  if (len > 0) {
419    if (mLen < len) {
420      unsigned char* newData = (unsigned char*)nsMemory::Realloc(mData, len);
421      if (!newData)
422        return NS_ERROR_OUT_OF_MEMORY;
423
424      mData = newData;
425    }
426
427    memcpy(mData, data, len);
428  } else if (len == 0) {
429    if (mData) {
430      nsMemory::Free(mData);
431      mData = nsnull;
432    }
433  }
434  mLen = len;
435  return NS_OK;  
436}
437
438NS_IMETHODIMP
439nsNSSASN1PrintableItem::GetData(char **outData, PRUint32 *outLen)
440{
441  NS_ENSURE_ARG_POINTER(outData);
442  NS_ENSURE_ARG_POINTER(outLen);
443
444  *outData = (char*)mData;
445  *outLen  = mLen;
446  return NS_OK;
447}
448
449/* attribute wstring displayName; */
450NS_IMETHODIMP 
451nsNSSASN1PrintableItem::GetDisplayName(nsAString &aDisplayName)
452{
453  aDisplayName = mDisplayName;
454  return NS_OK;
455}
456
457NS_IMETHODIMP 
458nsNSSASN1PrintableItem::SetDisplayName(const nsAString &aDisplayName)
459{
460  mDisplayName = aDisplayName;
461  return NS_OK;
462}
463