Implementation:Duckdb Duckdb Mbedtls PK
| Knowledge Sources | |
|---|---|
| Domains | Cryptography, Third_Party |
| Last Updated | 2026-02-07 12:00 GMT |
Overview
The mbedTLS PK module provides a public key abstraction layer that offers a unified interface for RSA, Elliptic Curve (ECDSA, ECDH), and opaque (PSA-backed) key operations including signing, verification, encryption, and decryption.
Description
This module abstracts over different public-key algorithms through a common interface. The mbedtls_pk_type_t enumeration defines supported key types:
MBEDTLS_PK_RSA-- RSA keysMBEDTLS_PK_ECKEY-- Generic EC keys (can be used for ECDSA or ECDH)MBEDTLS_PK_ECKEY_DH-- EC keys restricted to ECDHMBEDTLS_PK_ECDSA-- EC keys restricted to ECDSAMBEDTLS_PK_RSA_ALT-- RSA alternative (external implementation)MBEDTLS_PK_RSASSA_PSS-- RSA with PSS paddingMBEDTLS_PK_OPAQUE-- Opaque keys backed by PSA Crypto
The mbedtls_pk_context structure contains a pointer to a mbedtls_pk_info_t (vtable of operations), a pk_ctx (the underlying algorithm-specific context), and optional PSA key storage fields for EC keys.
The module is implemented across four files:
pk.cpp: Core PK API --mbedtls_pk_init(),mbedtls_pk_free(),mbedtls_pk_setup(), and dispatching for sign, verify, encrypt, decrypt operations. The free function uses the vtable'sctx_free_funcfor proper cleanup and callsmbedtls_platform_zeroize()for secure erasure.
pk_wrap.cpp: Concrete wrapper implementations that bridge the PK interface to RSA, ECDSA, and PSA operations. Each wrapper provides algorithm-specific implementations of the PK vtable functions.
pkparse.cpp: Key parsing from DER and PEM formats. Handles PKCS#1, PKCS#8, and SEC1 key formats. Includes support for SpecifiedECDomain parameters and password-protected private keys via PKCS#5 and PKCS#12.
The maximum signature size is computed at compile time via MBEDTLS_PK_SIGNATURE_MAX_SIZE, which accounts for RSA (up to MBEDTLS_MPI_MAX_SIZE bytes), ECDSA (with ASN.1 overhead), and PSA signature sizes.
Usage
DuckDB uses the PK module as the primary interface for:
- Extension signature verification: The PK layer provides the
mbedtls_pk_verify()function used to verify RSA/ECDSA signatures on DuckDB extensions - Key parsing:
mbedtls_pk_parse_public_key()andmbedtls_pk_parse_key()deserialize public and private keys from PEM/DER-encoded certificates and key files - TLS authentication: The PK module dispatches signature and verification operations during TLS handshakes, abstracting over the specific algorithm used by each certificate
Code Reference
Source Location
- Repository: Duckdb_Duckdb
- Files:
- third_party/mbedtls/include/mbedtls/pk.h -- Public key API header (1296 lines)
- third_party/mbedtls/library/pk.cpp -- PK implementation (1503 lines)
- third_party/mbedtls/library/pk_wrap.cpp -- PK wrappers (1585 lines)
- third_party/mbedtls/library/pkparse.cpp -- PK parsing (1392 lines)
Signature
// Context lifecycle
void mbedtls_pk_init(mbedtls_pk_context *ctx);
void mbedtls_pk_free(mbedtls_pk_context *ctx);
// Setup with specific key type
int mbedtls_pk_setup(mbedtls_pk_context *ctx,
const mbedtls_pk_info_t *info);
// Key type information
mbedtls_pk_type_t mbedtls_pk_get_type(const mbedtls_pk_context *ctx);
const char *mbedtls_pk_get_name(const mbedtls_pk_context *ctx);
size_t mbedtls_pk_get_bitlen(const mbedtls_pk_context *ctx);
// Signature verification
int mbedtls_pk_verify(mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg,
const unsigned char *hash, size_t hash_len,
const unsigned char *sig, size_t sig_len);
// Signature creation
int mbedtls_pk_sign(mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg,
const unsigned char *hash, size_t hash_len,
unsigned char *sig, size_t sig_size, size_t *sig_len,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng);
// Key parsing
int mbedtls_pk_parse_public_key(mbedtls_pk_context *ctx,
const unsigned char *key, size_t keylen);
int mbedtls_pk_parse_key(mbedtls_pk_context *ctx,
const unsigned char *key, size_t keylen,
const unsigned char *pwd, size_t pwdlen,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng);
Import
#include "mbedtls/pk.h"
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| ctx | mbedtls_pk_context * |
Yes | Public key context |
| md_alg | mbedtls_md_type_t |
For sign/verify | Hash algorithm used to produce the digest |
| hash | const unsigned char * |
For sign/verify | Pre-computed message digest |
| hash_len | size_t |
For sign/verify | Length of the hash in bytes |
| sig | const unsigned char * |
For verify | Signature buffer to verify |
| sig_len | size_t |
For verify | Length of the signature |
| key | const unsigned char * |
For parse | DER or PEM encoded key data |
| keylen | size_t |
For parse | Length of key data (including null terminator for PEM) |
| f_rng | function pointer | For sign | Random number generator callback |
Outputs
| Name | Type | Description |
|---|---|---|
| return value | int |
0 on success; error codes include MBEDTLS_ERR_PK_BAD_INPUT_DATA (-0x3E80), MBEDTLS_ERR_PK_TYPE_MISMATCH (-0x3F00), MBEDTLS_ERR_PK_KEY_INVALID_FORMAT (-0x3D00), MBEDTLS_ERR_PK_SIG_LEN_MISMATCH (-0x3900)
|
| sig | unsigned char * |
Written signature (for mbedtls_pk_sign)
|
| sig_len | size_t * |
Actual signature length written |
Usage Examples
// Verify an RSA signature using the PK abstraction
mbedtls_pk_context pk;
mbedtls_pk_init(&pk);
// Parse PEM-encoded public key
const unsigned char *pem_key = (const unsigned char *)"-----BEGIN PUBLIC KEY-----\n...";
size_t pem_len = strlen((const char *)pem_key) + 1;
int ret = mbedtls_pk_parse_public_key(&pk, pem_key, pem_len);
if (ret != 0) { /* handle error */ }
// Verify SHA-256 signature
unsigned char hash[32] = { /* SHA-256 digest of the message */ };
unsigned char sig[256] = { /* RSA signature */ };
size_t sig_len = /* actual signature length */;
ret = mbedtls_pk_verify(&pk, MBEDTLS_MD_SHA256,
hash, sizeof(hash), sig, sig_len);
if (ret != 0) { /* signature invalid or error */ }
mbedtls_pk_free(&pk);