Skip to content

Commit

Permalink
considerable improvements to ASN.1 BER/DER encoding.
Browse files Browse the repository at this point in the history
  • Loading branch information
dannyniu committed Oct 4, 2023
1 parent ef0d84e commit 41c0fb2
Show file tree
Hide file tree
Showing 10 changed files with 312 additions and 343 deletions.
1 change: 1 addition & 0 deletions src/0-exec/struct-delta.c.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

static inline void *DeltaAdd(void *base, ptrdiff_t offset)
{
if( !base ) return NULL;
return (uint8_t *)base + offset;
}

Expand Down
131 changes: 131 additions & 0 deletions src/2-asn1/der-codec.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,95 @@ size_t ber_push_tag(uint8_t **stack, uint32_t val, int pc)
else return 0;
}

size_t ber_put_tag(uint8_t *buf, uint32_t val, int pc)
{
uint8_t tagflags = ((6 & (val >> 28)) | (pc & 1)) << 5;
val &= BER_TLV_TAG_MAX;

if( val < (uint32_t)1 << 5 )
{
if( buf ) *buf++ = tagflags | val;
return 1;
}

else if( val < (uint32_t)1 << (7 * 1) )
{
if( buf )
{
*buf++ = tagflags | 31;
*buf++ = val;
}
return 2;
}

else if( val < (uint32_t)1 << (7 * 2) )
{
if( buf )
{
*buf++ = tagflags | 31;
*buf++ = (0x7f & (val >> 7)) | 0x80;
*buf++ = 0x7f & val;
}
return 3;
}

else if( val < (uint32_t)1 << (7 * 3) )
{
if( buf )
{
*buf++ = tagflags | 31;
*buf++ = (0x7f & (val >> 14)) | 0x80;
*buf++ = (0x7f & (val >> 7)) | 0x80;
*buf++ = 0x7f & val;
}
return 4;
}

else if( val < (uint32_t)1 << (7 * 4) )
{
if( buf )
{
*buf++ = tagflags | 31;
*buf++ = (0x7f & (val >> 21)) | 0x80;
*buf++ = (0x7f & (val >> 14)) | 0x80;
*buf++ = (0x7f & (val >> 7)) | 0x80;
*buf++ = 0x7f & val;
}
return 5;
}

else return 0;
}

size_t ber_put_len(uint8_t *buf, size_t val)
{
if( val < 0x80 )
{
if( buf )
{
*buf++ = val;
}
return 1;
}

else
{
size_t ret = 0, i;
while( (val >> (8*ret)) > 0 ) ret++;

if( buf )
{
*buf++ = 0x80 | ret;
for(i=ret; i-->0; )
{
*buf++ = val >> (8 * i);
}
}

return ret + 1;
}
}

void *ber_util_splice_insert(
void *buf, size_t len1,
ptrdiff_t offset, size_t len2)
Expand Down Expand Up @@ -324,3 +413,45 @@ IntPtr ber_tlv_encode_integer(BER_TLV_ENCODING_FUNC_PARAMS)

return ret;
}

IntPtr ber_tlv_put_integer(BER_TLV_ENCODING_FUNC_PARAMS)
{
size_t ret = 0, hdr;
size_t i;
const vlong_t *w = any;

// 2023-10-05:
// this function has error return values,
// so the [ber-int-err-chk:2021-02-13] note
// doesn't apply to it.

// This function handles only unsigned integers.
ret = w->c * sizeof(uint32_t) + 1;
for(i=w->c; --i < w->c; )
{
if( w->v[i] < UINT32_C(1) << 31 ) ret--;
if( w->v[i] < UINT32_C(1) << 23 ) ret--;
if( w->v[i] < UINT32_C(1) << 15 ) ret--;
if( w->v[i] < UINT32_C(1) << 7 ) ret--;
if( w->v[i] ) break;
}

hdr = ber_put_tag(NULL, BER_TLV_TAG_UNI(2), 0) + ber_put_len(NULL, ret);

if( !enc ) return ret + hdr;
if( enclen < ret + hdr ) return -1;

enc += ber_put_tag(enc, BER_TLV_TAG_UNI(2), 0);
enc += ber_put_len(enc, ret);

for(i=0; i<ret; i++) // i is the byte position in enc,
{
uint32_t u, v; // v is the shift amount,
u = ret - i - 1;
v = (u % sizeof(uint32_t)) * 8;
u /= sizeof(uint32_t); // u is the position in vlong.
enc[i] = u < w->c ? (w->v[u] >> v) : 0;
}

return ret + hdr;
}
10 changes: 10 additions & 0 deletions src/2-asn1/der-codec.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ void *ber_util_splice_insert(
void *buf, size_t len1,
ptrdiff_t offset, size_t len2);

// 2023-10-05:
// New (supposedly) more efficient way to encode DER.
// The following 2 functions assume the initial value
// of ``buf'' can hold both of their maximum output.
#define TAGLEN_MAX 16
size_t ber_put_tag(uint8_t *buf, uint32_t val, int pc);
size_t ber_put_len(uint8_t *buf, size_t val);

//
// A ``ber_tlv_{de,en}coding_func'' have 2 passes,
//
Expand Down Expand Up @@ -87,4 +95,6 @@ typedef IntPtr (*ber_tlv_encoding_func)(BER_TLV_ENCODING_FUNC_PARAMS);
IntPtr ber_tlv_decode_integer(BER_TLV_DECODING_FUNC_PARAMS);
IntPtr ber_tlv_encode_integer(BER_TLV_ENCODING_FUNC_PARAMS);

IntPtr ber_tlv_put_integer(BER_TLV_ENCODING_FUNC_PARAMS);

#endif /* MySuiteA_der_parse_h */
6 changes: 4 additions & 2 deletions src/2-rsa/rsa-privkey-codec-der-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ void dump_ctx_words(const uint32_t *ctx, size_t size)
#define dump_ctx_words(...) ((void)0)
#endif /* DUMP_CONTEXT_WORDS */

#include "../test-utils.c.h"

int main(int argc, char *argv[])
{
FILE *fp;
Expand All @@ -46,7 +48,7 @@ int main(int argc, char *argv[])

// decoding test.

size = ber_tlv_decode_RSAPrivateKey(NULL, buf, len);
size = ber_tlv_decode_RSAPrivateKey(NULL, buf, len); //dumphex(buf,len);
printf("1st pass decoding returned: %ld\n", size);

ctx = malloc(size);
Expand All @@ -62,7 +64,7 @@ int main(int argc, char *argv[])
size = ber_tlv_encode_RSAPrivateKey(ctx, NULL, 0);
printf("1st pass encoding returned: %ld\n", size);

size = ber_tlv_encode_RSAPrivateKey(ctx, buf2, len);
size = ber_tlv_encode_RSAPrivateKey(ctx, buf2, len); //dumphex(buf2,len);

if( memcmp(buf, buf2, len) )
{
Expand Down
5 changes: 3 additions & 2 deletions src/2-rsa/rsa-privkey-codec-der-test.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#!/bin/sh

optimize=true
optimize=debug
testfunc() {
$exec ../tests/rsa-1440-3primes.der
#lldb --\
$exec ../tests/rsa-1440-3primes.der
}

cd "$(dirname "$0")"
Expand Down
Loading

0 comments on commit 41c0fb2

Please sign in to comment.