|
DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
|
RSA-SHA2-256/512 host-key signing and public-key serialization. More...
#include "network_drivers/presentation/ssh/crypto/ssh_bignum.h"#include "network_drivers/presentation/ssh/crypto/ssh_sha256.h"#include "network_drivers/presentation/ssh/crypto/ssh_sha512.h"#include <stddef.h>#include <stdint.h>Go to the source code of this file.
Classes | |
| struct | SshRsaPrivKey |
| RSA-2048 private key parameters. More... | |
| struct | SshRsaPubKey |
| RSA-2048 public key parameters for the host key blob. More... | |
Macros | |
| #define | SSH_RSA_KEY_DER_MAX 1700 |
| Maximum DER size for a PKCS#1 RSAPrivateKey with 2048-bit fields. | |
| #define | SSH_RSA_KEY_BYTES 256 |
| RSA modulus and private exponent size in bytes (RSA-2048). | |
| #define | SSH_RSA_SIG_BYTES 256 |
| PKCS#1 v1.5 signature size for RSA-2048 in bytes. | |
| #define | SSH_RSA_PUBKEY_ALG "ssh-rsa" |
| Key-blob type string for an RSA host key. | |
| #define | SSH_RSA_PUBKEY_ALG_LEN 7 |
| Length of SSH_RSA_PUBKEY_ALG ("ssh-rsa" = 7 bytes). | |
| #define | SSH_RSA_PUBKEY_BLOB_MAX (4 + 7 + 4 + 1 + 4 + 4 + 1 + 256) |
| Maximum byte length of the serialized RSA public key blob. | |
Enumerations | |
| enum class | SshRsaHash : uint8_t { SHA256 = 0 , SHA512 = 1 } |
| Hash algorithm selecting the RSA signature scheme (RFC 8332). More... | |
Functions | |
| int | ssh_rsa_load_pubkey (void) |
| Load the public portion of the RSA host key into ssh_host_pubkey. | |
| int | ssh_rsa_sign (const uint8_t *msg, size_t msg_len, SshRsaHash hash, uint8_t sig[SSH_RSA_SIG_BYTES]) |
Sign msg using the RSA host key (PKCS#1 v1.5, rsa-sha2-256/512). | |
| int | ssh_rsa_encode_pubkey (uint8_t *out, size_t *out_len, size_t out_cap) |
| Serialize the RSA public host key into an SSH "ssh-rsa" key blob. | |
| int | ssh_rsa_verify (const uint8_t n_be[SSH_RSA_KEY_BYTES], const uint8_t e_be4[4], const uint8_t *msg, size_t msg_len, const uint8_t *sig, size_t sig_len, SshRsaHash hash) |
| Verify an RSA PKCS#1 v1.5 signature (rsa-sha2-256/512) with a public key. | |
Variables | |
| const uint8_t | ssh_pkcs1_sha256_digestinfo [SSH_PKCS1_DIGESTINFO_LEN] |
| The DER-encoded DigestInfo wrapper for SHA-256. | |
| const uint8_t | ssh_pkcs1_sha512_digestinfo [SSH_PKCS1_SHA512_DIGESTINFO_LEN] |
| The DER-encoded DigestInfo wrapper for SHA-512. | |
| SshRsaPubKey | ssh_host_pubkey |
| Static host public key (BSS). Set by ssh_rsa_load_pubkey(). | |
RSA-SHA2-256/512 host-key signing and public-key serialization.
═══════════════════════════════════════════════════════════════════════════ SECURITY MODEL - PRIVATE KEY LIFETIME ═══════════════════════════════════════════════════════════════════════════
The RSA-2048 private key (d, p, q, dp, dq, qinv) MUST NEVER live in static or global memory. Reasons:
MANDATED LIFETIME: load (from NVS) → stack → sign → volatile-wipe → return
The struct SshRsaPrivKey is declared here for documentation purposes; it must only ever be declared as a local variable inside ssh_rsa_sign().
═══════════════════════════════════════════════════════════════════════════ PKCS#1 v1.5 SIGNATURE SCHEME ═══════════════════════════════════════════════════════════════════════════
The signature produced by ssh_rsa_sign() follows PKCS#1 v1.5 (RFC 8017 §8.2), which is what SSH uses for "rsa-sha2-256" and "rsa-sha2-512" (RFC 8332) - the only difference is the hash and its DigestInfo OID:
hash.═══════════════════════════════════════════════════════════════════════════ ARDUINO VS NATIVE ═══════════════════════════════════════════════════════════════════════════
Arduino: uses mbedtls_pk_sign() with MBEDTLS_MD_SHA256 or MBEDTLS_MD_SHA512, which performs the full PKCS#1 v1.5 pad-and-sign in hardware-accelerated multiprecision arithmetic via ESP-IDF.
Native: software path - SHA-256/512 via ssh_sha256()/ssh_sha512(), PKCS#1 v1.5 padding built by hand, RSA exponentiation via bn_expmod_group14() (same Montgomery path used for DH). Both paths use the same key layout.
═══════════════════════════════════════════════════════════════════════════ NVS KEY FORMAT ═══════════════════════════════════════════════════════════════════════════
On Arduino the private key is stored in NVS namespace "ssh_host_key" under key "priv_der", as a DER-encoded PKCS#1 RSAPrivateKey (RFC 8017 App. C):
RSAPrivateKey ::= SEQUENCE { version Version (INTEGER: 0), modulus INTEGER, – n publicExponent INTEGER, – e privateExponent INTEGER, – d prime1 INTEGER, – p prime2 INTEGER, – q exponent1 INTEGER, – dp = d mod (p-1) exponent2 INTEGER, – dq = d mod (q-1) coefficient INTEGER, – qinv = q^(-1) mod p }
The DER blob is parsed by mbedtls_rsa_parse_key() on Arduino. On native builds, the test fixture injects n, e, d directly as raw 256-byte arrays.
Definition in file ssh_rsa.h.
| #define SSH_RSA_KEY_DER_MAX 1700 |
| #define SSH_RSA_KEY_BYTES 256 |
| #define SSH_RSA_SIG_BYTES 256 |
| #define SSH_RSA_PUBKEY_ALG "ssh-rsa" |
Key-blob type string for an RSA host key.
Per RFC 8332 §3, the RSA public-key blob always carries the type string "ssh-rsa" - even when the negotiated signature algorithm is "rsa-sha2-256" or "rsa-sha2-512". Only the signature and authentication algorithm-name fields use "rsa-sha2-256"; the key blob format is unchanged from RFC 4253 §6.6. Emitting "rsa-sha2-256" here would make compliant clients (e.g. OpenSSH) fail to parse the host key.
| #define SSH_RSA_PUBKEY_ALG_LEN 7 |
| #define SSH_RSA_PUBKEY_BLOB_MAX (4 + 7 + 4 + 1 + 4 + 4 + 1 + 256) |
|
strong |
| int ssh_rsa_load_pubkey | ( | void | ) |
Load the public portion of the RSA host key into ssh_host_pubkey.
Arduino: reads the DER blob from NVS ("ssh_host_key"/"priv_der"), parses n and e via mbedtls, stores them in ssh_host_pubkey.
Native: reads n and e from the test fixture arrays (see ssh_rsa.cpp).
Call once at startup (or after begin()). Must succeed before any SSH connections are accepted.
Definition at line 82 of file ssh_rsa.cpp.
References SshRsaPubKey::e_bytes, SshRsaPubKey::loaded, SshRsaCtx::lock, SshRsaPubKey::n, SshRsaCtx::pk, SshRsaCtx::ready, ssh_host_pubkey, SSH_RSA_KEY_BYTES, and SSH_RSA_KEY_DER_MAX.
Referenced by ssh_rsa_sign().
| int ssh_rsa_sign | ( | const uint8_t * | msg, |
| size_t | msg_len, | ||
| SshRsaHash | hash, | ||
| uint8_t | sig[SSH_RSA_SIG_BYTES] | ||
| ) |
Sign msg using the RSA host key (PKCS#1 v1.5, rsa-sha2-256/512).
The private key is loaded from NVS directly into a stack-local SshRsaPrivKey struct, used, then zeroed before this function returns. The key NEVER touches static or global memory.
On Arduino: delegates to mbedtls_pk_sign() (hardware-accelerated). On native: software SHA-256/512 + hand-built PKCS#1 pad + bn_expmod_group14().
| [in] | msg | Message to sign (typically the exchange hash H, 32 bytes). |
| [in] | msg_len | Length of msg. |
| [in] | hash | Signature hash: SHA256 (rsa-sha2-256) or SHA512 (rsa-sha2-512). |
| [out] | sig | Output buffer, must be SSH_RSA_SIG_BYTES (256) bytes. |
Definition at line 147 of file ssh_rsa.cpp.
References SshRsaCtx::lock, SshRsaCtx::pk, SshRsaCtx::ready, SHA512, ssh_rsa_load_pubkey(), SSH_RSA_SIG_BYTES, ssh_sha256(), SSH_SHA256_DIGEST_LEN, ssh_sha512(), and SSH_SHA512_DIGEST_LEN.
| int ssh_rsa_encode_pubkey | ( | uint8_t * | out, |
| size_t * | out_len, | ||
| size_t | out_cap | ||
| ) |
Serialize the RSA public host key into an SSH "ssh-rsa" key blob.
Format (RFC 4253 §6.6, RFC 8332 §3): uint32 len("ssh-rsa") = 7 byte[7] "ssh-rsa" mpint e mpint n
Writes into out; sets *out_len to the number of bytes written. out must be at least SSH_RSA_PUBKEY_BLOB_MAX bytes.
| [out] | out | Destination buffer. |
| [out] | out_len | Number of bytes written. |
| [in] | out_cap | Capacity of out. |
Definition at line 576 of file ssh_rsa.cpp.
References SshRsaPubKey::e_bytes, SshRsaPubKey::loaded, SshRsaPubKey::n, ssh_host_pubkey, SSH_RSA_KEY_BYTES, SSH_RSA_PUBKEY_ALG, SSH_RSA_PUBKEY_ALG_LEN, and SSH_RSA_PUBKEY_BLOB_MAX.
| int ssh_rsa_verify | ( | const uint8_t | n_be[SSH_RSA_KEY_BYTES], |
| const uint8_t | e_be4[4], | ||
| const uint8_t * | msg, | ||
| size_t | msg_len, | ||
| const uint8_t * | sig, | ||
| size_t | sig_len, | ||
| SshRsaHash | hash | ||
| ) |
Verify an RSA PKCS#1 v1.5 signature (rsa-sha2-256/512) with a public key.
Used for client publickey authentication (RFC 4252 §7): n_be / e_be4 come from the client-supplied key blob, not the host key. The public exponent is small (typically 65537), so the modular exponentiation s^e mod n is cheap and is performed for real on both platforms (native: schoolbook bignum; Arduino: mbedTLS). The hash is selected by the client's signature algorithm name (rsa-sha2-256 -> SHA256, rsa-sha2-512 -> SHA512), not by the key blob.
| [in] | n_be | RSA modulus n, big-endian, 256 bytes. |
| [in] | e_be4 | RSA public exponent e, big-endian, 4 bytes. |
| [in] | msg | Signed message. |
| [in] | msg_len | Length of msg. |
| [in] | sig | Signature bytes (256 for RSA-2048). |
| [in] | sig_len | Length of sig. |
| [in] | hash | Signature hash: SHA256 (rsa-sha2-256) or SHA512 (rsa-sha2-512). |
Definition at line 181 of file ssh_rsa.cpp.
References SHA512, SSH_RSA_KEY_BYTES, ssh_sha256(), SSH_SHA256_DIGEST_LEN, ssh_sha512(), and SSH_SHA512_DIGEST_LEN.
|
extern |
The DER-encoded DigestInfo wrapper for SHA-256.
Prepend this to the 32-byte SHA-256 digest to form the 51-byte DigestInfo structure for PKCS#1 v1.5.
Definition at line 17 of file ssh_rsa.cpp.
|
extern |
The DER-encoded DigestInfo wrapper for SHA-512.
Prepend this to the 64-byte SHA-512 digest to form the 83-byte DigestInfo structure for PKCS#1 v1.5.
Definition at line 26 of file ssh_rsa.cpp.
|
extern |
Static host public key (BSS). Set by ssh_rsa_load_pubkey().
Definition at line 39 of file ssh_rsa.cpp.
Referenced by ssh_rsa_encode_pubkey(), and ssh_rsa_load_pubkey().