static int int_end_context(WPACKET *pkt, int tag)
{
+ /*
+ * If someone set the flag WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH on this
+ * sub-packet and this sub-packet has nothing written to it, the DER length
+ * will not be written, and the total written size will be unchanged before
+ * and after WPACKET_close(). We use size1 and size2 to determine if
+ * anything was written, and only write our tag if it has.
+ *
+ */
+ size_t size1, size2;
+
if (tag < 0)
return 1;
if (!ossl_assert(tag <= 30))
return 0;
- return WPACKET_close(pkt)
- && WPACKET_put_bytes_u8(pkt, DER_C_CONTEXT | tag);
+ return WPACKET_get_total_written(pkt, &size1)
+ && WPACKET_close(pkt)
+ && WPACKET_get_total_written(pkt, &size2)
+ && (size1 == size2 || WPACKET_put_bytes_u8(pkt, DER_C_CONTEXT | tag));
}
int DER_w_precompiled(WPACKET *pkt, int tag,
int DER_w_end_sequence(WPACKET *pkt, int tag)
{
- return WPACKET_close(pkt)
- && WPACKET_put_bytes_u8(pkt, DER_F_CONSTRUCTED | DER_P_SEQUENCE)
+ /*
+ * If someone set the flag WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH on this
+ * sub-packet and this sub-packet has nothing written to it, the DER length
+ * will not be written, and the total written size will be unchanged before
+ * and after WPACKET_close(). We use size1 and size2 to determine if
+ * anything was written, and only write our tag if it has.
+ *
+ * Because we know that int_end_context() needs to do the same check,
+ * we reproduce this flag if the written length was unchanged, or we will
+ * have an erroneous context tag.
+ */
+ size_t size1, size2;
+
+ return WPACKET_get_total_written(pkt, &size1)
+ && WPACKET_close(pkt)
+ && WPACKET_get_total_written(pkt, &size2)
+ && (size1 == size2
+ ? WPACKET_set_flags(pkt, WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH)
+ : WPACKET_put_bytes_u8(pkt, DER_F_CONSTRUCTED | DER_P_SEQUENCE))
&& int_end_context(pkt, tag);
}