Implementation:Duckdb Duckdb Mbedtls ASN1
| Knowledge Sources | |
|---|---|
| Domains | Cryptography, Third_Party |
| Last Updated | 2026-02-07 12:00 GMT |
Overview
The mbedTLS ASN.1 module provides parsing and writing functionality for ASN.1 (Abstract Syntax Notation One) data structures encoded in DER (Distinguished Encoding Rules) format, used extensively for X.509 certificates, PKCS key formats, and cryptographic signatures.
Description
ASN.1 is the standard notation for specifying data structures in cryptographic protocols. This module implements both reading (parsing) and writing of DER-encoded ASN.1 structures.
DER Tag Constants: The module defines all standard ASN.1 tag types used in cryptographic data structures:
- Primitive types:
MBEDTLS_ASN1_BOOLEAN(0x01),MBEDTLS_ASN1_INTEGER(0x02),MBEDTLS_ASN1_BIT_STRING(0x03),MBEDTLS_ASN1_OCTET_STRING(0x04),MBEDTLS_ASN1_NULL(0x05),MBEDTLS_ASN1_OID(0x06) - String types:
MBEDTLS_ASN1_UTF8_STRING(0x0C),MBEDTLS_ASN1_PRINTABLE_STRING(0x13),MBEDTLS_ASN1_IA5_STRING(0x16) - Constructed types:
MBEDTLS_ASN1_SEQUENCE(0x10),MBEDTLS_ASN1_SET(0x11) - Time types:
MBEDTLS_ASN1_UTC_TIME(0x17),MBEDTLS_ASN1_GENERALIZED_TIME(0x18) - Modifiers:
MBEDTLS_ASN1_CONSTRUCTED(0x20),MBEDTLS_ASN1_CONTEXT_SPECIFIC(0x80)
Parsing API (asn1parse.cpp): Functions parse DER data by advancing a pointer through the buffer:
mbedtls_asn1_get_len(): Reads a DER length field (1-5 bytes), supporting both short form (single byte) and long form (up to 4 length bytes)mbedtls_asn1_get_tag(): Reads and validates a tag byte, then retrieves the associated lengthmbedtls_asn1_get_bool(),mbedtls_asn1_get_int(),mbedtls_asn1_get_mpi(): Type-specific parsers
Writing API (asn1write.cpp): Functions write DER data backwards from the end of a buffer:
mbedtls_asn1_write_len(): Writes a DER length fieldmbedtls_asn1_write_tag(): Writes a tag bytembedtls_asn1_write_raw_buffer(): Writes raw data
The writing API uses the MBEDTLS_ASN1_CHK_ADD macro for error-checked accumulation of written byte counts, and MBEDTLS_ASN1_CHK_CLEANUP_ADD for the same with goto-based cleanup.
Usage
DuckDB uses the ASN.1 module for:
- X.509 certificate parsing: Parsing DER-encoded certificate structures including subject, issuer, validity, extensions, and signature fields
- Key format parsing: Reading PKCS#1, PKCS#8, and SEC1 encoded public and private keys
- Signature encoding: Writing DER-encoded ECDSA signatures (SEQUENCE of two INTEGERs)
- OID matching: Parsing Object Identifiers to determine algorithm types in certificates and keys
Code Reference
Source Location
- Repository: Duckdb_Duckdb
- Files:
- third_party/mbedtls/include/mbedtls/asn1.h -- ASN.1 parsing API header (642 lines)
- third_party/mbedtls/include/mbedtls/asn1write.h -- ASN.1 writing API header (390 lines)
- third_party/mbedtls/library/asn1parse.cpp -- ASN.1 parsing implementation (468 lines)
- third_party/mbedtls/library/asn1write.cpp -- ASN.1 writing implementation (440 lines)
Signature
// Parsing functions (advance pointer through buffer)
int mbedtls_asn1_get_len(unsigned char **p,
const unsigned char *end,
size_t *len);
int mbedtls_asn1_get_tag(unsigned char **p,
const unsigned char *end,
size_t *len, int tag);
int mbedtls_asn1_get_bool(unsigned char **p,
const unsigned char *end,
int *val);
int mbedtls_asn1_get_int(unsigned char **p,
const unsigned char *end,
int *val);
int mbedtls_asn1_get_mpi(unsigned char **p,
const unsigned char *end,
mbedtls_mpi *X);
// Writing functions (write backwards from end of buffer)
int mbedtls_asn1_write_len(unsigned char **p,
const unsigned char *start,
size_t len);
int mbedtls_asn1_write_tag(unsigned char **p,
const unsigned char *start,
unsigned char tag);
int mbedtls_asn1_write_raw_buffer(unsigned char **p,
const unsigned char *start,
const unsigned char *buf,
size_t size);
Import
#include "mbedtls/asn1.h"
#include "mbedtls/asn1write.h"
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| p | unsigned char ** |
Yes | Pointer to current position in the DER buffer (advanced on success) |
| end | const unsigned char * |
For parsing | Pointer past the end of the input buffer (bounds checking) |
| start | const unsigned char * |
For writing | Pointer to the start of the output buffer (bounds checking) |
| tag | int / unsigned char |
Yes | Expected or desired ASN.1 tag value |
| buf | const unsigned char * |
For write_raw | Raw data buffer to write |
| size | size_t |
For write_raw | Length of the raw data buffer |
Outputs
| Name | Type | Description |
|---|---|---|
| return value (parse) | int |
0 on success; error codes include MBEDTLS_ERR_ASN1_OUT_OF_DATA (-0x0060), MBEDTLS_ERR_ASN1_UNEXPECTED_TAG (-0x0062), MBEDTLS_ERR_ASN1_INVALID_LENGTH (-0x0064)
|
| return value (write) | int |
Number of bytes written on success; MBEDTLS_ERR_ASN1_BUF_TOO_SMALL (-0x006C) on failure
|
| len | size_t * |
Parsed content length (parsing functions) |
| val | int * |
Parsed boolean or integer value |
| X | mbedtls_mpi * |
Parsed multi-precision integer |
Usage Examples
// Parse a DER-encoded ASN.1 INTEGER
unsigned char der_data[] = { 0x02, 0x01, 0x05 }; // INTEGER tag, length 1, value 5
unsigned char *p = der_data;
const unsigned char *end = der_data + sizeof(der_data);
size_t len;
int ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER);
if (ret == 0) {
// p now points to the value bytes, len == 1
int value = *p; // value == 5
}
// Write a DER-encoded ASN.1 tag+length (backwards)
unsigned char buf[10];
unsigned char *wp = buf + sizeof(buf);
const unsigned char *start = buf;
int written = 0;
written += mbedtls_asn1_write_len(&wp, start, 5);
written += mbedtls_asn1_write_tag(&wp, start, MBEDTLS_ASN1_INTEGER);
// wp now points to the beginning of the written TLV header