diff options
Diffstat (limited to 'security/nss/lib/util')
-rw-r--r-- | security/nss/lib/util/ciferfam.h | 3 | ||||
-rw-r--r-- | security/nss/lib/util/exports.gyp | 1 | ||||
-rw-r--r-- | security/nss/lib/util/manifest.mn | 2 | ||||
-rw-r--r-- | security/nss/lib/util/nssb64d.c | 41 | ||||
-rw-r--r-- | security/nss/lib/util/nssutil.def | 17 | ||||
-rw-r--r-- | security/nss/lib/util/nssutil.h | 6 | ||||
-rw-r--r-- | security/nss/lib/util/pkcs11n.h | 8 | ||||
-rw-r--r-- | security/nss/lib/util/pkcs11uri.c | 833 | ||||
-rw-r--r-- | security/nss/lib/util/pkcs11uri.h | 67 | ||||
-rw-r--r-- | security/nss/lib/util/quickder.c | 4 | ||||
-rw-r--r-- | security/nss/lib/util/secasn1.h | 12 | ||||
-rw-r--r-- | security/nss/lib/util/secasn1d.c | 45 | ||||
-rw-r--r-- | security/nss/lib/util/secport.c | 3 | ||||
-rw-r--r-- | security/nss/lib/util/secport.h | 4 | ||||
-rw-r--r-- | security/nss/lib/util/util.gyp | 1 | ||||
-rw-r--r-- | security/nss/lib/util/utilmod.c | 12 |
16 files changed, 1030 insertions, 29 deletions
diff --git a/security/nss/lib/util/ciferfam.h b/security/nss/lib/util/ciferfam.h index 559e92f1d..68caa4f8b 100644 --- a/security/nss/lib/util/ciferfam.h +++ b/security/nss/lib/util/ciferfam.h @@ -52,6 +52,9 @@ #define PKCS12_RC4_128 (CIPHER_FAMILYID_PKCS12 | 0012) #define PKCS12_DES_56 (CIPHER_FAMILYID_PKCS12 | 0021) #define PKCS12_DES_EDE3_168 (CIPHER_FAMILYID_PKCS12 | 0022) +#define PKCS12_AES_CBC_128 (CIPHER_FAMILYID_PKCS12 | 0031) +#define PKCS12_AES_CBC_192 (CIPHER_FAMILYID_PKCS12 | 0032) +#define PKCS12_AES_CBC_256 (CIPHER_FAMILYID_PKCS12 | 0033) /* SMIME version numbers are negative, to avoid colliding with SSL versions */ #define SMIME_LIBRARY_VERSION_1_0 -0x0100 diff --git a/security/nss/lib/util/exports.gyp b/security/nss/lib/util/exports.gyp index eb220d2db..9ed0c1685 100644 --- a/security/nss/lib/util/exports.gyp +++ b/security/nss/lib/util/exports.gyp @@ -30,6 +30,7 @@ 'pkcs11p.h', 'pkcs11t.h', 'pkcs11u.h', + 'pkcs11uri.h', 'pkcs1sig.h', 'portreg.h', 'secasn1.h', diff --git a/security/nss/lib/util/manifest.mn b/security/nss/lib/util/manifest.mn index f0a9fd0f2..b33a2049d 100644 --- a/security/nss/lib/util/manifest.mn +++ b/security/nss/lib/util/manifest.mn @@ -41,6 +41,7 @@ EXPORTS = \ utilrename.h \ utilpars.h \ utilparst.h \ + pkcs11uri.h \ $(NULL) PRIVATE_EXPORTS = \ @@ -76,6 +77,7 @@ CSRCS = \ utf8.c \ utilmod.c \ utilpars.c \ + pkcs11uri.c \ $(NULL) MODULE = nss diff --git a/security/nss/lib/util/nssb64d.c b/security/nss/lib/util/nssb64d.c index ceb0b8ca6..886ce21c0 100644 --- a/security/nss/lib/util/nssb64d.c +++ b/security/nss/lib/util/nssb64d.c @@ -704,9 +704,8 @@ NSSBase64_DecodeBuffer(PLArenaPool *arenaOpt, SECItem *outItemOpt, { SECItem *out_item = NULL; PRUint32 max_out_len = 0; - PRUint32 out_len; void *mark = NULL; - unsigned char *dummy; + unsigned char *dummy = NULL; if ((outItemOpt != NULL && outItemOpt->data != NULL) || inLen == 0) { PORT_SetError(SEC_ERROR_INVALID_ARGS); @@ -717,33 +716,35 @@ NSSBase64_DecodeBuffer(PLArenaPool *arenaOpt, SECItem *outItemOpt, mark = PORT_ArenaMark(arenaOpt); max_out_len = PL_Base64MaxDecodedLength(inLen); + if (max_out_len == 0) { + goto loser; + } out_item = SECITEM_AllocItem(arenaOpt, outItemOpt, max_out_len); if (out_item == NULL) { - if (arenaOpt != NULL) - PORT_ArenaRelease(arenaOpt, mark); - return NULL; + goto loser; } dummy = PL_Base64DecodeBuffer(inStr, inLen, out_item->data, - max_out_len, &out_len); + max_out_len, &out_item->len); if (dummy == NULL) { - if (arenaOpt != NULL) { - PORT_ArenaRelease(arenaOpt, mark); - if (outItemOpt != NULL) { - outItemOpt->data = NULL; - outItemOpt->len = 0; - } - } else { - SECITEM_FreeItem(out_item, - (outItemOpt == NULL) ? PR_TRUE : PR_FALSE); - } - return NULL; + goto loser; } - - if (arenaOpt != NULL) + if (arenaOpt != NULL) { PORT_ArenaUnmark(arenaOpt, mark); - out_item->len = out_len; + } return out_item; + +loser: + if (arenaOpt != NULL) { + PORT_ArenaRelease(arenaOpt, mark); + if (outItemOpt != NULL) { + outItemOpt->data = NULL; + outItemOpt->len = 0; + } + } else if (dummy == NULL) { + SECITEM_FreeItem(out_item, (PRBool)(outItemOpt == NULL)); + } + return NULL; } /* diff --git a/security/nss/lib/util/nssutil.def b/security/nss/lib/util/nssutil.def index e4a65726b..f4b9ef7ba 100644 --- a/security/nss/lib/util/nssutil.def +++ b/security/nss/lib/util/nssutil.def @@ -290,3 +290,20 @@ PORT_DestroyCheapArena; ;+ local: ;+ *; ;+}; +;+NSSUTIL_3.25 { # NSS Utilities 3.25 release +;+ global: +SEC_ASN1DecoderSetMaximumElementSize; +;+ local: +;+ *; +;+}; +;+NSSUTIL_3.31 { # NSS Utilities 3.31 release +;+ global: +PK11URI_CreateURI; +PK11URI_ParseURI; +PK11URI_FormatURI; +PK11URI_DestroyURI; +PK11URI_GetPathAttribute; +PK11URI_GetQueryAttribute; +;+ local: +;+ *; +;+}; diff --git a/security/nss/lib/util/nssutil.h b/security/nss/lib/util/nssutil.h index bf1feae6e..e8cb52aed 100644 --- a/security/nss/lib/util/nssutil.h +++ b/security/nss/lib/util/nssutil.h @@ -19,10 +19,10 @@ * The format of the version string should be * "<major version>.<minor version>[.<patch level>[.<build number>]][ <Beta>]" */ -#define NSSUTIL_VERSION "3.28.6" +#define NSSUTIL_VERSION "3.32.1" #define NSSUTIL_VMAJOR 3 -#define NSSUTIL_VMINOR 28 -#define NSSUTIL_VPATCH 6 +#define NSSUTIL_VMINOR 32 +#define NSSUTIL_VPATCH 1 #define NSSUTIL_VBUILD 0 #define NSSUTIL_BETA PR_FALSE diff --git a/security/nss/lib/util/pkcs11n.h b/security/nss/lib/util/pkcs11n.h index ebb812222..399d656a8 100644 --- a/security/nss/lib/util/pkcs11n.h +++ b/security/nss/lib/util/pkcs11n.h @@ -93,6 +93,8 @@ #define CKA_NSS_JPAKE_X2 (CKA_NSS + 32) #define CKA_NSS_JPAKE_X2S (CKA_NSS + 33) +#define CKA_NSS_MOZILLA_CA_POLICY (CKA_NSS + 34) + /* * Trust attributes: * @@ -222,6 +224,12 @@ #define CKM_NSS_CHACHA20_KEY_GEN (CKM_NSS + 27) #define CKM_NSS_CHACHA20_POLY1305 (CKM_NSS + 28) +/* Additional PKCS #12 PBE algorithms defined in v1.1 */ +#define CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN (CKM_NSS + 29) +#define CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN (CKM_NSS + 30) +#define CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN (CKM_NSS + 31) +#define CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN (CKM_NSS + 32) + /* * HISTORICAL: * Do not attempt to use these. They are only used by NETSCAPE's internal diff --git a/security/nss/lib/util/pkcs11uri.c b/security/nss/lib/util/pkcs11uri.c new file mode 100644 index 000000000..453440293 --- /dev/null +++ b/security/nss/lib/util/pkcs11uri.c @@ -0,0 +1,833 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "pkcs11.h" +#include "pkcs11uri.h" +#include "plarena.h" +#include "prprf.h" +#include "secport.h" + +/* Character sets used in the ABNF rules in RFC7512. */ +#define PK11URI_DIGIT "0123456789" +#define PK11URI_ALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define PK11URI_HEXDIG PK11URI_DIGIT "abcdefABCDEF" +#define PK11URI_UNRESERVED PK11URI_ALPHA PK11URI_DIGIT "-._~" +#define PK11URI_RES_AVAIL ":[]@!$'()*+,=" +#define PK11URI_PATH_RES_AVAIL PK11URI_RES_AVAIL "&" +#define PK11URI_QUERY_RES_AVAIL PK11URI_RES_AVAIL "/?|" +#define PK11URI_ATTR_NM_CHAR PK11URI_ALPHA PK11URI_DIGIT "-_" +#define PK11URI_PCHAR PK11URI_UNRESERVED PK11URI_PATH_RES_AVAIL +#define PK11URI_QCHAR PK11URI_UNRESERVED PK11URI_QUERY_RES_AVAIL + +/* Path attributes defined in RFC7512. */ +static const char *pattr_names[] = { + PK11URI_PATTR_TOKEN, + PK11URI_PATTR_MANUFACTURER, + PK11URI_PATTR_SERIAL, + PK11URI_PATTR_MODEL, + PK11URI_PATTR_LIBRARY_MANUFACTURER, + PK11URI_PATTR_LIBRARY_DESCRIPTION, + PK11URI_PATTR_LIBRARY_VERSION, + PK11URI_PATTR_OBJECT, + PK11URI_PATTR_TYPE, + PK11URI_PATTR_ID, + PK11URI_PATTR_SLOT_MANUFACTURER, + PK11URI_PATTR_SLOT_DESCRIPTION, + PK11URI_PATTR_SLOT_ID +}; + +/* Query attributes defined in RFC7512. */ +static const char *qattr_names[] = { + PK11URI_QATTR_PIN_SOURCE, + PK11URI_QATTR_PIN_VALUE, + PK11URI_QATTR_MODULE_NAME, + PK11URI_QATTR_MODULE_PATH +}; + +struct PK11URIBufferStr { + PLArenaPool *arena; + char *data; + size_t size; + size_t allocated; +}; +typedef struct PK11URIBufferStr PK11URIBuffer; + +struct PK11URIAttributeListEntryStr { + char *name; + char *value; +}; +typedef struct PK11URIAttributeListEntryStr PK11URIAttributeListEntry; + +struct PK11URIAttributeListStr { + PLArenaPool *arena; + PK11URIAttributeListEntry *attrs; + size_t num_attrs; +}; +typedef struct PK11URIAttributeListStr PK11URIAttributeList; + +struct PK11URIStr { + PLArenaPool *arena; + + PK11URIAttributeList pattrs; + PK11URIAttributeList vpattrs; + + PK11URIAttributeList qattrs; + PK11URIAttributeList vqattrs; +}; + +#define PK11URI_ARENA_SIZE 1024 + +typedef int (*PK11URIAttributeCompareNameFunc)(const char *a, const char *b); + +/* This belongs in secport.h */ +#define PORT_ArenaGrowArray(poolp, oldptr, type, oldnum, newnum) \ + (type *)PORT_ArenaGrow((poolp), (oldptr), \ + (oldnum) * sizeof(type), (newnum) * sizeof(type)) +#define PORT_ReallocArray(oldptr, type, newnum) \ + (type *)PORT_Realloc((oldptr), (newnum) * sizeof(type)) + +/* Functions for resizable buffer. */ +static SECStatus +pk11uri_AppendBuffer(PK11URIBuffer *buffer, const unsigned char *data, + size_t size) +{ + /* Check overflow. */ + if (buffer->size + size < buffer->size) + return SECFailure; + + if (buffer->size + size > buffer->allocated) { + size_t allocated = buffer->allocated * 2 + size; + if (allocated < buffer->allocated) + return SECFailure; + if (buffer->arena) + buffer->data = PORT_ArenaGrow(buffer->arena, buffer->data, + buffer->allocated, allocated); + else + buffer->data = PORT_Realloc(buffer->data, allocated); + if (buffer->data == NULL) + return SECFailure; + buffer->allocated = allocated; + } + + memcpy(&buffer->data[buffer->size], data, size); + buffer->size += size; + + return SECSuccess; +} + +static void +pk11uri_InitBuffer(PK11URIBuffer *buffer, PLArenaPool *arena) +{ + memset(buffer, 0, sizeof(PK11URIBuffer)); + buffer->arena = arena; +} + +static void +pk11uri_DestroyBuffer(PK11URIBuffer *buffer) +{ + if (buffer->arena == NULL) { + PORT_Free(buffer->data); + } +} + +/* URI encoding functions. */ +static char * +pk11uri_Escape(PLArenaPool *arena, const char *value, size_t length, + const char *available) +{ + PK11URIBuffer buffer; + const char *p; + unsigned char buf[4]; + char *result = NULL; + SECStatus ret; + + pk11uri_InitBuffer(&buffer, arena); + + for (p = value; p < value + length; p++) { + if (strchr(available, *p) == NULL) { + if (PR_snprintf((char *)buf, sizeof(buf), "%%%02X", *p) == (PRUint32)-1) { + goto fail; + } + ret = pk11uri_AppendBuffer(&buffer, buf, 3); + if (ret != SECSuccess) { + goto fail; + } + } else { + ret = pk11uri_AppendBuffer(&buffer, (const unsigned char *)p, 1); + if (ret != SECSuccess) { + goto fail; + } + } + } + buf[0] = '\0'; + ret = pk11uri_AppendBuffer(&buffer, buf, 1); + if (ret != SECSuccess) { + goto fail; + } + + /* Steal the memory allocated in buffer. */ + result = buffer.data; + buffer.data = NULL; + +fail: + pk11uri_DestroyBuffer(&buffer); + + return result; +} + +static char * +pk11uri_Unescape(PLArenaPool *arena, const char *value, size_t length) +{ + PK11URIBuffer buffer; + const char *p; + unsigned char buf[1]; + char *result = NULL; + SECStatus ret; + + pk11uri_InitBuffer(&buffer, arena); + + for (p = value; p < value + length; p++) { + if (*p == '%') { + int c; + size_t i; + + p++; + for (c = 0, i = 0; i < 2; i++) { + int h = *(p + i); + if ('0' <= h && h <= '9') { + c = (c << 4) | (h - '0'); + } else if ('a' <= h && h <= 'f') { + c = (c << 4) | (h - 'a' + 10); + } else if ('A' <= h && h <= 'F') { + c = (c << 4) | (h - 'A' + 10); + } else { + break; + } + } + if (i != 2) { + goto fail; + } + p++; + buf[0] = c; + } else { + buf[0] = *p; + } + ret = pk11uri_AppendBuffer(&buffer, buf, 1); + if (ret != SECSuccess) { + goto fail; + } + } + buf[0] = '\0'; + ret = pk11uri_AppendBuffer(&buffer, buf, 1); + if (ret != SECSuccess) { + goto fail; + } + + result = buffer.data; + buffer.data = NULL; + +fail: + pk11uri_DestroyBuffer(&buffer); + + return result; +} + +/* Functions for manipulating attributes array. */ + +/* Compare two attribute names by the array index in attr_names. Both + * attribute names must be present in attr_names, otherwise it is a + * programming error. */ +static int +pk11uri_CompareByPosition(const char *a, const char *b, + const char **attr_names, size_t num_attr_names) +{ + int i, j; + + for (i = 0; i < num_attr_names; i++) { + if (strcmp(a, attr_names[i]) == 0) { + break; + } + } + PR_ASSERT(i < num_attr_names); + + for (j = 0; j < num_attr_names; j++) { + if (strcmp(b, attr_names[j]) == 0) { + break; + } + } + PR_ASSERT(j < num_attr_names); + + return i - j; +} + +/* Those pk11uri_Compare{Path,Query}AttributeName functions are used + * to reorder attributes when inserting. */ +static int +pk11uri_ComparePathAttributeName(const char *a, const char *b) +{ + return pk11uri_CompareByPosition(a, b, pattr_names, PR_ARRAY_SIZE(pattr_names)); +} + +static int +pk11uri_CompareQueryAttributeName(const char *a, const char *b) +{ + return pk11uri_CompareByPosition(a, b, qattr_names, PR_ARRAY_SIZE(qattr_names)); +} + +static SECStatus +pk11uri_InsertToAttributeList(PK11URIAttributeList *attrs, + char *name, char *value, + PK11URIAttributeCompareNameFunc compare_name, + PRBool allow_duplicate) +{ + size_t i; + + if (attrs->arena) { + attrs->attrs = PORT_ArenaGrowArray(attrs->arena, attrs->attrs, + PK11URIAttributeListEntry, + attrs->num_attrs, + attrs->num_attrs + 1); + } else { + attrs->attrs = PORT_ReallocArray(attrs->attrs, + PK11URIAttributeListEntry, + attrs->num_attrs + 1); + } + if (attrs->attrs == NULL) { + return SECFailure; + } + + for (i = 0; i < attrs->num_attrs; i++) { + if (!allow_duplicate && strcmp(name, attrs->attrs[i].name) == 0) { + return SECFailure; + } + if (compare_name(name, attrs->attrs[i].name) < 0) { + memmove(&attrs->attrs[i + 1], &attrs->attrs[i], + sizeof(PK11URIAttributeListEntry) * (attrs->num_attrs - i)); + break; + } + } + + attrs->attrs[i].name = name; + attrs->attrs[i].value = value; + + attrs->num_attrs++; + + return SECSuccess; +} + +static SECStatus +pk11uri_InsertToAttributeListEscaped(PK11URIAttributeList *attrs, + const char *name, size_t name_size, + const char *value, size_t value_size, + PK11URIAttributeCompareNameFunc compare_name, + PRBool allow_duplicate) +{ + char *name_copy = NULL, *value_copy = NULL; + SECStatus ret; + + if (attrs->arena) { + name_copy = PORT_ArenaNewArray(attrs->arena, char, name_size + 1); + } else { + name_copy = PORT_Alloc(name_size + 1); + } + if (name_copy == NULL) { + goto fail; + } + memcpy(name_copy, name, name_size); + name_copy[name_size] = '\0'; + + value_copy = pk11uri_Unescape(attrs->arena, value, value_size); + if (value_copy == NULL) { + goto fail; + } + + ret = pk11uri_InsertToAttributeList(attrs, name_copy, value_copy, compare_name, + allow_duplicate); + if (ret != SECSuccess) { + goto fail; + } + + return ret; + +fail: + if (attrs->arena == NULL) { + PORT_Free(name_copy); + PORT_Free(value_copy); + } + + return SECFailure; +} + +static void +pk11uri_InitAttributeList(PK11URIAttributeList *attrs, PLArenaPool *arena) +{ + memset(attrs, 0, sizeof(PK11URIAttributeList)); + attrs->arena = arena; +} + +static void +pk11uri_DestroyAttributeList(PK11URIAttributeList *attrs) +{ + if (attrs->arena == NULL) { + size_t i; + + for (i = 0; i < attrs->num_attrs; i++) { + PORT_Free(attrs->attrs[i].name); + PORT_Free(attrs->attrs[i].value); + } + PORT_Free(attrs->attrs); + } +} + +static SECStatus +pk11uri_AppendAttributeListToBuffer(PK11URIBuffer *buffer, + PK11URIAttributeList *attrs, + int separator, + const char *unescaped) +{ + size_t i; + SECStatus ret; + + for (i = 0; i < attrs->num_attrs; i++) { + unsigned char sep[1]; + char *escaped; + PK11URIAttributeListEntry *attr = &attrs->attrs[i]; + + if (i > 0) { + sep[0] = separator; + ret = pk11uri_AppendBuffer(buffer, sep, 1); + if (ret != SECSuccess) { + return ret; + } + } + + ret = pk11uri_AppendBuffer(buffer, (unsigned char *)attr->name, + strlen(attr->name)); + if (ret != SECSuccess) { + return ret; + } + + sep[0] = '='; + ret = pk11uri_AppendBuffer(buffer, sep, 1); + if (ret != SECSuccess) { + return ret; + } + + escaped = pk11uri_Escape(buffer->arena, attr->value, strlen(attr->value), + unescaped); + if (escaped == NULL) { + return ret; + } + ret = pk11uri_AppendBuffer(buffer, (unsigned char *)escaped, + strlen(escaped)); + if (buffer->arena == NULL) { + PORT_Free(escaped); + } + if (ret != SECSuccess) { + return ret; + } + } + + return SECSuccess; +} + +/* Creation of PK11URI object. */ +static PK11URI * +pk11uri_AllocURI(void) +{ + PLArenaPool *arena; + PK11URI *result; + + arena = PORT_NewArena(PK11URI_ARENA_SIZE); + if (arena == NULL) { + return NULL; + } + + result = PORT_ArenaZAlloc(arena, sizeof(PK11URI)); + if (result == NULL) { + PORT_FreeArena(arena, PR_FALSE); + return NULL; + } + + result->arena = arena; + pk11uri_InitAttributeList(&result->pattrs, arena); + pk11uri_InitAttributeList(&result->vpattrs, arena); + pk11uri_InitAttributeList(&result->qattrs, arena); + pk11uri_InitAttributeList(&result->vqattrs, arena); + + return result; +} + +static SECStatus +pk11uri_InsertAttributes(PK11URIAttributeList *dest_attrs, + PK11URIAttributeList *dest_vattrs, + const PK11URIAttribute *attrs, + size_t num_attrs, + const char **attr_names, + size_t num_attr_names, + PK11URIAttributeCompareNameFunc compare_name, + PRBool allow_duplicate, + PRBool vendor_allow_duplicate) +{ + SECStatus ret; + size_t i; + + for (i = 0; i < num_attrs; i++) { + char *name, *value; + const char *p; + size_t j; + + p = attrs[i].name; + + /* The attribute must not be empty. */ + if (*p == '\0') { + return SECFailure; + } + + /* Check that the name doesn't contain invalid character. */ + for (; *p != '\0'; p++) { + if (strchr(PK11URI_ATTR_NM_CHAR, *p) == NULL) { + return SECFailure; + } + } + + name = PORT_ArenaStrdup(dest_attrs->arena, attrs[i].name); + if (name == NULL) { + return SECFailure; + } + + value = PORT_ArenaStrdup(dest_attrs->arena, attrs[i].value); + if (value == NULL) { + return SECFailure; + } + + for (j = 0; j < num_attr_names; j++) { + if (strcmp(name, attr_names[j]) == 0) { + break; + } + } + if (j < num_attr_names) { + /* Named attribute. */ + ret = pk11uri_InsertToAttributeList(dest_attrs, + name, value, + compare_name, + allow_duplicate); + if (ret != SECSuccess) { + return ret; + } + } else { + /* Vendor attribute. */ + ret = pk11uri_InsertToAttributeList(dest_vattrs, + name, value, + strcmp, + vendor_allow_duplicate); + if (ret != SECSuccess) { + return ret; + } + } + } + + return SECSuccess; +} + +PK11URI * +PK11URI_CreateURI(const PK11URIAttribute *pattrs, + size_t num_pattrs, + const PK11URIAttribute *qattrs, + size_t num_qattrs) +{ + PK11URI *result; + SECStatus ret; + + result = pk11uri_AllocURI(); + + ret = pk11uri_InsertAttributes(&result->pattrs, &result->vpattrs, + pattrs, num_pattrs, + pattr_names, PR_ARRAY_SIZE(pattr_names), + pk11uri_ComparePathAttributeName, + PR_FALSE, PR_FALSE); + if (ret != SECSuccess) { + goto fail; + } + + ret = pk11uri_InsertAttributes(&result->qattrs, &result->vqattrs, + qattrs, num_qattrs, + qattr_names, PR_ARRAY_SIZE(qattr_names), + pk11uri_CompareQueryAttributeName, + PR_FALSE, PR_TRUE); + if (ret != SECSuccess) { + goto fail; + } + + return result; + +fail: + PK11URI_DestroyURI(result); + + return NULL; +} + +/* Parsing. */ +static SECStatus +pk11uri_ParseAttributes(const char **string, + const char *stop_chars, + int separator, + const char *accept_chars, + const char **attr_names, size_t num_attr_names, + PK11URIAttributeList *attrs, + PK11URIAttributeList *vattrs, + PK11URIAttributeCompareNameFunc compare_name, + PRBool allow_duplicate, + PRBool vendor_allow_duplicate) +{ + const char *p = *string; + + for (; *p != '\0'; p++) { + const char *name_start, *name_end, *value_start, *value_end; + size_t name_length, value_length, i; + SECStatus ret; + + if (strchr(stop_chars, *p) != NULL) { + break; + } + for (name_start = p; *p != '=' && *p != '\0'; p++) { + if (strchr(PK11URI_ATTR_NM_CHAR, *p) != NULL) + continue; + + return SECFailure; + } + if (*p == '\0') { + return SECFailure; + } + name_end = p++; + + /* The attribute name must not be empty. */ + if (name_end == name_start) { + return SECFailure; + } + + for (value_start = p; *p != separator && *p != '\0'; p++) { + if (strchr(stop_chars, *p) != NULL) { + break; + } + if (strchr(accept_chars, *p) != NULL) { + continue; + } + if (*p == '%') { + const char ch2 = *++p; + if (strchr(PK11URI_HEXDIG, ch2) != NULL) { + const char ch3 = *++p; + if (strchr(PK11URI_HEXDIG, ch3) != NULL) + continue; + } + } + + return SECFailure; + } + value_end = p; + + name_length = name_end - name_start; + value_length = value_end - value_start; + + for (i = 0; i < num_attr_names; i++) { + if (name_length == strlen(attr_names[i]) && + memcmp(name_start, attr_names[i], name_length) == 0) { + break; + } + } + if (i < num_attr_names) { + /* Named attribute. */ + ret = pk11uri_InsertToAttributeListEscaped(attrs, + name_start, name_length, + value_start, value_length, + compare_name, + allow_duplicate); + if (ret != SECSuccess) { + return ret; + } + } else { + /* Vendor attribute. */ + ret = pk11uri_InsertToAttributeListEscaped(vattrs, + name_start, name_length, + value_start, value_length, + strcmp, + vendor_allow_duplicate); + if (ret != SECSuccess) { + return ret; + } + } + + if (*p == '?' || *p == '\0') { + break; + } + } + + *string = p; + return SECSuccess; +} + +PK11URI * +PK11URI_ParseURI(const char *string) +{ + PK11URI *result; + const char *p = string; + SECStatus ret; + + if (strncmp("pkcs11:", p, 7) != 0) { + return NULL; + } + p += 7; + + result = pk11uri_AllocURI(); + if (result == NULL) { + return NULL; + } + + /* Parse the path component and its attributes. */ + ret = pk11uri_ParseAttributes(&p, "?", ';', PK11URI_PCHAR, + pattr_names, PR_ARRAY_SIZE(pattr_names), + &result->pattrs, &result->vpattrs, + pk11uri_ComparePathAttributeName, + PR_FALSE, PR_FALSE); + if (ret != SECSuccess) { + goto fail; + } + + /* Parse the query component and its attributes. */ + if (*p == '?') { + p++; + ret = pk11uri_ParseAttributes(&p, "", '&', PK11URI_QCHAR, + qattr_names, PR_ARRAY_SIZE(qattr_names), + &result->qattrs, &result->vqattrs, + pk11uri_CompareQueryAttributeName, + PR_FALSE, PR_TRUE); + if (ret != SECSuccess) { + goto fail; + } + } + + return result; + +fail: + PK11URI_DestroyURI(result); + + return NULL; +} + +/* Formatting. */ +char * +PK11URI_FormatURI(PLArenaPool *arena, PK11URI *uri) +{ + PK11URIBuffer buffer; + SECStatus ret; + char *result = NULL; + + pk11uri_InitBuffer(&buffer, arena); + + ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)"pkcs11:", 7); + if (ret != SECSuccess) + goto fail; + + ret = pk11uri_AppendAttributeListToBuffer(&buffer, &uri->pattrs, ';', PK11URI_PCHAR); + if (ret != SECSuccess) { + goto fail; + } + + if (uri->pattrs.num_attrs > 0 && uri->vpattrs.num_attrs > 0) { + ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)";", 1); + if (ret != SECSuccess) { + goto fail; + } + } + + ret = pk11uri_AppendAttributeListToBuffer(&buffer, &uri->vpattrs, ';', + PK11URI_PCHAR); + if (ret != SECSuccess) { + goto fail; + } + + if (uri->qattrs.num_attrs > 0 || uri->vqattrs.num_attrs > 0) { + ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)"?", 1); + if (ret != SECSuccess) { + goto fail; + } + } + + ret = pk11uri_AppendAttributeListToBuffer(&buffer, &uri->qattrs, '&', PK11URI_QCHAR); + if (ret != SECSuccess) { + goto fail; + } + + if (uri->qattrs.num_attrs > 0 && uri->vqattrs.num_attrs > 0) { + ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)"&", 1); + if (ret != SECSuccess) { + goto fail; + } + } + + ret = pk11uri_AppendAttributeListToBuffer(&buffer, &uri->vqattrs, '&', + PK11URI_QCHAR); + if (ret != SECSuccess) { + goto fail; + } + + ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)"\0", 1); + if (ret != SECSuccess) { + goto fail; + } + + result = buffer.data; + buffer.data = NULL; + +fail: + pk11uri_DestroyBuffer(&buffer); + + return result; +} + +/* Deallocating. */ +void +PK11URI_DestroyURI(PK11URI *uri) +{ + pk11uri_DestroyAttributeList(&uri->pattrs); + pk11uri_DestroyAttributeList(&uri->vpattrs); + pk11uri_DestroyAttributeList(&uri->qattrs); + pk11uri_DestroyAttributeList(&uri->vqattrs); + PORT_FreeArena(uri->arena, PR_FALSE); +} + +/* Accessors. */ +static const char * +pk11uri_GetAttribute(PK11URIAttributeList *attrs, + PK11URIAttributeList *vattrs, + const char *name) +{ + size_t i; + + for (i = 0; i < attrs->num_attrs; i++) { + if (strcmp(name, attrs->attrs[i].name) == 0) { + return attrs->attrs[i].value; + } + } + + for (i = 0; i < vattrs->num_attrs; i++) { + if (strcmp(name, vattrs->attrs[i].name) == 0) { + return vattrs->attrs[i].value; + } + } + + return NULL; +} + +const char * +PK11URI_GetPathAttribute(PK11URI *uri, const char *name) +{ + return pk11uri_GetAttribute(&uri->pattrs, &uri->vpattrs, name); +} + +const char * +PK11URI_GetQueryAttribute(PK11URI *uri, const char *name) +{ + return pk11uri_GetAttribute(&uri->qattrs, &uri->vqattrs, name); +} diff --git a/security/nss/lib/util/pkcs11uri.h b/security/nss/lib/util/pkcs11uri.h new file mode 100644 index 000000000..662c85470 --- /dev/null +++ b/security/nss/lib/util/pkcs11uri.h @@ -0,0 +1,67 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _PKCS11URI_H_ +#define _PKCS11URI_H_ 1 + +#include "seccomon.h" + +/* Path attributes defined in RFC7512. */ +#define PK11URI_PATTR_TOKEN "token" +#define PK11URI_PATTR_MANUFACTURER "manufacturer" +#define PK11URI_PATTR_SERIAL "serial" +#define PK11URI_PATTR_MODEL "model" +#define PK11URI_PATTR_LIBRARY_MANUFACTURER "library-manufacturer" +#define PK11URI_PATTR_LIBRARY_DESCRIPTION "library-description" +#define PK11URI_PATTR_LIBRARY_VERSION "library-version" +#define PK11URI_PATTR_OBJECT "object" +#define PK11URI_PATTR_TYPE "type" +#define PK11URI_PATTR_ID "id" +#define PK11URI_PATTR_SLOT_MANUFACTURER "slot-manufacturer" +#define PK11URI_PATTR_SLOT_DESCRIPTION "slot-description" +#define PK11URI_PATTR_SLOT_ID "slot-id" + +/* Query attributes defined in RFC7512. */ +#define PK11URI_QATTR_PIN_SOURCE "pin-source" +#define PK11URI_QATTR_PIN_VALUE "pin-value" +#define PK11URI_QATTR_MODULE_NAME "module-name" +#define PK11URI_QATTR_MODULE_PATH "module-path" + +SEC_BEGIN_PROTOS + +/* A PK11URI object is an immutable structure that holds path and + * query attributes of a PKCS#11 URI. */ +struct PK11URIStr; +typedef struct PK11URIStr PK11URI; + +struct PK11URIAttributeStr { + const char *name; + const char *value; +}; +typedef struct PK11URIAttributeStr PK11URIAttribute; + +/* Create a new PK11URI object from a set of attributes. */ +extern PK11URI *PK11URI_CreateURI(const PK11URIAttribute *pattrs, + size_t num_pattrs, + const PK11URIAttribute *qattrs, + size_t num_qattrs); + +/* Parse PKCS#11 URI and return a new PK11URI object. */ +extern PK11URI *PK11URI_ParseURI(const char *string); + +/* Format a PK11URI object to a string. */ +extern char *PK11URI_FormatURI(PLArenaPool *arena, PK11URI *uri); + +/* Destroy a PK11URI object. */ +extern void PK11URI_DestroyURI(PK11URI *uri); + +/* Retrieve a path attribute with the given name. */ +extern const char *PK11URI_GetPathAttribute(PK11URI *uri, const char *name); + +/* Retrieve a query attribute with the given name. */ +extern const char *PK11URI_GetQueryAttribute(PK11URI *uri, const char *name); + +SEC_END_PROTOS + +#endif /* _PKCS11URI_H_ */ diff --git a/security/nss/lib/util/quickder.c b/security/nss/lib/util/quickder.c index 49ff14d55..1b474822e 100644 --- a/security/nss/lib/util/quickder.c +++ b/security/nss/lib/util/quickder.c @@ -408,6 +408,10 @@ DecodePointer(void* dest, { const SEC_ASN1Template* ptrTemplate = SEC_ASN1GetSubtemplate(templateEntry, dest, PR_FALSE); + if (!ptrTemplate) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } void* subdata = PORT_ArenaZAlloc(arena, ptrTemplate->size); *(void**)((char*)dest + templateEntry->offset) = subdata; if (subdata) { diff --git a/security/nss/lib/util/secasn1.h b/security/nss/lib/util/secasn1.h index b6292cd3b..78cab0a26 100644 --- a/security/nss/lib/util/secasn1.h +++ b/security/nss/lib/util/secasn1.h @@ -54,6 +54,18 @@ extern void SEC_ASN1DecoderSetNotifyProc(SEC_ASN1DecoderContext *cx, extern void SEC_ASN1DecoderClearNotifyProc(SEC_ASN1DecoderContext *cx); +/* Sets the maximum size that should be allocated for a single ASN.1 + * element. Set to 0 to indicate there is no limit. + * + * Note: This does not set the maximum size overall that may be allocated + * while parsing, nor does it guarantee that the decoder won't allocate + * more than |max_size| while parsing an individual element; rather, it + * merely guarantees that any individual allocation for returned data + * should not exceed |max_size|. +*/ +extern void SEC_ASN1DecoderSetMaximumElementSize(SEC_ASN1DecoderContext *cx, + unsigned long max_size); + extern SECStatus SEC_ASN1Decode(PLArenaPool *pool, void *dest, const SEC_ASN1Template *t, const char *buf, long len); diff --git a/security/nss/lib/util/secasn1d.c b/security/nss/lib/util/secasn1d.c index 797640dc4..e6abb5fd5 100644 --- a/security/nss/lib/util/secasn1d.c +++ b/security/nss/lib/util/secasn1d.c @@ -292,6 +292,17 @@ struct sec_DecoderContext_struct { sec_asn1d_state *current; sec_asn1d_parse_status status; + /* The maximum size the caller is willing to allow a single element + * to be before returning an error. + * + * In the case of an indefinite length element, this is the sum total + * of all child elements. + * + * In the case of a definite length element, this represents the maximum + * size of the top-level element. + */ + unsigned long max_element_size; + SEC_ASN1NotifyProc notify_proc; /* call before/after handling field */ void *notify_arg; /* argument to notify_proc */ PRBool during_notify; /* true during call to notify_proc */ @@ -1288,6 +1299,13 @@ sec_asn1d_prepare_for_contents(sec_asn1d_state *state) alloc_len += subitem->len; } + if (state->top->max_element_size > 0 && + alloc_len > state->top->max_element_size) { + PORT_SetError(SEC_ERROR_OUTPUT_LEN); + state->top->status = decodeError; + return; + } + item->data = (unsigned char *)sec_asn1d_zalloc(poolp, alloc_len); if (item->data == NULL) { state->top->status = decodeError; @@ -1396,6 +1414,13 @@ sec_asn1d_prepare_for_contents(sec_asn1d_state *state) if (state->dest != NULL) { item = (SECItem *)(state->dest); item->len = 0; + if (state->top->max_element_size > 0 && + state->contents_length > state->top->max_element_size) { + PORT_SetError(SEC_ERROR_OUTPUT_LEN); + state->top->status = decodeError; + return; + } + if (state->top->filter_only) { item->data = NULL; } else { @@ -2223,6 +2248,13 @@ sec_asn1d_concat_substrings(sec_asn1d_state *state) alloc_len = item_len; } + if (state->top->max_element_size > 0 && + alloc_len > state->top->max_element_size) { + PORT_SetError(SEC_ERROR_OUTPUT_LEN); + state->top->status = decodeError; + return; + } + item = (SECItem *)(state->dest); PORT_Assert(item != NULL); PORT_Assert(item->data == NULL); @@ -2726,7 +2758,7 @@ SEC_ASN1DecoderUpdate(SEC_ASN1DecoderContext *cx, #ifdef DEBUG_ASN1D_STATES printf("\nPLACE = %s, next byte = 0x%02x, %08x[%d]\n", (state->place >= 0 && state->place <= notInUse) ? place_names[state->place] : "(undefined)", - (unsigned int)((unsigned char *)buf)[consumed], + len ? (unsigned int)((unsigned char *)buf)[consumed] : 0, buf, consumed); dump_states(cx); #endif /* DEBUG_ASN1D_STATES */ @@ -3042,6 +3074,13 @@ SEC_ASN1DecoderClearNotifyProc(SEC_ASN1DecoderContext *cx) } void +SEC_ASN1DecoderSetMaximumElementSize(SEC_ASN1DecoderContext *cx, + unsigned long max_size) +{ + cx->max_element_size = max_size; +} + +void SEC_ASN1DecoderAbort(SEC_ASN1DecoderContext *cx, int error) { PORT_Assert(cx); @@ -3061,6 +3100,10 @@ SEC_ASN1Decode(PLArenaPool *poolp, void *dest, if (dcx == NULL) return SECFailure; + /* In one-shot mode, there's no possibility of streaming data beyond the + * length of len */ + SEC_ASN1DecoderSetMaximumElementSize(dcx, len); + urv = SEC_ASN1DecoderUpdate(dcx, buf, len); frv = SEC_ASN1DecoderFinish(dcx); diff --git a/security/nss/lib/util/secport.c b/security/nss/lib/util/secport.c index 0eea0cda0..01a7d0834 100644 --- a/security/nss/lib/util/secport.c +++ b/security/nss/lib/util/secport.c @@ -699,6 +699,9 @@ NSS_PutEnv(const char *envVarName, const char *envValue) #endif encoded = (char *)PORT_ZAlloc(strlen(envVarName) + 2 + strlen(envValue)); + if (!encoded) { + return SECFailure; + } strcpy(encoded, envVarName); strcat(encoded, "="); strcat(encoded, envValue); diff --git a/security/nss/lib/util/secport.h b/security/nss/lib/util/secport.h index 0f4b08f33..fb9ff4ebb 100644 --- a/security/nss/lib/util/secport.h +++ b/security/nss/lib/util/secport.h @@ -72,8 +72,8 @@ * and does not use a lock to protect accesses. This makes it cheaper but * less general. It is best used for arena pools that (a) are hot, (b) have * lifetimes bounded within a single function, and (c) don't need locking. - * Use PORT_InitArena() and PORT_DestroyArena() to initialize and finalize - * PORTCheapArenaPools. + * Use PORT_InitCheapArena() and PORT_DestroyCheapArena() to initialize and + * finalize PORTCheapArenaPools. * * All the other PORT_Arena* functions will operate safely with either * subclass. diff --git a/security/nss/lib/util/util.gyp b/security/nss/lib/util/util.gyp index 9f3a74b18..74eaef4bf 100644 --- a/security/nss/lib/util/util.gyp +++ b/security/nss/lib/util/util.gyp @@ -21,6 +21,7 @@ 'nssrwlk.c', 'oidstring.c', 'pkcs1sig.c', + 'pkcs11uri.c', 'portreg.c', 'quickder.c', 'secalgid.c', diff --git a/security/nss/lib/util/utilmod.c b/security/nss/lib/util/utilmod.c index e05680675..971b6c1dc 100644 --- a/security/nss/lib/util/utilmod.c +++ b/security/nss/lib/util/utilmod.c @@ -232,10 +232,15 @@ nssutil_ReadSecmodDB(const char *appName, internal = PR_FALSE; /* is this an internal module */ skipParams = PR_FALSE; /* did we find an override parameter block*/ paramsValue = NULL; /* the current parameter block value */ - while (fgets(line, sizeof(line), fd) != NULL) { - int len = PORT_Strlen(line); + do { + int len; + + if (fgets(line, sizeof(line), fd) == NULL) { + goto endloop; + } /* remove the ending newline */ + len = PORT_Strlen(line); if (len && line[len - 1] == '\n') { len--; line[len] = 0; @@ -344,6 +349,7 @@ nssutil_ReadSecmodDB(const char *appName, continue; } + endloop: /* * if we are here, we have found a complete stanza. Now write out * any param section we may have found. @@ -379,7 +385,7 @@ nssutil_ReadSecmodDB(const char *appName, moduleString = NULL; internal = PR_FALSE; skipParams = PR_FALSE; - } + } while (!feof(fd)); if (moduleString) { PORT_Free(moduleString); |