/* Forward Declarations */
static gboolean anode_decode_anything (GNode*, Atlv*);
static gboolean anode_decode_anything_for_flags (GNode *, Atlv*, gint);
-static gboolean anode_validate_anything (GNode*);
+static gboolean anode_validate_anything (GNode*, gboolean);
static gboolean anode_encode_prepare (GNode*, gboolean want);
static gint
static gint
compare_tlvs (Atlv *tlva, Atlv *tlvb)
{
- gint la = tlva->len;
- gint lb = tlvb->len;
+ gint la = tlva->off + tlva->len;
+ gint lb = tlvb->off + tlvb->len;
gint res;
g_assert (tlva->buf);
g_assert (tlvb->buf);
- res = memcmp (tlva->buf + tlva->off, tlvb->buf + tlvb->off, MIN (la, lb));
+ res = memcmp (tlva->buf, tlvb->buf, MIN (la, lb));
if (la == lb || res != 0)
return res;
return la < lb ? -1 : 1;
}
gboolean
-egg_asn1x_decode (GNode *asn, gconstpointer data, gsize n_data)
+egg_asn1x_decode_no_validate (GNode *asn,
+ gconstpointer data,
+ gsize n_data)
{
Atlv tlv;
- g_return_val_if_fail (asn, FALSE);
- g_return_val_if_fail (data, FALSE);
- g_return_val_if_fail (n_data, FALSE);
-
egg_asn1x_clear (asn);
if (!anode_decode_tlv_for_data (data, (const guchar*)data + n_data, &tlv))
if (tlv.end - tlv.buf != n_data)
return FALSE;
- return egg_asn1x_validate (asn);
+ return TRUE;
+}
+
+gboolean
+egg_asn1x_decode (GNode *asn,
+ gconstpointer data,
+ gsize n_data)
+{
+ gboolean ret;
+
+ g_return_val_if_fail (asn, FALSE);
+ g_return_val_if_fail (data, FALSE);
+ g_return_val_if_fail (n_data, FALSE);
+
+ ret = egg_asn1x_decode_no_validate (asn, data, n_data);
+ if (!ret)
+ return ret;
+
+ return egg_asn1x_validate (asn, TRUE);
}
/* -----------------------------------------------------------------------------------
return NULL;
if (anode_encode_build (asn, data, length) &&
- anode_validate_anything (asn)) {
+ anode_validate_anything (asn, TRUE)) {
anode_encode_commit (asn);
*n_data = length;
return data;
}
static gboolean
-anode_validate_choice (GNode *node)
+anode_validate_choice (GNode *node,
+ gboolean strict)
{
GNode *child, *choice;
Anode *an;
if (!choice)
return anode_failure (node, "one choice must be set");
- if (!anode_validate_anything (choice))
+ if (!anode_validate_anything (choice, strict))
return FALSE;
for (child = node->children; child; child = child->next) {
}
static gboolean
-anode_validate_sequence_or_set (GNode *node)
+anode_validate_sequence_or_set (GNode *node,
+ gboolean strict)
{
GNode *child;
gulong tag = 0;
/* All of the children must validate properly */
for (child = node->children; child; child = child->next) {
- if (!anode_validate_anything (child))
+ if (!anode_validate_anything (child, strict))
return FALSE;
/* Tags must be in ascending order */
}
static gboolean
-anode_validate_sequence_or_set_of (GNode *node)
+anode_validate_sequence_or_set_of (GNode *node,
+ gboolean strict)
{
GNode *child;
Atlv *tlv, *ptlv;
for (child = node->children; child; child = child->next) {
tlv = anode_get_tlv_data (child);
if (tlv) {
- if (!anode_validate_anything (child))
+ if (!anode_validate_anything (child, strict))
return FALSE;
/* Tag must have same tag as top */
return anode_failure (node, "invalid mismatched content");
/* Set of must be in ascending order */
- if (type == TYPE_SET_OF && ptlv && compare_tlvs (ptlv, tlv) > 0)
+ if (strict && type == TYPE_SET_OF &&
+ ptlv != NULL && compare_tlvs (ptlv, tlv) > 0)
return anode_failure (node, "content must be in ascending order");
ptlv = tlv;
++count;
}
static gboolean
-anode_validate_anything (GNode *node)
+anode_validate_anything (GNode *node,
+ gboolean strict)
{
Atlv *tlv;
gint type;
case TYPE_ANY:
return TRUE;
case TYPE_CHOICE:
- return anode_validate_choice (node);
+ return anode_validate_choice (node, strict);
/* Structured types */
case TYPE_SEQUENCE:
case TYPE_SET:
- return anode_validate_sequence_or_set (node);
+ return anode_validate_sequence_or_set (node, strict);
case TYPE_SEQUENCE_OF:
case TYPE_SET_OF:
- return anode_validate_sequence_or_set_of (node);
+ return anode_validate_sequence_or_set_of (node, strict);
default:
g_return_val_if_reached (FALSE);
}
gboolean
-egg_asn1x_validate (GNode *asn)
+egg_asn1x_validate (GNode *asn,
+ gboolean strict)
{
g_return_val_if_fail (asn, FALSE);
- return anode_validate_anything (asn);
+ return anode_validate_anything (asn, strict);
}
/* -----------------------------------------------------------------------------------
* PKCS12
*/
+static GNode *
+decode_pkcs12_asn1_accepting_invalid_crap (const ASN1_ARRAY_TYPE *defs,
+ const gchar *identifier,
+ gconstpointer data,
+ gsize n_data)
+{
+ GNode *asn;
+
+ /*
+ * Because PKCS#12 files, the bags specifically, are notorious for
+ * being crappily constructed and are often break rules such as DER
+ * sorting order etc.. we parse the DER in a non-strict fashion.
+ *
+ * The rules in DER are designed for X.509 certificates, so there is
+ * only one way to represent a given certificate (although they fail
+ * at that as well). But with PKCS#12 we don't have such high
+ * requirements, and we can slack off on our validation.
+ */
+
+ asn = egg_asn1x_create (defs, identifier);
+ g_return_val_if_fail (asn != NULL, NULL);
+
+ /* Passing FALSE as the strictness argument */
+ if (!egg_asn1x_decode_no_validate (asn, data, n_data) ||
+ !egg_asn1x_validate (asn, FALSE)) {
+ egg_asn1x_destroy (asn);
+ asn = NULL;
+ }
+
+ return asn;
+}
+
static gint
handle_pkcs12_cert_bag (GcrParser *self, const guchar *data, gsize n_data)
{
gint ret;
ret = GCR_ERROR_UNRECOGNIZED;
- asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-12-CertBag", data, n_data);
+ asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
+ "pkcs-12-CertBag",
+ data, n_data);
if (!asn)
goto done;
ret = GCR_ERROR_UNRECOGNIZED;
- asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-12-SafeContents", data, n_data);
+ asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
+ "pkcs-12-SafeContents",
+ data, n_data);
if (!asn)
goto done;
ret = GCR_ERROR_UNRECOGNIZED;
- asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-EncryptedData", data, n_data);
+ asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
+ "pkcs-7-EncryptedData",
+ data, n_data);
if (!asn)
goto done;
ret = GCR_ERROR_UNRECOGNIZED;
- asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-12-AuthenticatedSafe", data, n_data);
+ asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
+ "pkcs-12-AuthenticatedSafe",
+ data, n_data);
if (!asn)
goto done;
if (oid == GCR_OID_PKCS7_DATA) {
egg_asn1x_destroy (asn_content);
- asn_content = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-Data", bag, n_bag);
+ asn_content = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
+ "pkcs-7-Data",
+ bag, n_bag);
if (!asn_content)
goto done;
ret = GCR_ERROR_UNRECOGNIZED;
- asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-12-PFX", data, n_data);
+ asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab, "pkcs-12-PFX",
+ data, n_data);
if (!asn)
goto done;
if (!element)
goto done;
- asn_content = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-Data", element, n_element);
+ asn_content = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab, "pkcs-7-Data",
+ element, n_element);
if (!asn_content)
goto done;