mouse07410 / asn1c

The ASN.1 Compiler
http://lionet.info/asn1c/
BSD 2-Clause "Simplified" License
97 stars 71 forks source link

How to encode a buffer into der we don't know the size of the buffer #196

Closed chetanpandey1266 closed 1 month ago

chetanpandey1266 commented 2 months ago

I was trying to encode a buffer to ber but I don't know the exact size of the buffer.

I tried doing this

size = der_encode_to_buffer(&asn_DEF_type, struct_ptr, *buffer, 1000).encoded

Assuming that the size of the buffer will be less than 1000 But this way I have to choose a upper limit which is hard to define so I tried this

size = der_encode_to_buffer(&asn_DEF_type, struct_ptr, NULL, 0).encoded
der_encode_to_buffer(&asn_DEF_type, struct_ptr, *buffer, size)

But this is giving error

So is there a way to determine the size of the encoded buffer?

mouse07410 commented 2 months ago
  1. would you mind employing more traditional coding style? E.g., using explicit variables for return structures?
  2. From the ...enc_ret_t - verify and print return code, don't blindly assume it all good.
  3. "gives an error" isn't enough for me to investigate - please be (much) more specific.
mouse07410 commented 1 month ago

I found this issue to be a user error, as the following program works fine with the current repo:

/****************************************************/
/* Sample program to experiment with DER encoding   */
/* of PrintableString.                              */
/*                                                  */
/* The goal is to show that issue #196 can be       */
/* closed as a "user error".                        */
/*                                                  */
/* Copyright (C) Mouse (MIT) 2024                   */
/****************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <memory.h>

#include "Tstr.h"

/*
 Attempting to work with ASN.1 file

Tstr DEFINITIONS ::= BEGIN

    Tstr ::= SEQUENCE {
        len   INTEGER (1..63), -- Value range constraint
        val   PrintableString (FROM("?".."Z") ^ SIZE(1..63)), -- string constrained in size and content
        v2    PrintableString (FROM("A".."G") ^ SIZE(1..63))
    }

END

*/

/* Converts array of bytes to printable hex. Note: caller must free *result */
void bin_to_strhex(const unsigned char * bin,
    const size_t binsz, char ** result) {
    char hex_str[] = "0123456789abcdef";
    unsigned int i;

    if (!bin) {
        result = NULL;
        return;
    }
    * result = (char * ) malloc(binsz * 2 + 1);
    ( * result)[binsz * 2] = 0;

    if (binsz == 0)
        return;

    for (i = 0; i < binsz; i++) {
        ( * result)[i * 2 + 0] = hex_str[(bin[i] >> 4) & 0x0F];
        ( * result)[i * 2 + 1] = hex_str[(bin[i]) & 0x0F];
    }
}

int main(int argc, char * argv[]) {
    Tstr_t * t_p = NULL; /* pointer to Tstr PDU to assemble it in */
    char * hex_buf = (char * ) calloc(1024, sizeof(char));

    asn_enc_rval_t er;
    asn_dec_rval_t dec_ret;

    size_t buf_len = 0;

    const char * str_to_use = "TESTING?";
    const char * s2_to_use = "ABCDEFGA";
    printf("\nStarting the DER/BER test...\n\n");

    t_p = (Tstr_t * ) calloc(1, sizeof(Tstr_t));
    if (t_p == NULL) {
        fprintf(stderr, "Failed to allocate memory for Tstr_t... Leaving...\n");
        goto end;
    }

    /* Fill the allocated structure with values */
    t_p -> len = strlen(str_to_use); /* should be 8 */
    int rc = OCTET_STRING_fromBuf( & (t_p -> val), str_to_use, t_p -> len);
    if (rc != 0) {
        fprintf(stderr, "Failed to create OCTET STRING val from byte array...\n");
        fprintf(stderr, "proceeding to see if constraints violation would be caught by other components as well...\n");
    }
    rc = OCTET_STRING_fromBuf( & (t_p -> v2), s2_to_use, strlen(s2_to_use));
    if (rc != 0) {
        fprintf(stderr, "Failed to create OCTET STRING v2 from byte array...\n");
        fprintf(stderr, "proceeding to see if constraints violation would be caught by other components as well...\n");
    }

    /* Check before encoding that constraints set in ASN.1 spec are satisfied */
    char errbuf[128]; /* buffer to hold error msg in text form */
    size_t errlen = sizeof(errbuf);
    memset(errbuf, 0x0, sizeof(errbuf));
    int constraints_status = asn_check_constraints( & asn_DEF_Tstr, t_p, errbuf, & errlen);
    if (constraints_status != 0) {
        fprintf(stderr, "Failed to validate constraints! %s %d\n", errbuf, constraints_status);
        fprintf(stderr, "proceeding to see if constraints violation would be caught by other components as well...\n");
        fflush(stderr);
    } else {
        printf("\nValidated constraints on Tstr_t PDU\n\n");
    }

    /* Print it out as XER for visual check */
    printf("Visual check of created Tstr_t PDU:\n");
    xer_fprint(stdout, & asn_DEF_Tstr, t_p);
    printf("\n");

    /* Do some DER to satisfy issue #196 */
    printf("DER encoding using _to_buffer()...\n");
    void * der_buf = NULL; /* buffer for DER-encoded PDU */
    er = asn_encode_to_buffer(NULL, ATS_DER,
        (const asn_TYPE_descriptor_t * )( & asn_DEF_Tstr),
        t_p, NULL, 0);
    if (er.encoded < 0) {
        fprintf(stderr,
            "Failed to determine required buffer size for DER-encoded Tstr PDU (rc=%ld)\n",
            er.encoded);
        perror(NULL);
        fflush(stderr);
        fflush(stdout);
        goto end;
    }
    /* Now er.encoded returns # of encoded bytes, not bits! */
    buf_len = er.encoded;
    printf("Basic DER-encoded Tstr_t PDU requires buffer of %ld bytes\n", buf_len);
    fflush(stdout);
    der_buf = (void * ) calloc(1, buf_len);
    asn_enc_rval_t er1 = asn_encode_to_buffer(NULL, ATS_DER,
        (const asn_TYPE_descriptor_t * )( & asn_DEF_Tstr),
        t_p, der_buf, buf_len);
    if (er1.encoded < 0) {
        fprintf(stderr,
            "Failed to DER-encode Tstr_t PDU (rc=%ld)\n", er1.encoded);
        perror(NULL);
        fflush(stderr);
        fflush(stdout);
        goto end;
    }
    printf("\nSuccessfully DER-encoded Tstr_t PDU (%ld bytes):\n", er.encoded);
    bin_to_strhex(der_buf, er.encoded, & hex_buf);
    printf("%s\n\n", hex_buf);
    fflush(stderr);
    fflush(stdout);

    /* BER decode */
    Tstr_t * ber_dec = NULL;
    dec_ret = ber_decode(0, & asn_DEF_Tstr, (void ** ) & ber_dec, der_buf, buf_len);
    if (dec_ret.consumed < 1) {
        fprintf(stderr,
            "Failed to BER-decode Tstr_t PDU...(consumed=%ld)\n",
            dec_ret.consumed);
        perror(NULL);
        fflush(stderr);
        fflush(stdout);
        goto end;
    }
    printf("\nSuccessfully DER-decoded Tstr_t PDU (consumed=%ld)\n\n",
        dec_ret.consumed);
    printf("Visual check:\n");
    xer_fprint(stdout, & asn_DEF_Tstr, ber_dec);
    printf("\n");

    /* And practice freeing things... */
    end:
        printf("\nfreeing all the buffers...\n");
    if (t_p) {
        //printf("freeing Tstr_t PDU object\n");
        ASN_STRUCT_FREE(asn_DEF_Tstr, t_p); /* Tstr PDU */
        t_p = NULL;
    }
    if (ber_dec) {
        //printf("freeing decoded Tstr_t PDU object\n");
        ASN_STRUCT_FREE(asn_DEF_Tstr, ber_dec);
        ber_dec = NULL;
    }

    printf("\nFinishing the DER/BER test.\n\n");
    return 0;
}