aboutsummaryrefslogtreecommitdiffstats
path: root/common/tlv.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2020-04-23 07:51:15 +0000
committerWerner Koch <[email protected]>2020-04-23 07:51:15 +0000
commit5d015b38eb9f828acf522fa89e4944f3b343678c (patch)
tree8a3debe73942a0b6659736ccc04b5f7616d52039 /common/tlv.c
parentsm: Support import of PKCS#12 encoded ECC private keys. (diff)
downloadgnupg-5d015b38eb9f828acf522fa89e4944f3b343678c.tar.gz
gnupg-5d015b38eb9f828acf522fa89e4944f3b343678c.zip
common: Add functions to help create DER objects.
* common/tlv.c (put_tlv_to_membuf): New. (get_tlv_length): New. * common/tlv.h: Include membuf.h. Signed-off-by: Werner Koch <[email protected]>
Diffstat (limited to 'common/tlv.c')
-rw-r--r--common/tlv.c101
1 files changed, 101 insertions, 0 deletions
diff --git a/common/tlv.c b/common/tlv.c
index 0058b67ca..86e954a19 100644
--- a/common/tlv.c
+++ b/common/tlv.c
@@ -157,6 +157,107 @@ find_tlv_unchecked (const unsigned char *buffer, size_t length,
}
+/* Write TAG of CLASS to MEMBUF. CONSTRUCTED is a flag telling
+ * whether the value is constructed. LENGTH gives the length of the
+ * value, if it is 0 undefinite length is assumed. LENGTH is ignored
+ * for the NULL tag. TAG must be less that 0x1f. */
+void
+put_tlv_to_membuf (membuf_t *membuf, int class, int tag,
+ int constructed, size_t length)
+{
+ unsigned char buf[20];
+ int buflen = 0;
+ int i;
+
+ if (tag < 0x1f)
+ {
+ *buf = (class << 6) | tag;
+ if (constructed)
+ *buf |= 0x20;
+ buflen++;
+ }
+ else
+ BUG ();
+
+ if (!tag && !class)
+ buf[buflen++] = 0; /* end tag */
+ else if (tag == TAG_NULL && !class)
+ buf[buflen++] = 0; /* NULL tag */
+ else if (!length)
+ buf[buflen++] = 0x80; /* indefinite length */
+ else if (length < 128)
+ buf[buflen++] = length;
+ else
+ {
+ /* If we know the sizeof a size_t we could support larger
+ * objects - however this is pretty ridiculous */
+ i = (length <= 0xff ? 1:
+ length <= 0xffff ? 2:
+ length <= 0xffffff ? 3: 4);
+
+ buf[buflen++] = (0x80 | i);
+ if (i > 3)
+ buf[buflen++] = length >> 24;
+ if (i > 2)
+ buf[buflen++] = length >> 16;
+ if (i > 1)
+ buf[buflen++] = length >> 8;
+ buf[buflen++] = length;
+ }
+
+ put_membuf (membuf, buf, buflen);
+}
+
+
+/* Return the length of the to be constructed TLV. CONSTRUCTED is a
+ * flag telling whether the value is constructed. LENGTH gives the
+ * length of the value, if it is 0 undefinite length is assumed.
+ * LENGTH is ignored for the NULL tag. TAG must be less that 0x1f. */
+size_t
+get_tlv_length (int class, int tag, int constructed, size_t length)
+{
+ size_t buflen = 0;
+ int i;
+
+ (void)constructed; /* Not used, but passed for uniformity of such calls. */
+
+ if (tag < 0x1f)
+ {
+ buflen++;
+ }
+ else
+ {
+ buflen++; /* assume one and let the actual write function bail out */
+ }
+
+ if (!tag && !class)
+ buflen++; /* end tag */
+ else if (tag == TAG_NULL && !class)
+ buflen++; /* NULL tag */
+ else if (!length)
+ buflen++; /* indefinite length */
+ else if (length < 128)
+ buflen++;
+ else
+ {
+ i = (length <= 0xff ? 1:
+ length <= 0xffff ? 2:
+ length <= 0xffffff ? 3: 4);
+
+ buflen++;
+ if (i > 3)
+ buflen++;
+ if (i > 2)
+ buflen++;
+ if (i > 1)
+ buflen++;
+ buflen++;
+ }
+
+ return buflen + length;
+}
+
+
/* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
and the length part from the TLV triplet. Update BUFFER and SIZE
on success. */