Back to index

lightning-sunbird  0.9+nobinonly
nsNSSASN1Object.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Javier Delgadillo <javi@netscape.com>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 #include "nsNSSASN1Object.h"
00038 #include "nsIComponentManager.h"
00039 #include "secasn1.h"
00040 #include "nsReadableUtils.h"
00041 #include "nsArray.h"
00042 #include "nsXPCOMCID.h"
00043 
00044 NS_IMPL_THREADSAFE_ISUPPORTS2(nsNSSASN1Sequence, nsIASN1Sequence, 
00045                                                  nsIASN1Object)
00046 NS_IMPL_THREADSAFE_ISUPPORTS2(nsNSSASN1PrintableItem, nsIASN1PrintableItem,
00047                                                       nsIASN1Object)
00048 
00049 // This function is used to interpret an integer that
00050 // was encoded in a DER buffer. This function is used
00051 // when converting a DER buffer into a nsIASN1Object 
00052 // structure.  This interprets the buffer in data
00053 // as defined by the DER (Distinguised Encoding Rules) of
00054 // ASN1.
00055 static int
00056 getInteger256(unsigned char *data, unsigned int nb)
00057 {
00058     int val;
00059 
00060     switch (nb) {
00061       case 1:
00062         val = data[0];
00063         break;
00064       case 2:
00065         val = (data[0] << 8) | data[1];
00066         break;
00067       case 3:
00068         val = (data[0] << 16) | (data[1] << 8) | data[2];
00069         break;
00070       case 4:
00071         val = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
00072         break;
00073       default:
00074         return -1;
00075     }
00076 
00077     return val;
00078 }
00079 
00080 // This function is used to retrieve the lenght of a DER encoded
00081 // item.  It looks to see if this a multibyte length and then
00082 // interprets the buffer accordingly to get the actual length value.
00083 // This funciton is used mostly while parsing the DER headers.
00084 // 
00085 // A DER encoded item has the following structure:
00086 //
00087 //  <tag><length<data consisting of lenght bytes>
00088 static PRInt32
00089 getDERItemLength(unsigned char *data, unsigned char *end,
00090                  unsigned long *bytesUsed, PRBool *indefinite)
00091 {
00092   unsigned char lbyte = *data++;
00093   PRInt32 length = -1;
00094   
00095   *indefinite = PR_FALSE;
00096   if (lbyte >= 0x80) {
00097     // Multibyte length
00098     unsigned nb = (unsigned) (lbyte & 0x7f);
00099     if (nb > 4) {
00100       return -1;
00101     }
00102     if (nb > 0) {
00103     
00104       if ((data+nb) > end) {
00105         return -1;
00106       }
00107       length = getInteger256(data, nb);
00108       if (length < 0)
00109         return -1;
00110     } else {
00111       *indefinite = PR_TRUE;
00112       length = 0;
00113     }
00114     *bytesUsed = nb+1;
00115   } else {
00116     length = lbyte;
00117     *bytesUsed = 1; 
00118   }
00119   return length;
00120 }
00121 
00122 static nsresult
00123 buildASN1ObjectFromDER(unsigned char *data,
00124                        unsigned char *end,
00125                        nsIASN1Sequence *parent)
00126 {
00127   nsresult rv;
00128   nsCOMPtr<nsIASN1Sequence> sequence;
00129   nsCOMPtr<nsIASN1PrintableItem> printableItem;
00130   nsCOMPtr<nsIASN1Object> asn1Obj;
00131   nsCOMPtr<nsIMutableArray> parentObjects;
00132 
00133   NS_ENSURE_ARG_POINTER(parent);
00134   if (data >= end)
00135     return NS_OK;
00136 
00137   unsigned char code, tagnum;
00138 
00139   // A DER item has the form of |tag|len|data
00140   // tag is one byte and describes the type of elment
00141   //     we are dealing with.
00142   // len is a DER encoded int telling us how long the data is
00143   // data is a buffer that is len bytes long and has to be
00144   //      interpreted according to its type.
00145   unsigned long bytesUsed;
00146   PRBool indefinite;
00147   PRInt32 len;
00148   PRUint32 type;
00149 
00150   if (parent == nsnull) {
00151     parent = new nsNSSASN1Sequence();
00152     NS_IF_ADDREF(parent);
00153   }
00154   if (parent == nsnull) 
00155     return NS_ERROR_FAILURE;
00156 
00157   rv = parent->GetASN1Objects(getter_AddRefs(parentObjects));
00158   if (NS_FAILED(rv) || parentObjects == nsnull)
00159     return NS_ERROR_FAILURE;
00160   while (data < end) {
00161     code = *data;
00162     tagnum = code & SEC_ASN1_TAGNUM_MASK;
00163 
00164     /*
00165      * NOTE: This code does not (yet) handle the high-tag-number form!
00166      */
00167     if (tagnum == SEC_ASN1_HIGH_TAG_NUMBER) {
00168       return NS_ERROR_FAILURE;
00169     }
00170     data++;
00171     len = getDERItemLength(data, end, &bytesUsed, &indefinite);
00172     data += bytesUsed;
00173     if ((len < 0) || ((data+len) > end))
00174       return NS_ERROR_FAILURE;
00175 
00176     if (code & SEC_ASN1_CONSTRUCTED) {
00177       if (len > 0 || indefinite) {
00178         sequence = new nsNSSASN1Sequence();
00179         switch (code & SEC_ASN1_CLASS_MASK) {
00180         case SEC_ASN1_UNIVERSAL:
00181           type = tagnum;
00182           break;
00183         case SEC_ASN1_APPLICATION:
00184           type = nsIASN1Object::ASN1_APPLICATION;
00185           break;
00186         case SEC_ASN1_CONTEXT_SPECIFIC:
00187           type = nsIASN1Object::ASN1_CONTEXT_SPECIFIC;
00188           break;
00189         case SEC_ASN1_PRIVATE:
00190           type = nsIASN1Object::ASN1_PRIVATE;
00191           break;
00192         default:
00193           NS_ASSERTION(0,"Bad DER");
00194           return NS_ERROR_FAILURE;
00195         }
00196         sequence->SetTag(tagnum);
00197         sequence->SetType(type);
00198         rv = buildASN1ObjectFromDER(data, (len == 0) ? end : data + len, 
00199                                     sequence);
00200         asn1Obj = sequence;
00201       }
00202     } else {
00203       printableItem = new nsNSSASN1PrintableItem();
00204 
00205       asn1Obj = printableItem;
00206       asn1Obj->SetType(tagnum);
00207       asn1Obj->SetTag(tagnum); 
00208       printableItem->SetData((char*)data, len);
00209     }
00210     data += len;
00211     parentObjects->AppendElement(asn1Obj, PR_FALSE);
00212   }
00213 
00214   return NS_OK;
00215 }
00216 
00217 nsresult
00218 CreateFromDER(unsigned char *data,
00219               unsigned int   len,
00220               nsIASN1Object **retval)
00221 {
00222   nsCOMPtr<nsIASN1Sequence> sequence = new nsNSSASN1Sequence;
00223   *retval = nsnull;
00224   
00225   nsresult rv =  buildASN1ObjectFromDER(data, data+len, sequence);
00226 
00227   if (NS_SUCCEEDED(rv)) {
00228     // The actual object will be the first element inserted
00229     // into the sequence of the sequence variable we created.
00230     nsCOMPtr<nsIMutableArray> elements;
00231 
00232     sequence->GetASN1Objects(getter_AddRefs(elements));
00233     nsCOMPtr<nsIASN1Object> asn1Obj = do_QueryElementAt(elements, 0);
00234     *retval = asn1Obj;
00235     if (*retval == nsnull)
00236       return NS_ERROR_FAILURE;
00237 
00238     NS_ADDREF(*retval);
00239       
00240   }
00241   return rv; 
00242 }
00243 
00244 nsNSSASN1Sequence::nsNSSASN1Sequence() : mType(0),
00245                                          mTag(0),
00246                                          mIsValidContainer(PR_TRUE),
00247                                          mIsExpanded(PR_TRUE)
00248 {
00249   /* member initializers and constructor code */
00250 }
00251 
00252 nsNSSASN1Sequence::~nsNSSASN1Sequence()
00253 {
00254   /* destructor code */
00255 }
00256 
00257 NS_IMETHODIMP 
00258 nsNSSASN1Sequence::GetASN1Objects(nsIMutableArray * *aASN1Objects)
00259 {
00260   if (mASN1Objects == nsnull) {
00261     mASN1Objects = do_CreateInstance(NS_ARRAY_CONTRACTID);
00262   }
00263   *aASN1Objects = mASN1Objects;
00264   NS_IF_ADDREF(*aASN1Objects);
00265   return NS_OK;
00266 }
00267 
00268 NS_IMETHODIMP 
00269 nsNSSASN1Sequence::SetASN1Objects(nsIMutableArray * aASN1Objects)
00270 {
00271   mASN1Objects = aASN1Objects;
00272   return NS_OK;
00273 }
00274 
00275 NS_IMETHODIMP 
00276 nsNSSASN1Sequence::GetTag(PRUint32 *aTag)
00277 {
00278   *aTag = mTag;
00279   return NS_OK;
00280 }
00281 
00282 NS_IMETHODIMP 
00283 nsNSSASN1Sequence::SetTag(PRUint32 aTag)
00284 {
00285   mTag = aTag;
00286   return NS_OK;
00287 }
00288 
00289 NS_IMETHODIMP 
00290 nsNSSASN1Sequence::GetType(PRUint32 *aType)
00291 {
00292   *aType = mType;
00293   return NS_OK;
00294 }
00295 
00296 NS_IMETHODIMP 
00297 nsNSSASN1Sequence::SetType(PRUint32 aType)
00298 {
00299   mType = aType;
00300   return NS_OK;
00301 }
00302 
00303 NS_IMETHODIMP 
00304 nsNSSASN1Sequence::GetDisplayName(nsAString &aDisplayName)
00305 {
00306   aDisplayName = mDisplayName;
00307   return NS_OK;
00308 }
00309 
00310 NS_IMETHODIMP 
00311 nsNSSASN1Sequence::SetDisplayName(const nsAString &aDisplayName)
00312 {
00313   mDisplayName = aDisplayName;
00314   return NS_OK;
00315 }
00316 
00317 NS_IMETHODIMP 
00318 nsNSSASN1Sequence::GetDisplayValue(nsAString &aDisplayValue)
00319 {
00320   aDisplayValue = mDisplayValue;
00321   return NS_OK;
00322 }
00323 
00324 NS_IMETHODIMP 
00325 nsNSSASN1Sequence::SetDisplayValue(const nsAString &aDisplayValue)
00326 {
00327   mDisplayValue = aDisplayValue;
00328   return NS_OK;
00329 }
00330 
00331 NS_IMETHODIMP 
00332 nsNSSASN1Sequence::GetIsValidContainer(PRBool *aIsValidContainer)
00333 {
00334   NS_ENSURE_ARG_POINTER(aIsValidContainer);
00335   *aIsValidContainer = mIsValidContainer;
00336   return NS_OK;
00337 }
00338 
00339 NS_IMETHODIMP
00340 nsNSSASN1Sequence::SetIsValidContainer(PRBool aIsValidContainer)
00341 {
00342   mIsValidContainer = aIsValidContainer;
00343   SetIsExpanded(mIsValidContainer);
00344   return NS_OK;
00345 }
00346 
00347 NS_IMETHODIMP 
00348 nsNSSASN1Sequence::GetIsExpanded(PRBool *aIsExpanded)
00349 {
00350   NS_ENSURE_ARG_POINTER(aIsExpanded);
00351   *aIsExpanded = mIsExpanded;
00352   return NS_OK;
00353 }
00354 
00355 NS_IMETHODIMP 
00356 nsNSSASN1Sequence::SetIsExpanded(PRBool aIsExpanded)
00357 {
00358   mIsExpanded = aIsExpanded;
00359   return NS_OK;
00360 }
00361 
00362 
00363 nsNSSASN1PrintableItem::nsNSSASN1PrintableItem() : mType(0),
00364                                                    mTag(0),
00365                                                    mData(nsnull),
00366                                                    mLen(0)
00367 {
00368   /* member initializers and constructor code */
00369 }
00370 
00371 nsNSSASN1PrintableItem::~nsNSSASN1PrintableItem()
00372 {
00373   /* destructor code */
00374   if (mData)
00375     nsMemory::Free(mData);
00376 }
00377 
00378 /* readonly attribute wstring value; */
00379 NS_IMETHODIMP 
00380 nsNSSASN1PrintableItem::GetDisplayValue(nsAString &aValue)
00381 {
00382   aValue = mValue;
00383   return NS_OK;
00384 }
00385 
00386 NS_IMETHODIMP 
00387 nsNSSASN1PrintableItem::SetDisplayValue(const nsAString &aValue)
00388 {
00389   mValue = aValue;
00390   return NS_OK;
00391 }
00392 
00393 NS_IMETHODIMP 
00394 nsNSSASN1PrintableItem::GetTag(PRUint32 *aTag)
00395 {
00396   *aTag = mTag;
00397   return NS_OK;
00398 }
00399 
00400 NS_IMETHODIMP 
00401 nsNSSASN1PrintableItem::SetTag(PRUint32 aTag)
00402 {
00403   mTag = aTag;
00404   return NS_OK;
00405 }
00406 
00407 NS_IMETHODIMP 
00408 nsNSSASN1PrintableItem::GetType(PRUint32 *aType)
00409 {
00410   *aType = mType;
00411   return NS_OK;
00412 }
00413 
00414 NS_IMETHODIMP 
00415 nsNSSASN1PrintableItem::SetType(PRUint32 aType)
00416 {
00417   mType = aType;
00418   return NS_OK;
00419 }
00420 
00421 NS_IMETHODIMP 
00422 nsNSSASN1PrintableItem::SetData(char *data, PRUint32 len)
00423 {
00424   if (len > 0) {
00425     if (mLen < len) {
00426       unsigned char* newData = (unsigned char*)nsMemory::Realloc(mData, len);
00427       if (!newData)
00428         return NS_ERROR_OUT_OF_MEMORY;
00429 
00430       mData = newData;
00431     }
00432 
00433     memcpy(mData, data, len);
00434   } else if (len == 0) {
00435     if (mData) {
00436       nsMemory::Free(mData);
00437       mData = nsnull;
00438     }
00439   }
00440   mLen = len;
00441   return NS_OK;  
00442 }
00443 
00444 NS_IMETHODIMP
00445 nsNSSASN1PrintableItem::GetData(char **outData, PRUint32 *outLen)
00446 {
00447   NS_ENSURE_ARG_POINTER(outData);
00448   NS_ENSURE_ARG_POINTER(outLen);
00449 
00450   *outData = (char*)mData;
00451   *outLen  = mLen;
00452   return NS_OK;
00453 }
00454 
00455 /* attribute wstring displayName; */
00456 NS_IMETHODIMP 
00457 nsNSSASN1PrintableItem::GetDisplayName(nsAString &aDisplayName)
00458 {
00459   aDisplayName = mDisplayName;
00460   return NS_OK;
00461 }
00462 
00463 NS_IMETHODIMP 
00464 nsNSSASN1PrintableItem::SetDisplayName(const nsAString &aDisplayName)
00465 {
00466   mDisplayName = aDisplayName;
00467   return NS_OK;
00468 }
00469