Coverage Report

Created: 2018-09-25 14:53

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