/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 | } |