summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/util
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/util')
-rw-r--r--security/nss/lib/util/ciferfam.h3
-rw-r--r--security/nss/lib/util/exports.gyp1
-rw-r--r--security/nss/lib/util/manifest.mn2
-rw-r--r--security/nss/lib/util/nssb64d.c41
-rw-r--r--security/nss/lib/util/nssutil.def17
-rw-r--r--security/nss/lib/util/nssutil.h6
-rw-r--r--security/nss/lib/util/pkcs11n.h8
-rw-r--r--security/nss/lib/util/pkcs11uri.c833
-rw-r--r--security/nss/lib/util/pkcs11uri.h67
-rw-r--r--security/nss/lib/util/quickder.c4
-rw-r--r--security/nss/lib/util/secasn1.h12
-rw-r--r--security/nss/lib/util/secasn1d.c45
-rw-r--r--security/nss/lib/util/secport.c3
-rw-r--r--security/nss/lib/util/secport.h4
-rw-r--r--security/nss/lib/util/util.gyp1
-rw-r--r--security/nss/lib/util/utilmod.c12
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);