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