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