sc_asn1_put_tag - support larger tags

Enhance sc_asn1_put_tag to support larger tag names and larger tags.
Prior to this, sc_asn1_put_tag did only support tags with a length of at most 127 bytes and tag names of one byte.
This commit is contained in:
Philip Wendland 2014-10-28 09:05:02 +01:00 committed by Viktor Tarasov
parent 3961275d8c
commit 7e7a44acff
2 changed files with 64 additions and 15 deletions

View File

@ -740,23 +740,70 @@ static int sc_asn1_decode_utf8string(const u8 *inbuf, size_t inlen,
return 0;
}
int sc_asn1_put_tag(int tag, const u8 * data, size_t datalen, u8 * out, size_t outlen, u8 **ptr)
int sc_asn1_put_tag(unsigned int tag, const u8 * data, size_t datalen, u8 * out, size_t outlen, u8 **ptr)
{
size_t c = 0;
size_t tag_len;
size_t ii;
u8 *p = out;
u8 tag_char[4] = {0, 0, 0, 0};
if (outlen < 2)
return SC_ERROR_INVALID_ARGUMENTS;
if (datalen > 127)
return SC_ERROR_INVALID_ARGUMENTS;
*p++ = tag & 0xFF; /* FIXME: Support longer tags */
outlen--;
*p++ = datalen;
outlen--;
if (outlen < datalen)
return SC_ERROR_INVALID_ARGUMENTS;
/* Check tag */
if (tag == 0 || tag > 0xFFFFFFFF) {
/* A tag of 0x00 is not valid and at most 4-byte tag names are supported. */
return SC_ERROR_INVALID_DATA;
}
for (tag_len = 0; tag; tag >>= 8) {
/* Note: tag char will be reversed order. */
tag_char[tag_len++] = tag & 0xFF;
}
memcpy(p, data, datalen);
p += datalen;
if (tag_len > 1) {
if ((tag_char[tag_len - 1] & SC_ASN1_TAG_PRIMITIVE) != SC_ASN1_TAG_ESCAPE_MARKER) {
/* First byte is not escape marker. */
return SC_ERROR_INVALID_DATA;
}
for (ii = 1; ii < tag_len - 1; ii++) {
if ((tag_char[ii] & 0x80) != 0x80) {
/* MS bit is not 'one'. */
return SC_ERROR_INVALID_DATA;
}
}
if ((tag_char[0] & 0x80) != 0x00) {
/* MS bit of the last byte is not 'zero'. */
return SC_ERROR_INVALID_DATA;
}
}
/* Calculate the number of additional bytes necessary to encode the length. */
/* c+1 is the size of the length field. */
if (datalen > 127) {
c = 1;
while (datalen >> (c << 3))
c++;
}
if (outlen == 0 || out == NULL) {
/* Caller only asks for the length that would be written. */
return tag_len + (c+1) + datalen;
}
/* We will write the tag, so check the length. */
if (outlen < tag_len + (c+1) + datalen)
return SC_ERROR_BUFFER_TOO_SMALL;
for (ii=0;ii<tag_len;ii++)
*p++ = tag_char[tag_len - ii - 1];
if (c > 0) {
*p++ = 0x80 | c;
while (c--)
*p++ = (datalen >> (c << 3)) & 0xFF;
}
else {
*p++ = datalen & 0x7F;
}
if(data && datalen > 0) {
memcpy(p, data, datalen);
p += datalen;
}
if (ptr != NULL)
*ptr = p;
return 0;

View File

@ -84,8 +84,10 @@ const u8 *sc_asn1_skip_tag(struct sc_context *ctx, const u8 ** buf,
/* DER encoding */
/* Argument 'ptr' is set to the location of the next possible ASN.1 object.
* If NULL, no action on 'ptr' is performed. */
int sc_asn1_put_tag(int tag, const u8 * data, size_t datalen, u8 * out, size_t outlen, u8 ** ptr);
* If NULL, no action on 'ptr' is performed.
* If out is NULL or outlen is zero, the length that would be written is returned.
* If data is NULL, the data field will not be written. This is helpful for constructed structures. */
int sc_asn1_put_tag(unsigned int tag, const u8 * data, size_t datalen, u8 * out, size_t outlen, u8 ** ptr);
/* ASN.1 printing functions */
void sc_asn1_print_tags(const u8 * buf, size_t buflen);