summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2020-04-23 09:51:15 +0200
committerWerner Koch <wk@gnupg.org>2020-04-23 09:51:15 +0200
commit5d015b38eb9f828acf522fa89e4944f3b343678c (patch)
tree8a3debe73942a0b6659736ccc04b5f7616d52039
parentsm: Support import of PKCS#12 encoded ECC private keys. (diff)
downloadgnupg2-5d015b38eb9f828acf522fa89e4944f3b343678c.tar.xz
gnupg2-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 <wk@gnupg.org>
-rw-r--r--common/tlv.c101
-rw-r--r--common/tlv.h12
2 files changed, 111 insertions, 2 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. */
diff --git a/common/tlv.h b/common/tlv.h
index ba4ea2e42..0c915e63f 100644
--- a/common/tlv.h
+++ b/common/tlv.h
@@ -30,6 +30,7 @@
#ifndef SCD_TLV_H
#define SCD_TLV_H 1
+#include "membuf.h"
enum tlv_tag_class {
CLASS_UNIVERSAL = 0,
@@ -86,13 +87,20 @@ const unsigned char *find_tlv_unchecked (const unsigned char *buffer,
size_t length,
int tag, size_t *nbytes);
+/* Wite a TLV header to MEMBUF. */
+void put_tlv_to_membuf (membuf_t *membuf, int class, int tag,
+ int constructed, size_t length);
+
+/* Count the length of a to be constructed TLV. */
+size_t get_tlv_length (int class, int tag, int constructed, size_t 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. */
gpg_error_t parse_ber_header (unsigned char const **buffer, size_t *size,
- int *r_class, int *r_tag,
- int *r_constructed,
+ int *r_class, int *r_tag,
+ int *r_constructed,
int *r_ndef, size_t *r_length, size_t *r_nhdr);