Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
418991d
Move mbedtls_asn1_write_mpi to bignum.h as it is now private
Apr 23, 2025
282822c
Add initial test for asn1 encode
Apr 28, 2025
b78910c
Added initial POC
May 1, 2025
f13eeed
Add additional test cases
May 6, 2025
e78276c
added in processor endian detection and conversion
May 27, 2025
d2633bb
Fix size check test and adjust to re-use buffer where possible
May 28, 2025
87fd8bb
tidy up of asn1 encode tests
May 28, 2025
67b7acb
remove data_t
May 28, 2025
30dd96f
Update tests and fix endian
May 28, 2025
28bd96c
Remove debug and add code to handle clause 8.3.2 of the X.690-0207 spec
May 29, 2025
4d25d3f
Remove debug lines
davidhorstmann-arm Jun 30, 2025
2a31846
tidied up error handling
May 29, 2025
819b81d
Add function docs for asn1_write
May 29, 2025
c119952
Correct return value of p after an error
May 29, 2025
2cae6ad
Improve bignum writing in asn1_write
Jun 2, 2025
c1b7fab
Add code to handle leading zero's
Jun 2, 2025
a1a7b01
Improve naming of asn1_write test cases
Jun 2, 2025
5368b6e
fix style issues and tidy up
Jun 3, 2025
1a3e2cb
Remove sign parameter
davidhorstmann-arm Jun 24, 2025
23ff8ee
Fix typo
davidhorstmann-arm Jun 24, 2025
387122d
Remove imprecise warning
davidhorstmann-arm Jun 24, 2025
72ff18c
Clarify integer start and length descriptions
davidhorstmann-arm Jun 24, 2025
4fbeec3
Rewrite function description
davidhorstmann-arm Jun 24, 2025
8492d85
Preexisting: Use the definite article in notes
davidhorstmann-arm Jun 24, 2025
e43ee4a
Rename input_buffer_size -> output_buffer_size
davidhorstmann-arm Jun 24, 2025
0cf4f8e
Remove unnecessary error checks:
davidhorstmann-arm Jun 24, 2025
e7e4257
Adjust for leading zeroes before checking space
davidhorstmann-arm Jun 24, 2025
b4e1e82
Fix buffer overread in leading-zero count
davidhorstmann-arm Jun 24, 2025
fc3827c
Add basic positive testcase
davidhorstmann-arm Jun 25, 2025
cf0da9b
Allow NULL pointers for zero-length output buffers
davidhorstmann-arm Jun 26, 2025
85ee411
Add remaining positive testcases
davidhorstmann-arm Jun 26, 2025
cdfd40f
Fix bug when dealing with the value zero
davidhorstmann-arm Jun 26, 2025
1a26241
Do not attempt to memset() a zero-length buffer
davidhorstmann-arm Jun 26, 2025
852428c
Add note about overlap
davidhorstmann-arm Jun 26, 2025
21b91d2
Remove unnecessary testcases
davidhorstmann-arm Jun 26, 2025
1036671
Remove NULL pointer checks
davidhorstmann-arm Jun 26, 2025
2df32f5
Tidy up checks for successful encoding cases
davidhorstmann-arm Jun 26, 2025
00a3949
Add extra testcases for interesting leading-zeroes
davidhorstmann-arm Jun 26, 2025
724654c
Allocate a new buffer for test inputs
davidhorstmann-arm Jun 26, 2025
cd9f70a
Set the test step
davidhorstmann-arm Jun 27, 2025
ebbbb01
Remove useless cast
davidhorstmann-arm Jun 27, 2025
0f6b5ba
Do not check for zero-length output buffers
davidhorstmann-arm Jun 27, 2025
16e2a36
Re-add zero-length test
davidhorstmann-arm Jun 27, 2025
49db86f
Remove guarantee about p on failure
davidhorstmann-arm Jun 27, 2025
4e726ae
Fix buffer overread in tests
davidhorstmann-arm Jun 27, 2025
6a525ed
Add ChangeLog entry for ASN.1 integer function
davidhorstmann-arm Jun 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions ChangeLog.d/asn1-write-integer.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Features
* Add a new function mbedtls_asn1_write_integer() that encodes an arbitrary
precision integer into ASN.1 DER format. This function replaces
mbedtls_asn1_write_mpi(), which has been made internal-only.
Removals
* Remove mbedtls_asn1_write_mpi() from the public API. This has been replaced
by mbedtls_asn1_write_integer(), which does not use the legacy mbedtls_mpi
type.
16 changes: 16 additions & 0 deletions drivers/builtin/include/mbedtls/bignum.h
Original file line number Diff line number Diff line change
Expand Up @@ -1107,6 +1107,22 @@ int mbedtls_mpi_self_test(int verbose);
#endif /* MBEDTLS_SELF_TEST */

#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */
/**
* \brief Write an arbitrary-precision number (#MBEDTLS_ASN1_INTEGER)
* in ASN.1 format.
*
* \note This function works backwards in data buffer.
*
* \param p The reference to the current position pointer.
* \param start The start of the buffer, for bounds-checking.
* \param X The MPI to write.
* It must be non-negative.
*
* \return The number of bytes written to \p p on success.
* \return A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure.
*/
int mbedtls_asn1_write_mpi(unsigned char **p, const unsigned char *start,
const mbedtls_mpi *X);

#ifdef __cplusplus
}
Expand Down
65 changes: 65 additions & 0 deletions drivers/builtin/src/asn1write.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include "mbedtls/asn1write.h"
#include "mbedtls/error_common.h"
#include "bignum_core.h"

#include <string.h>

Expand Down Expand Up @@ -434,4 +435,68 @@ mbedtls_asn1_named_data *mbedtls_asn1_store_named_data(

return cur;
}

int mbedtls_asn1_write_integer(unsigned char **p,
unsigned char *start,
const unsigned char *integer,
size_t integer_length)
{

int asn1_frame_size = 0;
unsigned int number_of_leading_zeros = 0;
size_t output_buffer_size = (*p-start);
const unsigned char *integer_start = NULL;

// asn1 specifies that the bignum must be encoded in the minimum allowable space, so leading zeros must be removed.
while ((number_of_leading_zeros < integer_length)
&& (integer[number_of_leading_zeros] == 0x0)) {
number_of_leading_zeros++;
}

integer_start = integer + number_of_leading_zeros;

integer_length -= number_of_leading_zeros;

if (output_buffer_size < integer_length) {
return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;//TC3 buffer less than integer size.
}

memset(start, 0, output_buffer_size);

/* Special case - if integer_length is zero, the value is zero and it
* should be encoded as one byte. */
if (integer_length == 0) {
if (output_buffer_size < 1) {
return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
}

*p -= 1;
integer_length = 1;

} else {

*p -= integer_length;

memcpy(*p, integer_start, integer_length);

// DER format assumes 2s complement for numbers, so the leftmost bit
// should be 0.
if (**p & 0x80) {
if (*p - start < 1) {
return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
}

*--(*p) = 0x00;
integer_length += 1;
}
}

asn1_frame_size =
mbedtls_asn1_write_len_and_tag(p, start, integer_length, MBEDTLS_ASN1_INTEGER);
if (asn1_frame_size < 0) {
return asn1_frame_size;//TC4 mbedtls_asn1_write_len_and_tag failed.
}

return asn1_frame_size;
}
#endif /* MBEDTLS_ASN1_WRITE_C */
77 changes: 42 additions & 35 deletions include/mbedtls/asn1write.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ extern "C" {
/**
* \brief Write a length field in ASN.1 format.
*
* \note This function works backwards in data buffer.
* \note This function works backwards within the data buffer.
*
* \param p The reference to the current position pointer.
* \param start The start of the buffer, for bounds-checking.
Expand All @@ -55,7 +55,7 @@ int mbedtls_asn1_write_len(unsigned char **p, const unsigned char *start,
/**
* \brief Write an ASN.1 tag in ASN.1 format.
*
* \note This function works backwards in data buffer.
* \note This function works backwards within the data buffer.
*
* \param p The reference to the current position pointer.
* \param start The start of the buffer, for bounds-checking.
Expand All @@ -72,7 +72,7 @@ int mbedtls_asn1_write_tag(unsigned char **p, const unsigned char *start,
/**
* \brief Write raw buffer data.
*
* \note This function works backwards in data buffer.
* \note This function works backwards within the data buffer.
*
* \param p The reference to the current position pointer.
* \param start The start of the buffer, for bounds-checking.
Expand All @@ -85,30 +85,11 @@ int mbedtls_asn1_write_tag(unsigned char **p, const unsigned char *start,
int mbedtls_asn1_write_raw_buffer(unsigned char **p, const unsigned char *start,
const unsigned char *buf, size_t size);

#if defined(MBEDTLS_BIGNUM_C)
/**
* \brief Write an arbitrary-precision number (#MBEDTLS_ASN1_INTEGER)
* in ASN.1 format.
*
* \note This function works backwards in data buffer.
*
* \param p The reference to the current position pointer.
* \param start The start of the buffer, for bounds-checking.
* \param X The MPI to write.
* It must be non-negative.
*
* \return The number of bytes written to \p p on success.
* \return A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure.
*/
int mbedtls_asn1_write_mpi(unsigned char **p, const unsigned char *start,
const mbedtls_mpi *X);
#endif /* MBEDTLS_BIGNUM_C */

/**
* \brief Write a NULL tag (#MBEDTLS_ASN1_NULL) with zero data
* in ASN.1 format.
*
* \note This function works backwards in data buffer.
* \note This function works backwards within the data buffer.
*
* \param p The reference to the current position pointer.
* \param start The start of the buffer, for bounds-checking.
Expand All @@ -122,7 +103,7 @@ int mbedtls_asn1_write_null(unsigned char **p, const unsigned char *start);
* \brief Write an OID tag (#MBEDTLS_ASN1_OID) and data
* in ASN.1 format.
*
* \note This function works backwards in data buffer.
* \note This function works backwards within the data buffer.
*
* \param p The reference to the current position pointer.
* \param start The start of the buffer, for bounds-checking.
Expand All @@ -138,7 +119,7 @@ int mbedtls_asn1_write_oid(unsigned char **p, const unsigned char *start,
/**
* \brief Write an AlgorithmIdentifier sequence in ASN.1 format.
*
* \note This function works backwards in data buffer.
* \note This function works backwards within the data buffer.
*
* \param p The reference to the current position pointer.
* \param start The start of the buffer, for bounds-checking.
Expand All @@ -158,7 +139,7 @@ int mbedtls_asn1_write_algorithm_identifier(unsigned char **p,
/**
* \brief Write an AlgorithmIdentifier sequence in ASN.1 format.
*
* \note This function works backwards in data buffer.
* \note This function works backwards within the data buffer.
*
* \param p The reference to the current position pointer.
* \param start The start of the buffer, for bounds-checking.
Expand All @@ -180,7 +161,7 @@ int mbedtls_asn1_write_algorithm_identifier_ext(unsigned char **p,
* \brief Write a boolean tag (#MBEDTLS_ASN1_BOOLEAN) and value
* in ASN.1 format.
*
* \note This function works backwards in data buffer.
* \note This function works backwards within the data buffer.
*
* \param p The reference to the current position pointer.
* \param start The start of the buffer, for bounds-checking.
Expand All @@ -196,7 +177,7 @@ int mbedtls_asn1_write_bool(unsigned char **p, const unsigned char *start,
* \brief Write an int tag (#MBEDTLS_ASN1_INTEGER) and value
* in ASN.1 format.
*
* \note This function works backwards in data buffer.
* \note This function works backwards within the data buffer.
*
* \param p The reference to the current position pointer.
* \param start The start of the buffer, for bounds-checking.
Expand All @@ -212,7 +193,7 @@ int mbedtls_asn1_write_int(unsigned char **p, const unsigned char *start, int va
* \brief Write an enum tag (#MBEDTLS_ASN1_ENUMERATED) and value
* in ASN.1 format.
*
* \note This function works backwards in data buffer.
* \note This function works backwards within the data buffer.
*
* \param p The reference to the current position pointer.
* \param start The start of the buffer, for bounds-checking.
Expand All @@ -227,7 +208,7 @@ int mbedtls_asn1_write_enum(unsigned char **p, const unsigned char *start, int v
* \brief Write a string in ASN.1 format using a specific
* string encoding tag.

* \note This function works backwards in data buffer.
* \note This function works backwards within the data buffer.
*
* \param p The reference to the current position pointer.
* \param start The start of the buffer, for bounds-checking.
Expand All @@ -248,7 +229,7 @@ int mbedtls_asn1_write_tagged_string(unsigned char **p, const unsigned char *sta
* \brief Write a string in ASN.1 format using the PrintableString
* string encoding tag (#MBEDTLS_ASN1_PRINTABLE_STRING).
*
* \note This function works backwards in data buffer.
* \note This function works backwards within the data buffer.
*
* \param p The reference to the current position pointer.
* \param start The start of the buffer, for bounds-checking.
Expand All @@ -267,7 +248,7 @@ int mbedtls_asn1_write_printable_string(unsigned char **p,
* \brief Write a UTF8 string in ASN.1 format using the UTF8String
* string encoding tag (#MBEDTLS_ASN1_UTF8_STRING).
*
* \note This function works backwards in data buffer.
* \note This function works backwards within the data buffer.
*
* \param p The reference to the current position pointer.
* \param start The start of the buffer, for bounds-checking.
Expand All @@ -285,7 +266,7 @@ int mbedtls_asn1_write_utf8_string(unsigned char **p, const unsigned char *start
* \brief Write a string in ASN.1 format using the IA5String
* string encoding tag (#MBEDTLS_ASN1_IA5_STRING).
*
* \note This function works backwards in data buffer.
* \note This function works backwards within the data buffer.
*
* \param p The reference to the current position pointer.
* \param start The start of the buffer, for bounds-checking.
Expand All @@ -303,7 +284,7 @@ int mbedtls_asn1_write_ia5_string(unsigned char **p, const unsigned char *start,
* \brief Write a bitstring tag (#MBEDTLS_ASN1_BIT_STRING) and
* value in ASN.1 format.
*
* \note This function works backwards in data buffer.
* \note This function works backwards within the data buffer.
*
* \param p The reference to the current position pointer.
* \param start The start of the buffer, for bounds-checking.
Expand Down Expand Up @@ -342,7 +323,7 @@ int mbedtls_asn1_write_named_bitstring(unsigned char **p,
* \brief Write an octet string tag (#MBEDTLS_ASN1_OCTET_STRING)
* and value in ASN.1 format.
*
* \note This function works backwards in data buffer.
* \note This function works backwards within the data buffer.
*
* \param p The reference to the current position pointer.
* \param start The start of the buffer, for bounds-checking.
Expand Down Expand Up @@ -381,6 +362,32 @@ mbedtls_asn1_named_data *mbedtls_asn1_store_named_data(mbedtls_asn1_named_data *
const unsigned char *val,
size_t val_len);

/**
* \brief Encode an integer into ASN.1 and write it to a buffer.
* Write the integer given in \p integer into the buffer
* given by \p *p and \p start in DER-encoded ASN.1
* representation.
*
* \note This function works backwards within the data buffer.
*
* \note This function is not guaranteed to work when the
* input and output buffers overlap.
*
* \param p The reference to the current position pointer.
* \param start The start of the buffer, for bounds-checking.
* \param integer Pointer to a big-endian representation of an integer.
* \param integer_length The number of bytes in the integer buffer.
*
* \return An integer number of bytes written on success.
* \return An appropriate error code on failure.
* \return On success p will be set to point to the start of
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor:

Suggested change
* \return On success p will be set to point to the start of
* \return On success \c *p will be set to point to the start of

* the encoded integer.
*/
int mbedtls_asn1_write_integer(unsigned char **p,
unsigned char *start,
const unsigned char *integer,
size_t integer_length);

#ifdef __cplusplus
}
#endif
Expand Down
27 changes: 27 additions & 0 deletions tests/suites/test_suite_asn1write.data
Original file line number Diff line number Diff line change
Expand Up @@ -393,3 +393,30 @@ store_named_data_val_new:4:1

Store named data: new, val_len=4, val=NULL
store_named_data_val_new:4:0

ASN.1 write integer: Basic encode
mbedtls_asn1_write_integer_positive:"0123":"02020123"

ASN.1 write integer: Leading zeroes
mbedtls_asn1_write_integer_positive:"000123":"02020123"
Comment thread
gilles-peskine-arm marked this conversation as resolved.

ASN.1 write integer: Many leading zeroes (input longer than output)
mbedtls_asn1_write_integer_positive:"000000000123":"02020123"

ASN.1 write integer: Most significant bit is 1
mbedtls_asn1_write_integer_positive:"800123":"020400800123"

ASN.1 write integer: Leading zeroes and MSb of first byte is 1
mbedtls_asn1_write_integer_positive:"000000800123":"020400800123"

ASN.1 write integer: Multibyte length (> 255)
mbedtls_asn1_write_integer_positive:"0123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF0000000000000000":"028201000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF00000000000000000123456789ABCDEF0000000000000000"

ASN.1 write integer: Zero (single-byte)
mbedtls_asn1_write_integer_positive:"00":"020100"

ASN.1 write integer: Zero (multi-byte)
mbedtls_asn1_write_integer_positive:"000000":"020100"

ASN.1 write integer: Zero (empty)
mbedtls_asn1_write_integer_positive:"":"020100"
Loading