1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/manager/ssl/src/nsNSSASN1Object.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,428 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +#include "nsNSSASN1Object.h" 1.8 +#include "nsIComponentManager.h" 1.9 +#include "secasn1.h" 1.10 +#include "nsReadableUtils.h" 1.11 +#include "nsIMutableArray.h" 1.12 +#include "nsArrayUtils.h" 1.13 +#include "nsXPCOMCID.h" 1.14 + 1.15 +NS_IMPL_ISUPPORTS(nsNSSASN1Sequence, nsIASN1Sequence, nsIASN1Object) 1.16 +NS_IMPL_ISUPPORTS(nsNSSASN1PrintableItem, nsIASN1PrintableItem, nsIASN1Object) 1.17 + 1.18 +// This function is used to interpret an integer that 1.19 +// was encoded in a DER buffer. This function is used 1.20 +// when converting a DER buffer into a nsIASN1Object 1.21 +// structure. This interprets the buffer in data 1.22 +// as defined by the DER (Distinguised Encoding Rules) of 1.23 +// ASN1. 1.24 +static int 1.25 +getInteger256(unsigned char *data, unsigned int nb) 1.26 +{ 1.27 + int val; 1.28 + 1.29 + switch (nb) { 1.30 + case 1: 1.31 + val = data[0]; 1.32 + break; 1.33 + case 2: 1.34 + val = (data[0] << 8) | data[1]; 1.35 + break; 1.36 + case 3: 1.37 + val = (data[0] << 16) | (data[1] << 8) | data[2]; 1.38 + break; 1.39 + case 4: 1.40 + val = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; 1.41 + break; 1.42 + default: 1.43 + return -1; 1.44 + } 1.45 + 1.46 + return val; 1.47 +} 1.48 + 1.49 +// This function is used to retrieve the lenght of a DER encoded 1.50 +// item. It looks to see if this a multibyte length and then 1.51 +// interprets the buffer accordingly to get the actual length value. 1.52 +// This funciton is used mostly while parsing the DER headers. 1.53 +// 1.54 +// A DER encoded item has the following structure: 1.55 +// 1.56 +// <tag><length<data consisting of lenght bytes> 1.57 +static int32_t 1.58 +getDERItemLength(unsigned char *data, unsigned char *end, 1.59 + unsigned long *bytesUsed, bool *indefinite) 1.60 +{ 1.61 + unsigned char lbyte = *data++; 1.62 + int32_t length = -1; 1.63 + 1.64 + *indefinite = false; 1.65 + if (lbyte >= 0x80) { 1.66 + // Multibyte length 1.67 + unsigned nb = (unsigned) (lbyte & 0x7f); 1.68 + if (nb > 4) { 1.69 + return -1; 1.70 + } 1.71 + if (nb > 0) { 1.72 + 1.73 + if ((data+nb) > end) { 1.74 + return -1; 1.75 + } 1.76 + length = getInteger256(data, nb); 1.77 + if (length < 0) 1.78 + return -1; 1.79 + } else { 1.80 + *indefinite = true; 1.81 + length = 0; 1.82 + } 1.83 + *bytesUsed = nb+1; 1.84 + } else { 1.85 + length = lbyte; 1.86 + *bytesUsed = 1; 1.87 + } 1.88 + return length; 1.89 +} 1.90 + 1.91 +static nsresult 1.92 +buildASN1ObjectFromDER(unsigned char *data, 1.93 + unsigned char *end, 1.94 + nsIASN1Sequence *parent) 1.95 +{ 1.96 + nsresult rv; 1.97 + nsCOMPtr<nsIASN1Sequence> sequence; 1.98 + nsCOMPtr<nsIASN1PrintableItem> printableItem; 1.99 + nsCOMPtr<nsIASN1Object> asn1Obj; 1.100 + nsCOMPtr<nsIMutableArray> parentObjects; 1.101 + 1.102 + NS_ENSURE_ARG_POINTER(parent); 1.103 + if (data >= end) 1.104 + return NS_OK; 1.105 + 1.106 + unsigned char code, tagnum; 1.107 + 1.108 + // A DER item has the form of |tag|len|data 1.109 + // tag is one byte and describes the type of element 1.110 + // we are dealing with. 1.111 + // len is a DER encoded int telling us how long the data is 1.112 + // data is a buffer that is len bytes long and has to be 1.113 + // interpreted according to its type. 1.114 + unsigned long bytesUsed; 1.115 + bool indefinite; 1.116 + int32_t len; 1.117 + uint32_t type; 1.118 + 1.119 + rv = parent->GetASN1Objects(getter_AddRefs(parentObjects)); 1.120 + if (NS_FAILED(rv) || !parentObjects) 1.121 + return NS_ERROR_FAILURE; 1.122 + while (data < end) { 1.123 + code = *data; 1.124 + tagnum = code & SEC_ASN1_TAGNUM_MASK; 1.125 + 1.126 + /* 1.127 + * NOTE: This code does not (yet) handle the high-tag-number form! 1.128 + */ 1.129 + if (tagnum == SEC_ASN1_HIGH_TAG_NUMBER) { 1.130 + return NS_ERROR_FAILURE; 1.131 + } 1.132 + data++; 1.133 + len = getDERItemLength(data, end, &bytesUsed, &indefinite); 1.134 + data += bytesUsed; 1.135 + if ((len < 0) || ((data+len) > end)) 1.136 + return NS_ERROR_FAILURE; 1.137 + 1.138 + if (code & SEC_ASN1_CONSTRUCTED) { 1.139 + if (len > 0 || indefinite) { 1.140 + sequence = new nsNSSASN1Sequence(); 1.141 + switch (code & SEC_ASN1_CLASS_MASK) { 1.142 + case SEC_ASN1_UNIVERSAL: 1.143 + type = tagnum; 1.144 + break; 1.145 + case SEC_ASN1_APPLICATION: 1.146 + type = nsIASN1Object::ASN1_APPLICATION; 1.147 + break; 1.148 + case SEC_ASN1_CONTEXT_SPECIFIC: 1.149 + type = nsIASN1Object::ASN1_CONTEXT_SPECIFIC; 1.150 + break; 1.151 + case SEC_ASN1_PRIVATE: 1.152 + type = nsIASN1Object::ASN1_PRIVATE; 1.153 + break; 1.154 + default: 1.155 + NS_ERROR("Bad DER"); 1.156 + return NS_ERROR_FAILURE; 1.157 + } 1.158 + sequence->SetTag(tagnum); 1.159 + sequence->SetType(type); 1.160 + rv = buildASN1ObjectFromDER(data, (len == 0) ? end : data + len, 1.161 + sequence); 1.162 + asn1Obj = sequence; 1.163 + } 1.164 + } else { 1.165 + printableItem = new nsNSSASN1PrintableItem(); 1.166 + 1.167 + asn1Obj = printableItem; 1.168 + asn1Obj->SetType(tagnum); 1.169 + asn1Obj->SetTag(tagnum); 1.170 + printableItem->SetData((char*)data, len); 1.171 + } 1.172 + data += len; 1.173 + parentObjects->AppendElement(asn1Obj, false); 1.174 + } 1.175 + 1.176 + return NS_OK; 1.177 +} 1.178 + 1.179 +nsresult 1.180 +CreateFromDER(unsigned char *data, 1.181 + unsigned int len, 1.182 + nsIASN1Object **retval) 1.183 +{ 1.184 + nsCOMPtr<nsIASN1Sequence> sequence = new nsNSSASN1Sequence; 1.185 + *retval = nullptr; 1.186 + 1.187 + nsresult rv = buildASN1ObjectFromDER(data, data+len, sequence); 1.188 + 1.189 + if (NS_SUCCEEDED(rv)) { 1.190 + // The actual object will be the first element inserted 1.191 + // into the sequence of the sequence variable we created. 1.192 + nsCOMPtr<nsIMutableArray> elements; 1.193 + 1.194 + sequence->GetASN1Objects(getter_AddRefs(elements)); 1.195 + nsCOMPtr<nsIASN1Object> asn1Obj = do_QueryElementAt(elements, 0); 1.196 + *retval = asn1Obj; 1.197 + if (!*retval) 1.198 + return NS_ERROR_FAILURE; 1.199 + 1.200 + NS_ADDREF(*retval); 1.201 + 1.202 + } 1.203 + return rv; 1.204 +} 1.205 + 1.206 +nsNSSASN1Sequence::nsNSSASN1Sequence() : mType(0), 1.207 + mTag(0), 1.208 + mIsValidContainer(true), 1.209 + mIsExpanded(true) 1.210 +{ 1.211 + /* member initializers and constructor code */ 1.212 +} 1.213 + 1.214 +nsNSSASN1Sequence::~nsNSSASN1Sequence() 1.215 +{ 1.216 + /* destructor code */ 1.217 +} 1.218 + 1.219 +NS_IMETHODIMP 1.220 +nsNSSASN1Sequence::GetASN1Objects(nsIMutableArray * *aASN1Objects) 1.221 +{ 1.222 + if (!mASN1Objects) { 1.223 + mASN1Objects = do_CreateInstance(NS_ARRAY_CONTRACTID); 1.224 + } 1.225 + *aASN1Objects = mASN1Objects; 1.226 + NS_IF_ADDREF(*aASN1Objects); 1.227 + return NS_OK; 1.228 +} 1.229 + 1.230 +NS_IMETHODIMP 1.231 +nsNSSASN1Sequence::SetASN1Objects(nsIMutableArray * aASN1Objects) 1.232 +{ 1.233 + mASN1Objects = aASN1Objects; 1.234 + return NS_OK; 1.235 +} 1.236 + 1.237 +NS_IMETHODIMP 1.238 +nsNSSASN1Sequence::GetTag(uint32_t *aTag) 1.239 +{ 1.240 + *aTag = mTag; 1.241 + return NS_OK; 1.242 +} 1.243 + 1.244 +NS_IMETHODIMP 1.245 +nsNSSASN1Sequence::SetTag(uint32_t aTag) 1.246 +{ 1.247 + mTag = aTag; 1.248 + return NS_OK; 1.249 +} 1.250 + 1.251 +NS_IMETHODIMP 1.252 +nsNSSASN1Sequence::GetType(uint32_t *aType) 1.253 +{ 1.254 + *aType = mType; 1.255 + return NS_OK; 1.256 +} 1.257 + 1.258 +NS_IMETHODIMP 1.259 +nsNSSASN1Sequence::SetType(uint32_t aType) 1.260 +{ 1.261 + mType = aType; 1.262 + return NS_OK; 1.263 +} 1.264 + 1.265 +NS_IMETHODIMP 1.266 +nsNSSASN1Sequence::GetDisplayName(nsAString &aDisplayName) 1.267 +{ 1.268 + aDisplayName = mDisplayName; 1.269 + return NS_OK; 1.270 +} 1.271 + 1.272 +NS_IMETHODIMP 1.273 +nsNSSASN1Sequence::SetDisplayName(const nsAString &aDisplayName) 1.274 +{ 1.275 + mDisplayName = aDisplayName; 1.276 + return NS_OK; 1.277 +} 1.278 + 1.279 +NS_IMETHODIMP 1.280 +nsNSSASN1Sequence::GetDisplayValue(nsAString &aDisplayValue) 1.281 +{ 1.282 + aDisplayValue = mDisplayValue; 1.283 + return NS_OK; 1.284 +} 1.285 + 1.286 +NS_IMETHODIMP 1.287 +nsNSSASN1Sequence::SetDisplayValue(const nsAString &aDisplayValue) 1.288 +{ 1.289 + mDisplayValue = aDisplayValue; 1.290 + return NS_OK; 1.291 +} 1.292 + 1.293 +NS_IMETHODIMP 1.294 +nsNSSASN1Sequence::GetIsValidContainer(bool *aIsValidContainer) 1.295 +{ 1.296 + NS_ENSURE_ARG_POINTER(aIsValidContainer); 1.297 + *aIsValidContainer = mIsValidContainer; 1.298 + return NS_OK; 1.299 +} 1.300 + 1.301 +NS_IMETHODIMP 1.302 +nsNSSASN1Sequence::SetIsValidContainer(bool aIsValidContainer) 1.303 +{ 1.304 + mIsValidContainer = aIsValidContainer; 1.305 + SetIsExpanded(mIsValidContainer); 1.306 + return NS_OK; 1.307 +} 1.308 + 1.309 +NS_IMETHODIMP 1.310 +nsNSSASN1Sequence::GetIsExpanded(bool *aIsExpanded) 1.311 +{ 1.312 + NS_ENSURE_ARG_POINTER(aIsExpanded); 1.313 + *aIsExpanded = mIsExpanded; 1.314 + return NS_OK; 1.315 +} 1.316 + 1.317 +NS_IMETHODIMP 1.318 +nsNSSASN1Sequence::SetIsExpanded(bool aIsExpanded) 1.319 +{ 1.320 + mIsExpanded = aIsExpanded; 1.321 + return NS_OK; 1.322 +} 1.323 + 1.324 + 1.325 +nsNSSASN1PrintableItem::nsNSSASN1PrintableItem() : mType(0), 1.326 + mTag(0), 1.327 + mData(nullptr), 1.328 + mLen(0) 1.329 +{ 1.330 + /* member initializers and constructor code */ 1.331 +} 1.332 + 1.333 +nsNSSASN1PrintableItem::~nsNSSASN1PrintableItem() 1.334 +{ 1.335 + /* destructor code */ 1.336 + if (mData) 1.337 + nsMemory::Free(mData); 1.338 +} 1.339 + 1.340 +/* readonly attribute wstring value; */ 1.341 +NS_IMETHODIMP 1.342 +nsNSSASN1PrintableItem::GetDisplayValue(nsAString &aValue) 1.343 +{ 1.344 + aValue = mValue; 1.345 + return NS_OK; 1.346 +} 1.347 + 1.348 +NS_IMETHODIMP 1.349 +nsNSSASN1PrintableItem::SetDisplayValue(const nsAString &aValue) 1.350 +{ 1.351 + mValue = aValue; 1.352 + return NS_OK; 1.353 +} 1.354 + 1.355 +NS_IMETHODIMP 1.356 +nsNSSASN1PrintableItem::GetTag(uint32_t *aTag) 1.357 +{ 1.358 + *aTag = mTag; 1.359 + return NS_OK; 1.360 +} 1.361 + 1.362 +NS_IMETHODIMP 1.363 +nsNSSASN1PrintableItem::SetTag(uint32_t aTag) 1.364 +{ 1.365 + mTag = aTag; 1.366 + return NS_OK; 1.367 +} 1.368 + 1.369 +NS_IMETHODIMP 1.370 +nsNSSASN1PrintableItem::GetType(uint32_t *aType) 1.371 +{ 1.372 + *aType = mType; 1.373 + return NS_OK; 1.374 +} 1.375 + 1.376 +NS_IMETHODIMP 1.377 +nsNSSASN1PrintableItem::SetType(uint32_t aType) 1.378 +{ 1.379 + mType = aType; 1.380 + return NS_OK; 1.381 +} 1.382 + 1.383 +NS_IMETHODIMP 1.384 +nsNSSASN1PrintableItem::SetData(char *data, uint32_t len) 1.385 +{ 1.386 + if (len > 0) { 1.387 + if (mLen < len) { 1.388 + unsigned char* newData = (unsigned char*)nsMemory::Realloc(mData, len); 1.389 + if (!newData) 1.390 + return NS_ERROR_OUT_OF_MEMORY; 1.391 + 1.392 + mData = newData; 1.393 + } 1.394 + 1.395 + memcpy(mData, data, len); 1.396 + } else if (len == 0) { 1.397 + if (mData) { 1.398 + nsMemory::Free(mData); 1.399 + mData = nullptr; 1.400 + } 1.401 + } 1.402 + mLen = len; 1.403 + return NS_OK; 1.404 +} 1.405 + 1.406 +NS_IMETHODIMP 1.407 +nsNSSASN1PrintableItem::GetData(char **outData, uint32_t *outLen) 1.408 +{ 1.409 + NS_ENSURE_ARG_POINTER(outData); 1.410 + NS_ENSURE_ARG_POINTER(outLen); 1.411 + 1.412 + *outData = (char*)mData; 1.413 + *outLen = mLen; 1.414 + return NS_OK; 1.415 +} 1.416 + 1.417 +/* attribute wstring displayName; */ 1.418 +NS_IMETHODIMP 1.419 +nsNSSASN1PrintableItem::GetDisplayName(nsAString &aDisplayName) 1.420 +{ 1.421 + aDisplayName = mDisplayName; 1.422 + return NS_OK; 1.423 +} 1.424 + 1.425 +NS_IMETHODIMP 1.426 +nsNSSASN1PrintableItem::SetDisplayName(const nsAString &aDisplayName) 1.427 +{ 1.428 + mDisplayName = aDisplayName; 1.429 + return NS_OK; 1.430 +} 1.431 +