mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-22 11:36:21 +00:00
Add RSA & chain support
This commit is contained in:
1 parent
ab83acf2d1
commit
d5e5b3397d
5 files changed
+1687
-175
No files matched your search
+819
-69
File diff suppressed because it is too large.
Load diff
+42
-36
@@ -2739,7 +2739,13 @@ PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt(
|
||||
|
||||
|
||||
int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp, size_t expsz, const uint8_t *msg, size_t msgsz, uint8_t *out, size_t outsz);
|
||||
|
||||
int mg_rsa_crt_sign(const uint8_t *em, size_t em_len,
|
||||
const uint8_t *dP, size_t dP_len,
|
||||
const uint8_t *dQ, size_t dQ_len,
|
||||
const uint8_t *p, size_t p_len,
|
||||
const uint8_t *q, size_t q_len,
|
||||
const uint8_t *qInv, size_t qInv_len,
|
||||
uint8_t *signature, size_t sig_len);
|
||||
#endif // TLS_RSA_H
|
||||
|
||||
|
||||
@@ -3944,41 +3950,6 @@ struct mg_tcpip_driver_tms570_data {
|
||||
|
||||
|
||||
|
||||
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC7) && MG_ENABLE_DRIVER_XMC7
|
||||
|
||||
struct mg_tcpip_driver_xmc7_data {
|
||||
int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5
|
||||
uint8_t phy_addr;
|
||||
};
|
||||
|
||||
#ifndef MG_TCPIP_PHY_ADDR
|
||||
#define MG_TCPIP_PHY_ADDR 0
|
||||
#endif
|
||||
|
||||
#ifndef MG_DRIVER_MDC_CR
|
||||
#define MG_DRIVER_MDC_CR 3
|
||||
#endif
|
||||
|
||||
#define MG_TCPIP_DRIVER_INIT(mgr) \
|
||||
do { \
|
||||
static struct mg_tcpip_driver_xmc7_data driver_data_; \
|
||||
static struct mg_tcpip_if mif_; \
|
||||
driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \
|
||||
driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \
|
||||
mif_.ip = MG_TCPIP_IP; \
|
||||
mif_.mask = MG_TCPIP_MASK; \
|
||||
mif_.gw = MG_TCPIP_GW; \
|
||||
mif_.driver = &mg_tcpip_driver_xmc7; \
|
||||
mif_.driver_data = &driver_data_; \
|
||||
MG_SET_MAC_ADDRESS(mif_.mac); \
|
||||
mg_tcpip_init(mgr, &mif_); \
|
||||
MG_INFO(("Driver: xmc7, MAC: %M", mg_print_mac, mif_.mac)); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC) && MG_ENABLE_DRIVER_XMC
|
||||
|
||||
struct mg_tcpip_driver_xmc_data {
|
||||
@@ -4025,6 +3996,41 @@ struct mg_tcpip_driver_xmc_data {
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC7) && MG_ENABLE_DRIVER_XMC7
|
||||
|
||||
struct mg_tcpip_driver_xmc7_data {
|
||||
int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5
|
||||
uint8_t phy_addr;
|
||||
};
|
||||
|
||||
#ifndef MG_TCPIP_PHY_ADDR
|
||||
#define MG_TCPIP_PHY_ADDR 0
|
||||
#endif
|
||||
|
||||
#ifndef MG_DRIVER_MDC_CR
|
||||
#define MG_DRIVER_MDC_CR 3
|
||||
#endif
|
||||
|
||||
#define MG_TCPIP_DRIVER_INIT(mgr) \
|
||||
do { \
|
||||
static struct mg_tcpip_driver_xmc7_data driver_data_; \
|
||||
static struct mg_tcpip_if mif_; \
|
||||
driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \
|
||||
driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \
|
||||
mif_.ip = MG_TCPIP_IP; \
|
||||
mif_.mask = MG_TCPIP_MASK; \
|
||||
mif_.gw = MG_TCPIP_GW; \
|
||||
mif_.driver = &mg_tcpip_driver_xmc7; \
|
||||
mif_.driver_data = &driver_data_; \
|
||||
MG_SET_MAC_ADDRESS(mif_.mac); \
|
||||
mg_tcpip_init(mgr, &mif_); \
|
||||
MG_INFO(("Driver: xmc7, MAC: %M", mg_print_mac, mif_.mac)); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
+774
-67
@@ -12,6 +12,19 @@
|
||||
|
||||
#if MG_TLS == MG_TLS_BUILTIN
|
||||
|
||||
// PKCS#8 algorithm OIDs
|
||||
static const uint8_t mg_rsa_oid[] = {
|
||||
0x2a, 0x86, 0x48, 0x86, 0xf7,
|
||||
0x0d, 0x01, 0x01, 0x01 // 1.2.840.113549.1.1.1 rsaEncryption
|
||||
};
|
||||
static const uint8_t mg_ec_public_key_oid[] = {
|
||||
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01 // 1.2.840.10045.2.1 ecPublicKey
|
||||
};
|
||||
static const uint8_t mg_secp256r1_oid[] = {
|
||||
0x2a, 0x86, 0x48, 0xce,
|
||||
0x3d, 0x03, 0x01, 0x07 // 1.2.840.10045.3.1.7 secp256r1
|
||||
};
|
||||
|
||||
/* TLS 1.3 Record Content Type (RFC8446 B.1) */
|
||||
#define MG_TLS_CHANGE_CIPHER 20
|
||||
#define MG_TLS_ALERT 21
|
||||
@@ -28,6 +41,8 @@
|
||||
#define MG_TLS_CERTIFICATE_VERIFY 15
|
||||
#define MG_TLS_FINISHED 20
|
||||
|
||||
#define MG_TLS_RSA_USE_CRT 1 // CRT instead of naive RSA
|
||||
|
||||
// handshake is re-entrant, so we need to keep track of its state state names
|
||||
// refer to RFC8446#A.1
|
||||
enum mg_tls_hs_state {
|
||||
@@ -62,6 +77,17 @@ struct tls_enc {
|
||||
uint8_t client_finished_key[32];
|
||||
};
|
||||
|
||||
struct mg_rsa_key {
|
||||
struct mg_str n; // modulus
|
||||
struct mg_str e; // public exponent
|
||||
struct mg_str d; // private exponent
|
||||
struct mg_str p; // prime1
|
||||
struct mg_str q; // prime2
|
||||
struct mg_str dP; // exponent1 (d mod (p-1))
|
||||
struct mg_str dQ; // exponent2 (d mod (q-1))
|
||||
struct mg_str qInv; // coefficient ((inverse of q) mod p)
|
||||
};
|
||||
|
||||
// per-connection TLS data
|
||||
struct tls_data {
|
||||
enum mg_tls_hs_state state; // keep track of connection handshake progress
|
||||
@@ -79,13 +105,17 @@ struct tls_data {
|
||||
uint8_t x25519_cli[32]; // client X25519 key between the handshake states
|
||||
uint8_t x25519_sec[32]; // x25519 secret between the handshake states
|
||||
|
||||
bool skip_verification; // do not perform checks on server certificate
|
||||
bool cert_requested; // client received a CertificateRequest
|
||||
bool is_twoway; // server is configured to authenticate clients
|
||||
struct mg_str cert_der; // certificate in DER format
|
||||
struct mg_str ca_der; // CA certificate
|
||||
uint8_t ec_key[32]; // EC private key
|
||||
char hostname[254]; // matching hostname
|
||||
bool skip_verification; // do not perform checks on server certificate
|
||||
bool cert_requested; // client received a CertificateRequest
|
||||
bool is_twoway; // server is configured to authenticate clients
|
||||
struct mg_str cert_der; // certificate in DER format
|
||||
struct mg_str ca_der; // CA certificate
|
||||
struct mg_str *chain_der; // certificate chain (intermediate certs)
|
||||
size_t chain_len; // number of certificates in chain
|
||||
uint8_t ec_key[32]; // EC private key
|
||||
struct mg_rsa_key rsa;
|
||||
struct mg_str rsa_key_der; // RSA private key in DER format
|
||||
char hostname[254]; // matching hostname
|
||||
|
||||
bool is_ec_pubkey; // EC or RSA
|
||||
uint8_t pubkey[512 + 16]; // server EC (64) or RSA (512+exp) public key to
|
||||
@@ -490,7 +520,20 @@ static int mg_tls_recv_record(struct mg_connection *c) {
|
||||
} else if (rio->buf[0] == MG_TLS_CHANGE_CIPHER) { // skip CCS
|
||||
mg_tls_drop_record(c);
|
||||
} else if (rio->buf[0] == MG_TLS_ALERT) { // Skip Alerts
|
||||
MG_INFO(("TLS ALERT packet received"));
|
||||
if (rio->len >= 7) {
|
||||
uint8_t level = rio->buf[5], desc = rio->buf[6];
|
||||
MG_INFO(("TLS ALERT received: level=%d, desc=%d (%s)", level, desc,
|
||||
desc == 0 ? "close_notify"
|
||||
: desc == 10 ? "unexpected_message"
|
||||
: desc == 20 ? "bad_record_mac"
|
||||
: desc == 21 ? "decryption_failed"
|
||||
: desc == 40 ? "handshake_failure"
|
||||
: desc == 42 ? "bad_certificate"
|
||||
: desc == 43 ? "unsupported_certificate"
|
||||
: "unknown"));
|
||||
} else {
|
||||
MG_INFO(("TLS ALERT packet received (short)"));
|
||||
}
|
||||
mg_tls_drop_record(c);
|
||||
} else {
|
||||
mg_error(c, "unexpected packet");
|
||||
@@ -700,8 +743,7 @@ static bool mg_tls_server_send_ext(struct mg_connection *c) {
|
||||
// signature algorithms we actually support:
|
||||
// rsa_pkcs1_sha256, rsa_pss_rsae_sha256 and ecdsa_secp256r1_sha256
|
||||
static const uint8_t secp256r1_sig_algs[12] = {
|
||||
0x00, 0x0d, 0x00, 0x08, 0x00, 0x06, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01
|
||||
};
|
||||
0x00, 0x0d, 0x00, 0x08, 0x00, 0x06, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01};
|
||||
|
||||
static bool mg_tls_server_send_cert_request(struct mg_connection *c) {
|
||||
struct tls_data *tls = (struct tls_data *) c->tls;
|
||||
@@ -724,28 +766,47 @@ static bool mg_tls_send_cert(struct mg_connection *c, bool is_client) {
|
||||
struct tls_data *tls = (struct tls_data *) c->tls;
|
||||
int send_ca = !is_client && tls->ca_der.len > 0;
|
||||
// DER certificate + CA (server optional)
|
||||
size_t n = tls->cert_der.len + (send_ca ? tls->ca_der.len + 5 : 0);
|
||||
uint8_t *cert = (uint8_t *) mg_calloc(1, 13 + n);
|
||||
size_t total_size = tls->cert_der.len + 5;
|
||||
for (size_t i = 1; i < tls->chain_len; i++) {
|
||||
total_size += tls->chain_der[i].len + 5;
|
||||
}
|
||||
if (send_ca) {
|
||||
total_size += tls->ca_der.len + 5;
|
||||
}
|
||||
uint8_t *cert = (uint8_t *) mg_calloc(1, 13 + total_size);
|
||||
bool res;
|
||||
if (cert == NULL) return false;
|
||||
cert[0] = MG_TLS_CERTIFICATE; // handshake header
|
||||
MG_STORE_BE24(cert + 1, n + 9);
|
||||
cert[4] = 0; // request context
|
||||
MG_STORE_BE24(cert + 5, n + 5); // 3 bytes: cert (s) length
|
||||
MG_STORE_BE24(cert + 8, tls->cert_der.len); // 3 bytes: first cert len
|
||||
MG_STORE_BE24(cert + 1, total_size + 4);
|
||||
cert[4] = 0; // request context
|
||||
MG_STORE_BE24(cert + 5, total_size); // 3 bytes: cert (s) length
|
||||
size_t offset = 8;
|
||||
MG_STORE_BE24(cert + offset, tls->cert_der.len); // 3 bytes: first cert len
|
||||
offset += 3;
|
||||
// bytes 11+ are certificate in DER format
|
||||
memmove(cert + 11, tls->cert_der.buf, tls->cert_der.len);
|
||||
MG_STORE_BE16(cert + 11 + tls->cert_der.len,
|
||||
0); // certificate extensions (none)
|
||||
if (send_ca) {
|
||||
size_t offset = 13 + tls->cert_der.len;
|
||||
MG_STORE_BE24(cert + offset, tls->ca_der.len); // 3 bytes: CA cert length
|
||||
memmove(cert + offset + 3, tls->ca_der.buf,
|
||||
tls->ca_der.len); // CA cert data
|
||||
MG_STORE_BE16(cert + 11 + n, 0); // certificate extensions (none)
|
||||
memmove(cert + offset, tls->cert_der.buf, tls->cert_der.len);
|
||||
offset += tls->cert_der.len;
|
||||
MG_STORE_BE16(cert + offset, 0); // certificate extensions (none)
|
||||
offset += 2;
|
||||
for (size_t i = 1; i < tls->chain_len; i++) {
|
||||
MG_STORE_BE24(cert + offset, tls->chain_der[i].len);
|
||||
offset += 3;
|
||||
memmove(cert + offset, tls->chain_der[i].buf, tls->chain_der[i].len);
|
||||
offset += tls->chain_der[i].len;
|
||||
MG_STORE_BE16(cert + offset, 0); // certificate extensions (none)
|
||||
offset += 2;
|
||||
}
|
||||
mg_sha256_update(&tls->sha256, cert, 13 + n);
|
||||
res = mg_tls_encrypt(c, cert, 13 + n, MG_TLS_HANDSHAKE);
|
||||
if (send_ca) {
|
||||
MG_STORE_BE24(cert + offset, tls->ca_der.len); // 3 bytes: CA cert length
|
||||
offset += 3;
|
||||
memmove(cert + offset, tls->ca_der.buf,
|
||||
tls->ca_der.len); // CA cert data
|
||||
offset += tls->ca_der.len;
|
||||
MG_STORE_BE16(cert + offset, 0); // certificate extensions (none)
|
||||
offset += 2;
|
||||
}
|
||||
mg_sha256_update(&tls->sha256, cert, offset);
|
||||
res = mg_tls_encrypt(c, cert, offset, MG_TLS_HANDSHAKE);
|
||||
mg_free(cert);
|
||||
return res;
|
||||
}
|
||||
@@ -772,41 +833,253 @@ static void finish_SHA256(const MG_UECC_HashContext *base,
|
||||
mg_sha256_final(hash_result, &c->ctx);
|
||||
}
|
||||
|
||||
static void mg_tls_mgf1(uint8_t *mask, size_t mask_len, const uint8_t *seed,
|
||||
size_t seed_len) {
|
||||
uint32_t counter = 0;
|
||||
size_t generated = 0;
|
||||
while (generated < mask_len) {
|
||||
mg_sha256_ctx ctx;
|
||||
uint8_t digest[32];
|
||||
uint8_t ctr[4];
|
||||
ctr[0] = (uint8_t) (counter >> 24);
|
||||
ctr[1] = (uint8_t) (counter >> 16);
|
||||
ctr[2] = (uint8_t) (counter >> 8);
|
||||
ctr[3] = (uint8_t) counter;
|
||||
mg_sha256_init(&ctx);
|
||||
mg_sha256_update(&ctx, seed, seed_len);
|
||||
mg_sha256_update(&ctx, ctr, sizeof(ctr));
|
||||
mg_sha256_final(digest, &ctx);
|
||||
size_t chunk_len = mask_len - generated;
|
||||
size_t chunk = (chunk_len < sizeof(digest) ? chunk_len : sizeof(digest));
|
||||
memmove(mask + generated, digest, chunk);
|
||||
generated += chunk;
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned mg_tls_rsa_bits(const struct mg_str *n) {
|
||||
size_t i = 0;
|
||||
unsigned bits = 0;
|
||||
while (i < n->len && n->buf[i] == 0) i++;
|
||||
if (i == n->len) return 0;
|
||||
bits = (unsigned) ((n->len - i) * 8);
|
||||
{
|
||||
uint8_t byte = (uint8_t) n->buf[i];
|
||||
while ((byte & 0x80U) == 0) {
|
||||
bits--;
|
||||
byte <<= 1;
|
||||
}
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
static bool mg_tls_pss_encode(const uint8_t *hash, size_t hashlen,
|
||||
const struct mg_str *n, uint8_t *em) {
|
||||
size_t emlen = n->len;
|
||||
size_t saltlen = hashlen;
|
||||
size_t dblen;
|
||||
size_t pslen;
|
||||
uint8_t salt[64]; // Max salt size for any reasonable hash
|
||||
uint8_t m[136]; // 8 + max hash (64) + max salt (64) = 136
|
||||
uint8_t H[64]; // Max hash size
|
||||
uint8_t DB[512]; // Max for 4096-bit RSA
|
||||
uint8_t mask[512]; // Max for 4096-bit RSA
|
||||
mg_sha256_ctx ctx;
|
||||
|
||||
// Check bounds
|
||||
if (saltlen > sizeof(salt) || (8 + hashlen + saltlen) > sizeof(m) ||
|
||||
hashlen > sizeof(H) || emlen > sizeof(DB)) {
|
||||
MG_ERROR(("RSA key too large for static buffers"));
|
||||
return false;
|
||||
}
|
||||
if (emlen < hashlen + saltlen + 2) {
|
||||
return false;
|
||||
}
|
||||
if (!mg_random(salt, saltlen)) {
|
||||
return false;
|
||||
}
|
||||
MG_VERBOSE(("PSS salt: %M", mg_print_hex, saltlen, salt));
|
||||
|
||||
// Build m = 8 zero bytes || hash || salt
|
||||
memset(m, 0, 8);
|
||||
memcpy(m + 8, hash, hashlen);
|
||||
memcpy(m + 8 + hashlen, salt, saltlen);
|
||||
mg_sha256_init(&ctx);
|
||||
mg_sha256_update(&ctx, m, 8 + hashlen + saltlen);
|
||||
mg_sha256_final(H, &ctx);
|
||||
MG_VERBOSE(("PSS H: %M", mg_print_hex, hashlen, H));
|
||||
|
||||
dblen = emlen - hashlen - 1;
|
||||
pslen = emlen - hashlen - saltlen - 2;
|
||||
|
||||
// Build DB = PS || 0x01 || salt
|
||||
memset(DB, 0, pslen);
|
||||
DB[pslen] = 0x01;
|
||||
memcpy(DB + pslen + 1, salt, saltlen);
|
||||
|
||||
// Generate mask and apply to DB
|
||||
mg_tls_mgf1(mask, dblen, H, hashlen);
|
||||
for (size_t i = 0; i < dblen; i++) DB[i] ^= mask[i];
|
||||
|
||||
{
|
||||
// PSS standard: emBits = modulus_bit_length - 1
|
||||
unsigned rsa_bits = mg_tls_rsa_bits(n);
|
||||
unsigned embits = rsa_bits - 1;
|
||||
unsigned unused = (unsigned) (8 * emlen - embits);
|
||||
MG_VERBOSE(("RSA modulus bits: %u, emBits: %u, emlen: %zu, unused: %u",
|
||||
rsa_bits, embits, emlen, unused));
|
||||
if (unused > 0 && unused < 8) {
|
||||
uint8_t mask_byte = (uint8_t) (0xff >> unused);
|
||||
MG_VERBOSE(("Applying mask 0x%02x to first byte (was 0x%02x)", mask_byte,
|
||||
DB[0]));
|
||||
DB[0] &= mask_byte;
|
||||
MG_VERBOSE(("First byte after mask: 0x%02x", DB[0]));
|
||||
}
|
||||
}
|
||||
|
||||
// Build final em = maskedDB || H || 0xbc
|
||||
memcpy(em, DB, dblen);
|
||||
memcpy(em + dblen, H, hashlen);
|
||||
em[emlen - 1] = 0xbc;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool mg_tls_rsa_sign(struct tls_data *tls, const uint8_t *em,
|
||||
size_t emlen, uint8_t *sig) {
|
||||
#if MG_TLS_RSA_USE_CRT
|
||||
// RSA CRT (Chinese Remainder Theorem) optimization:
|
||||
// s1 = em^dP mod p
|
||||
// s2 = em^dQ mod q
|
||||
// h = qInv * (s1 - s2) mod p
|
||||
// s = s2 + h * q
|
||||
|
||||
if (tls->rsa.p.len == 0 || tls->rsa.q.len == 0 || tls->rsa.dP.len == 0 ||
|
||||
tls->rsa.dQ.len == 0 || tls->rsa.qInv.len == 0) {
|
||||
MG_ERROR(("CRT parameters missing, cannot use CRT optimization"));
|
||||
return false;
|
||||
}
|
||||
|
||||
MG_VERBOSE(("Using RSA-CRT optimization"));
|
||||
|
||||
size_t nlen = tls->rsa.n.len;
|
||||
|
||||
int crt_result = mg_rsa_crt_sign(
|
||||
em, emlen, (const uint8_t *) tls->rsa.dP.buf, tls->rsa.dP.len,
|
||||
(const uint8_t *) tls->rsa.dQ.buf, tls->rsa.dQ.len,
|
||||
(const uint8_t *) tls->rsa.p.buf, tls->rsa.p.len,
|
||||
(const uint8_t *) tls->rsa.q.buf, tls->rsa.q.len,
|
||||
(const uint8_t *) tls->rsa.qInv.buf, tls->rsa.qInv.len, sig, nlen);
|
||||
|
||||
if (crt_result == 0) {
|
||||
MG_VERBOSE(("CRT signature successful (first 4 bytes): %02x %02x %02x %02x",
|
||||
sig[0], sig[1], sig[2], sig[3]));
|
||||
MG_VERBOSE(("CRT signature successful (last 4 bytes): %02x %02x %02x %02x",
|
||||
sig[nlen - 4], sig[nlen - 3], sig[nlen - 2], sig[nlen - 1]));
|
||||
return true;
|
||||
} else {
|
||||
MG_ERROR(("CRT signing failed"));
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
// Standard RSA: s = em^d mod n
|
||||
memset(sig, 0, tls->rsa.n.len);
|
||||
int ret = mg_rsa_mod_pow((const uint8_t *) tls->rsa.n.buf, tls->rsa.n.len,
|
||||
(const uint8_t *) tls->rsa.d.buf, tls->rsa.d.len, em,
|
||||
emlen, sig, tls->rsa.n.len);
|
||||
if (ret == 0) {
|
||||
MG_VERBOSE(("RSA signature first 4 bytes: %02x %02x %02x %02x", sig[0],
|
||||
sig[1], sig[2], sig[3]));
|
||||
MG_VERBOSE(("RSA signature last 4 bytes: %02x %02x %02x %02x",
|
||||
sig[tls->rsa.n.len - 4], sig[tls->rsa.n.len - 3],
|
||||
sig[tls->rsa.n.len - 2], sig[tls->rsa.n.len - 1]));
|
||||
}
|
||||
return ret == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool mg_tls_send_cert_verify(struct mg_connection *c, bool is_client) {
|
||||
struct tls_data *tls = (struct tls_data *) c->tls;
|
||||
// server certificate verify packet
|
||||
uint8_t verify[82] = {0x0f, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00};
|
||||
size_t sigsz, verifysz = 0;
|
||||
uint8_t hash[32] = {0}, tmp[2 * 32 + 64] = {0};
|
||||
struct SHA256_HashContext ctx = {
|
||||
{&init_SHA256, &update_SHA256, &finish_SHA256, 64, 32, tmp},
|
||||
{{0}, 0, 0, {0}}};
|
||||
int neg1, neg2;
|
||||
uint8_t sig[64] = {0};
|
||||
uint8_t hash[32] = {0};
|
||||
|
||||
mg_tls_calc_cert_verify_hash(c, (uint8_t *) hash, is_client);
|
||||
|
||||
mg_uecc_sign_deterministic(tls->ec_key, hash, sizeof(hash), &ctx.uECC, sig,
|
||||
mg_uecc_secp256r1());
|
||||
if (tls->rsa.n.len > 0 && tls->rsa.d.len > 0) {
|
||||
// RSA certificate verify packet
|
||||
size_t emlen = tls->rsa.n.len;
|
||||
size_t verifysz = 8U + emlen;
|
||||
uint8_t em[512]; // Max for 4096-bit RSA
|
||||
uint8_t verify[520]; // 8 + 512 max
|
||||
|
||||
neg1 = !!(sig[0] & 0x80);
|
||||
neg2 = !!(sig[32] & 0x80);
|
||||
verify[8] = 0x30; // ASN.1 SEQUENCE
|
||||
verify[9] = (uint8_t) (68 + neg1 + neg2);
|
||||
verify[10] = 0x02; // ASN.1 INTEGER
|
||||
verify[11] = (uint8_t) (32 + neg1);
|
||||
memmove(verify + 12 + neg1, sig, 32);
|
||||
verify[12 + 32 + neg1] = 0x02; // ASN.1 INTEGER
|
||||
verify[13 + 32 + neg1] = (uint8_t) (32 + neg2);
|
||||
memmove(verify + 14 + 32 + neg1 + neg2, sig + 32, 32);
|
||||
// Check bounds
|
||||
if (emlen > sizeof(em) || verifysz > sizeof(verify)) {
|
||||
MG_ERROR(("RSA key too large for static buffers"));
|
||||
return false;
|
||||
}
|
||||
|
||||
sigsz = (size_t) (70 + neg1 + neg2);
|
||||
verifysz = 8U + sigsz;
|
||||
verify[3] = (uint8_t) (sigsz + 4);
|
||||
verify[7] = (uint8_t) sigsz;
|
||||
if (!mg_tls_pss_encode(hash, sizeof(hash), &tls->rsa.n, em)) {
|
||||
MG_ERROR(("Failed PSS encode"));
|
||||
return false;
|
||||
}
|
||||
|
||||
mg_sha256_update(&tls->sha256, verify, verifysz);
|
||||
return mg_tls_encrypt(c, verify, verifysz, MG_TLS_HANDSHAKE);
|
||||
// Validate PSS encoded message format
|
||||
if (em[emlen - 1] != 0xbc) {
|
||||
MG_ERROR(("Invalid PSS encoding: last byte is 0x%02x, expected 0xbc",
|
||||
em[emlen - 1]));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build verify packet header, then sign directly into the packet
|
||||
verify[0] = 0x0f;
|
||||
MG_STORE_BE24(verify + 1, (uint32_t) (emlen + 4));
|
||||
MG_STORE_BE16(verify + 4, 0x0804);
|
||||
MG_STORE_BE16(verify + 6, (uint16_t) emlen);
|
||||
|
||||
// Sign directly into the verify buffer (verify + 8 = signature location)
|
||||
memset(verify + 8, 0, emlen); // Initialize signature area
|
||||
if (!mg_tls_rsa_sign(tls, em, emlen, verify + 8)) {
|
||||
MG_ERROR(("Failed RSA sign"));
|
||||
return false;
|
||||
}
|
||||
|
||||
MG_VERBOSE(
|
||||
("PSS EM first 4: %02x %02x %02x %02x", em[0], em[1], em[2], em[3]));
|
||||
MG_VERBOSE(("PSS EM last 4: %02x %02x %02x %02x", em[emlen - 4],
|
||||
em[emlen - 3], em[emlen - 2], em[emlen - 1]));
|
||||
|
||||
mg_sha256_update(&tls->sha256, verify, verifysz);
|
||||
return mg_tls_encrypt(c, verify, verifysz, MG_TLS_HANDSHAKE);
|
||||
} else {
|
||||
// EC certificate verify packet
|
||||
uint8_t verify[82] = {0x0f, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00};
|
||||
uint8_t tmp[2 * 32 + 64] = {0};
|
||||
struct SHA256_HashContext ctx = {
|
||||
{&init_SHA256, &update_SHA256, &finish_SHA256, 64, 32, tmp},
|
||||
{{0}, 0, 0, {0}}};
|
||||
size_t sigsz, verifysz = 0;
|
||||
int neg1, neg2;
|
||||
uint8_t sig[64] = {0};
|
||||
mg_uecc_sign_deterministic(tls->ec_key, hash, sizeof(hash), &ctx.uECC, sig,
|
||||
mg_uecc_secp256r1());
|
||||
|
||||
neg1 = !!(sig[0] & 0x80);
|
||||
neg2 = !!(sig[32] & 0x80);
|
||||
verify[8] = 0x30; // ASN.1 SEQUENCE
|
||||
verify[9] = (uint8_t) (68 + neg1 + neg2);
|
||||
verify[10] = 0x02; // ASN.1 INTEGER
|
||||
verify[11] = (uint8_t) (32 + neg1);
|
||||
memmove(verify + 12 + neg1, sig, 32);
|
||||
verify[12 + 32 + neg1] = 0x02; // ASN.1 INTEGER
|
||||
verify[13 + 32 + neg1] = (uint8_t) (32 + neg2);
|
||||
memmove(verify + 14 + 32 + neg1 + neg2, sig + 32, 32);
|
||||
|
||||
sigsz = (size_t) (70 + neg1 + neg2);
|
||||
verifysz = 8U + sigsz;
|
||||
verify[3] = (uint8_t) (sigsz + 4);
|
||||
verify[7] = (uint8_t) sigsz;
|
||||
|
||||
mg_sha256_update(&tls->sha256, verify, verifysz);
|
||||
return mg_tls_encrypt(c, verify, verifysz, MG_TLS_HANDSHAKE);
|
||||
}
|
||||
}
|
||||
|
||||
static bool mg_tls_server_send_finish(struct mg_connection *c) {
|
||||
@@ -1213,16 +1486,17 @@ static int mg_tls_verify_cert_san(const uint8_t *der, size_t dersz,
|
||||
return -1;
|
||||
}
|
||||
while (mg_der_next(&field, &name) > 0) {
|
||||
if (name.type == 0x87 && name.len == 4) { // this is an IPv4 address
|
||||
if (name.type == 0x87 && name.len == 4) { // this is an IPv4 address
|
||||
MG_DEBUG(("Found SAN, IP: %M", mg_print_ip4, name.value));
|
||||
if (!server_ip->is_ip6 && *((uint32_t *) name.value) == server_ip->addr.ip4)
|
||||
if (!server_ip->is_ip6 &&
|
||||
*((uint32_t *) name.value) == server_ip->addr.ip4)
|
||||
return 1; // and matches the one we're connected to
|
||||
} else { // this is a text SAN
|
||||
} else { // this is a text SAN
|
||||
MG_DEBUG(("Found SAN, (%u): %.*s", name.type, name.len, name.value));
|
||||
if (mg_match(mg_str(server_name), mg_str_n((char *) name.value, name.len),
|
||||
NULL))
|
||||
return 1; // and matches the host name
|
||||
} // TODO(): add IPv6 comparison, more items ?
|
||||
} // TODO(): add IPv6 comparison, more items ?
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -1593,7 +1867,9 @@ static bool mg_tls_server_handshake(struct mg_connection *c) {
|
||||
mg_tls_generate_handshake_keys(c);
|
||||
if (!mg_tls_server_send_ext(c)) return false;
|
||||
if (tls->is_twoway && !mg_tls_server_send_cert_request(c)) return false;
|
||||
if (!mg_tls_send_cert(c, false) || !mg_tls_send_cert_verify(c, false) || !mg_tls_server_send_finish(c)) return false;
|
||||
if (!mg_tls_send_cert(c, false) || !mg_tls_send_cert_verify(c, false) ||
|
||||
!mg_tls_server_send_finish(c))
|
||||
return false;
|
||||
if (tls->is_twoway) {
|
||||
// generate application keys at this point, keep using handshake keys
|
||||
struct tls_enc hs_keys = tls->enc;
|
||||
@@ -1634,7 +1910,7 @@ void mg_tls_handshake(struct mg_connection *c) {
|
||||
struct tls_data *tls = (struct tls_data *) c->tls;
|
||||
long n;
|
||||
bool res;
|
||||
if (c->is_closing) return; // we don't clear rx buf, so ignore what's left
|
||||
if (c->is_closing) return; // we don't clear rx buf, so ignore what's left
|
||||
if (c->is_client) {
|
||||
// will clear is_hs when sending last chunk
|
||||
res = mg_tls_client_handshake(c);
|
||||
@@ -1652,6 +1928,310 @@ void mg_tls_handshake(struct mg_connection *c) {
|
||||
// otherwise, it needs to be flushed
|
||||
}
|
||||
|
||||
static int mg_rsa_parse_der_int(const uint8_t **p, const uint8_t *end,
|
||||
struct mg_str *out) {
|
||||
const uint8_t *start = *p;
|
||||
uint32_t len;
|
||||
|
||||
if (end - start < 2) {
|
||||
MG_VERBOSE(("DER INT: not enough bytes (%d < 2)", (int) (end - start)));
|
||||
return -1;
|
||||
}
|
||||
if (start[0] != 0x02) {
|
||||
MG_VERBOSE(("DER INT: expected 0x02, got 0x%02x", start[0]));
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = start[1];
|
||||
*p = start + 2;
|
||||
|
||||
if (len > 0x7F) {
|
||||
// Long form length
|
||||
uint8_t len_bytes = len & 0x7F;
|
||||
MG_VERBOSE(("DER INT: long form, %d length bytes", len_bytes));
|
||||
if (end - *p < len_bytes) {
|
||||
MG_VERBOSE(("DER INT: not enough bytes for length"));
|
||||
return -1;
|
||||
}
|
||||
len = 0;
|
||||
for (uint8_t i = 0; i < len_bytes; i++) {
|
||||
len = (len << 8) | (*p)[i];
|
||||
}
|
||||
*p += len_bytes;
|
||||
}
|
||||
|
||||
MG_VERBOSE(("DER INT: length=%u, remaining=%d", len, (int) (end - *p)));
|
||||
|
||||
if (end - *p < (long) len) {
|
||||
MG_VERBOSE(("DER INT: length exceeds remaining bytes"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// The encoded length tells us how many bytes to consume from the stream
|
||||
const uint8_t *value_start = *p;
|
||||
const uint8_t *value_end = *p + len;
|
||||
|
||||
// Skip leading zero byte if present (for positive numbers)
|
||||
// This doesn't change how many bytes we consume, just what we expose
|
||||
if (len > 0 && (*p)[0] == 0x00) {
|
||||
(*p)++;
|
||||
len--;
|
||||
}
|
||||
|
||||
out->buf = (char *) *p;
|
||||
out->len = len;
|
||||
|
||||
// Advance pointer by the ORIGINAL encoded length, not the adjusted length
|
||||
*p = value_end;
|
||||
|
||||
MG_VERBOSE(("DER INT: parsed %u bytes (skipped zero=%d)", len,
|
||||
value_end - value_start != len ? 1 : 0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// RFC 5915 ECPrivateKey ::= SEQUENCE {
|
||||
// version INTEGER { ecPrivkeyVer1(1) },
|
||||
// privateKey OCTET STRING,
|
||||
// parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
|
||||
// publicKey [1] BIT STRING OPTIONAL
|
||||
// }
|
||||
static int mg_parse_ec_private_key(const uint8_t *der, size_t dersz,
|
||||
uint8_t *ec_key) {
|
||||
struct mg_der_tlv root, version, private_key_octets;
|
||||
|
||||
if (mg_der_parse((uint8_t *) der, dersz, &root) < 0 || root.type != 0x30) {
|
||||
MG_ERROR(("EC private key: invalid SEQUENCE"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mg_der_next(&root, &version) < 0 || version.type != 0x02) {
|
||||
MG_ERROR(("EC private key: invalid version"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mg_der_next(&root, &private_key_octets) < 0 ||
|
||||
private_key_octets.type != 0x04) {
|
||||
MG_ERROR(("EC private key: invalid privateKey OCTET STRING"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (private_key_octets.len != 32) {
|
||||
MG_ERROR(
|
||||
("EC private key: expected 32 bytes, got %u", private_key_octets.len));
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(ec_key, private_key_octets.value, 32);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Parse RSA private key from DER format
|
||||
// RSAPrivateKey ::= SEQUENCE {
|
||||
// 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 = (inverse of q) mod p
|
||||
// }
|
||||
int mg_rsa_parse_key(const uint8_t *der, size_t dersz, struct mg_rsa_key *key) {
|
||||
const uint8_t *p = der;
|
||||
const uint8_t *end = der + dersz;
|
||||
uint32_t seq_len;
|
||||
struct mg_str version;
|
||||
|
||||
memset(key, 0, sizeof(*key));
|
||||
|
||||
// Debug: show first few bytes
|
||||
MG_DEBUG(
|
||||
("RSA key DER first 16 bytes: %02x %02x %02x %02x %02x %02x %02x %02x "
|
||||
"%02x %02x %02x %02x %02x %02x %02x %02x",
|
||||
der[0], der[1], der[2], der[3], der[4], der[5], der[6], der[7], der[8],
|
||||
der[9], der[10], der[11], der[12], der[13], der[14], der[15]));
|
||||
|
||||
// Parse outer SEQUENCE
|
||||
if (end - p < 2) {
|
||||
MG_ERROR(("RSA key too short for SEQUENCE header"));
|
||||
return -1;
|
||||
}
|
||||
if (p[0] != 0x30) {
|
||||
MG_ERROR(("RSA key: expected SEQUENCE (0x30), got 0x%02x", p[0]));
|
||||
return -1;
|
||||
}
|
||||
|
||||
seq_len = p[1];
|
||||
p += 2;
|
||||
|
||||
if (seq_len > 0x7F) {
|
||||
// Long form length
|
||||
uint8_t len_bytes = seq_len & 0x7F;
|
||||
MG_DEBUG(("Long form length: %d bytes", len_bytes));
|
||||
if (end - p < len_bytes) {
|
||||
MG_ERROR(("Not enough bytes for long form length"));
|
||||
return -1;
|
||||
}
|
||||
seq_len = 0;
|
||||
for (uint8_t i = 0; i < len_bytes; i++) {
|
||||
seq_len = (seq_len << 8) | p[i];
|
||||
}
|
||||
p += len_bytes;
|
||||
}
|
||||
|
||||
MG_DEBUG(
|
||||
("SEQUENCE length: %u, total DER size: %u", seq_len, (unsigned) dersz));
|
||||
|
||||
if (end - p < (long) seq_len) {
|
||||
MG_ERROR(("SEQUENCE length exceeds buffer"));
|
||||
return -1;
|
||||
}
|
||||
end = p + seq_len; // Adjust end to sequence boundary
|
||||
|
||||
// Parse version (should be 0)
|
||||
MG_DEBUG(("Before version: offset=%d, bytes: %02x %02x %02x %02x",
|
||||
(int) (p - der), p[0], p[1], p[2], p[3]));
|
||||
if (mg_rsa_parse_der_int(&p, end, &version) < 0) {
|
||||
MG_ERROR(("Failed to parse version"));
|
||||
return -1;
|
||||
}
|
||||
MG_DEBUG(("Version: %d byte(s), value=%d, offset now=%d", (int) version.len,
|
||||
version.len > 0 ? (int) (unsigned char) version.buf[0] : -1,
|
||||
(int) (p - der)));
|
||||
|
||||
// Parse the 8 components: n, e, d, p, q, dP, dQ, qInv
|
||||
MG_DEBUG(("Before n: offset=%d, bytes: %02x %02x %02x %02x %02x %02x",
|
||||
(int) (p - der), p[0], p[1], p[2], p[3], p[4], p[5]));
|
||||
if (mg_rsa_parse_der_int(&p, end, &key->n) < 0) {
|
||||
MG_ERROR(("Failed to parse n (modulus)"));
|
||||
return -1;
|
||||
}
|
||||
MG_DEBUG(("Parsed n: %d bytes, offset now=%d, consumed=%d bytes total",
|
||||
(int) key->n.len, (int) (p - der), (int) (p - der)));
|
||||
MG_DEBUG((" First 8 bytes of n: %02x %02x %02x %02x %02x %02x %02x %02x",
|
||||
(unsigned char) key->n.buf[0], (unsigned char) key->n.buf[1],
|
||||
(unsigned char) key->n.buf[2], (unsigned char) key->n.buf[3],
|
||||
(unsigned char) key->n.buf[4], (unsigned char) key->n.buf[5],
|
||||
(unsigned char) key->n.buf[6], (unsigned char) key->n.buf[7]));
|
||||
MG_DEBUG((" Next bytes after n: %02x %02x %02x %02x %02x %02x",
|
||||
p < end ? p[0] : 0xFF, p + 1 < end ? p[1] : 0xFF,
|
||||
p + 2 < end ? p[2] : 0xFF, p + 3 < end ? p[3] : 0xFF,
|
||||
p + 4 < end ? p[4] : 0xFF, p + 5 < end ? p[5] : 0xFF));
|
||||
|
||||
if (mg_rsa_parse_der_int(&p, end, &key->e) < 0) {
|
||||
MG_ERROR(("Failed to parse e (public exponent), bytes remaining: %d",
|
||||
(int) (end - p)));
|
||||
if (end - p >= 4) {
|
||||
MG_ERROR((" Next 4 bytes: %02x %02x %02x %02x", p[0], p[1], p[2], p[3]));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (mg_rsa_parse_der_int(&p, end, &key->d) < 0) {
|
||||
MG_ERROR(("Failed to parse d (private exponent)"));
|
||||
return -1;
|
||||
}
|
||||
if (mg_rsa_parse_der_int(&p, end, &key->p) < 0) {
|
||||
MG_ERROR(("Failed to parse p (prime1)"));
|
||||
return -1;
|
||||
}
|
||||
if (mg_rsa_parse_der_int(&p, end, &key->q) < 0) {
|
||||
MG_ERROR(("Failed to parse q (prime2)"));
|
||||
return -1;
|
||||
}
|
||||
if (mg_rsa_parse_der_int(&p, end, &key->dP) < 0) {
|
||||
MG_ERROR(("Failed to parse dP (exponent1)"));
|
||||
return -1;
|
||||
}
|
||||
if (mg_rsa_parse_der_int(&p, end, &key->dQ) < 0) {
|
||||
MG_ERROR(("Failed to parse dQ (exponent2)"));
|
||||
return -1;
|
||||
}
|
||||
if (mg_rsa_parse_der_int(&p, end, &key->qInv) < 0) {
|
||||
MG_ERROR(("Failed to parse qInv (coefficient)"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
MG_DEBUG(("Successfully parsed RSA key"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// PKCS#8 PrivateKeyInfo ::= SEQUENCE {
|
||||
// version INTEGER,
|
||||
// privateKeyAlgorithm AlgorithmIdentifier,
|
||||
// privateKey OCTET STRING,
|
||||
// attributes [0] Attributes OPTIONAL
|
||||
// }
|
||||
// AlgorithmIdentifier ::= SEQUENCE {
|
||||
// algorithm OBJECT IDENTIFIER,
|
||||
// parameters ANY OPTIONAL
|
||||
// }
|
||||
static int mg_parse_pkcs8_key(const uint8_t *der, size_t dersz,
|
||||
struct tls_data *tls) {
|
||||
struct mg_der_tlv root, version, alg_id, private_key_octets;
|
||||
struct mg_der_tlv alg_oid, alg_params;
|
||||
|
||||
if (mg_der_parse((uint8_t *) der, dersz, &root) < 0 || root.type != 0x30) {
|
||||
MG_ERROR(("PKCS#8: invalid PrivateKeyInfo SEQUENCE"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mg_der_next(&root, &version) < 0 || version.type != 0x02) {
|
||||
MG_ERROR(("PKCS#8: invalid version"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mg_der_next(&root, &alg_id) < 0 || alg_id.type != 0x30) {
|
||||
MG_ERROR(("PKCS#8: invalid AlgorithmIdentifier SEQUENCE"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mg_der_next(&alg_id, &alg_oid) < 0 || alg_oid.type != 0x06) {
|
||||
MG_ERROR(("PKCS#8: invalid algorithm OID"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mg_der_next(&root, &private_key_octets) < 0 ||
|
||||
private_key_octets.type != 0x04) {
|
||||
MG_ERROR(("PKCS#8: invalid privateKey OCTET STRING"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (alg_oid.len == sizeof(mg_rsa_oid) &&
|
||||
memcmp(alg_oid.value, mg_rsa_oid, sizeof(mg_rsa_oid)) == 0) {
|
||||
struct mg_rsa_key rsa_key;
|
||||
if (mg_rsa_parse_key(private_key_octets.value, private_key_octets.len,
|
||||
&rsa_key) < 0) {
|
||||
MG_ERROR(("PKCS#8: failed to parse inner RSA key"));
|
||||
return -1;
|
||||
}
|
||||
tls->rsa = rsa_key;
|
||||
return 0;
|
||||
|
||||
} else if (alg_oid.len == sizeof(mg_ec_public_key_oid) &&
|
||||
memcmp(alg_oid.value, mg_ec_public_key_oid,
|
||||
sizeof(mg_ec_public_key_oid)) == 0) {
|
||||
if (mg_der_next(&alg_id, &alg_params) < 0 || alg_params.type != 0x06) {
|
||||
MG_ERROR(("PKCS#8: invalid EC parameters OID"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (alg_params.len != sizeof(mg_secp256r1_oid) ||
|
||||
memcmp(alg_params.value, mg_secp256r1_oid, sizeof(mg_secp256r1_oid)) !=
|
||||
0) {
|
||||
MG_ERROR(("PKCS#8: unsupported EC curve (only secp256r1 supported)"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return mg_parse_ec_private_key(private_key_octets.value,
|
||||
private_key_octets.len, tls->ec_key);
|
||||
|
||||
} else {
|
||||
MG_ERROR(("PKCS#8: unsupported algorithm"));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int mg_parse_pem(const struct mg_str pem, const struct mg_str label,
|
||||
struct mg_str *der) {
|
||||
size_t n = 0, m = 0;
|
||||
@@ -1685,6 +2265,70 @@ static int mg_parse_pem(const struct mg_str pem, const struct mg_str label,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mg_parse_pem_certs(const struct mg_str pem, struct mg_str **ders) {
|
||||
int count = 0;
|
||||
struct mg_str *certs = NULL;
|
||||
const char *p = pem.buf;
|
||||
const char *end = pem.buf + pem.len;
|
||||
const char *begin_marker = "-----BEGIN CERTIFICATE-----";
|
||||
const char *end_marker = "-----END CERTIFICATE-----";
|
||||
size_t begin_len = strlen(begin_marker);
|
||||
size_t end_len = strlen(end_marker);
|
||||
|
||||
while (p < end) {
|
||||
const char *begin = NULL;
|
||||
for (const char *s = p; s <= end - (int) begin_len; s++) {
|
||||
if (memcmp(s, begin_marker, begin_len) == 0) {
|
||||
begin = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (begin == NULL) break;
|
||||
|
||||
const char *finish = NULL;
|
||||
for (const char *s = begin + begin_len; s <= end - (int) end_len; s++) {
|
||||
if (memcmp(s, end_marker, end_len) == 0) {
|
||||
finish = s + end_len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (finish == NULL) {
|
||||
for (int i = 0; i < count; i++) mg_free((void *) certs[i].buf);
|
||||
mg_free(certs);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct mg_str cert_pem = mg_str_n(begin, (size_t) (finish - begin));
|
||||
struct mg_str cert_der;
|
||||
|
||||
if (mg_parse_pem(cert_pem, mg_str_s("CERTIFICATE"), &cert_der) < 0) {
|
||||
for (int i = 0; i < count; i++) mg_free((void *) certs[i].buf);
|
||||
mg_free(certs);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct mg_str *new_certs =
|
||||
(struct mg_str *) mg_calloc((size_t) count + 1, sizeof(struct mg_str));
|
||||
if (new_certs == NULL) {
|
||||
mg_free((void *) cert_der.buf);
|
||||
for (int i = 0; i < count; i++) mg_free((void *) certs[i].buf);
|
||||
mg_free(certs);
|
||||
return -1;
|
||||
}
|
||||
if (count > 0) {
|
||||
memmove(new_certs, certs, (size_t) count * sizeof(struct mg_str));
|
||||
mg_free(certs);
|
||||
}
|
||||
certs = new_certs;
|
||||
|
||||
certs[count++] = cert_der;
|
||||
p = finish;
|
||||
}
|
||||
|
||||
*ders = certs;
|
||||
return count;
|
||||
}
|
||||
|
||||
void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
|
||||
struct mg_str key;
|
||||
struct tls_data *tls =
|
||||
@@ -1728,9 +2372,23 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
|
||||
}
|
||||
|
||||
// parse PEM or DER certificate
|
||||
if (mg_parse_pem(opts->cert, mg_str_s("CERTIFICATE"), &tls->cert_der) < 0) {
|
||||
MG_ERROR(("Failed to load certificate"));
|
||||
return;
|
||||
struct mg_str *all_certs = NULL;
|
||||
int cert_count = mg_parse_pem_certs(opts->cert, &all_certs);
|
||||
|
||||
if (cert_count > 0) {
|
||||
tls->cert_der.buf = all_certs[0].buf;
|
||||
tls->cert_der.len = all_certs[0].len;
|
||||
if (cert_count > 1) {
|
||||
tls->chain_len = (size_t) cert_count;
|
||||
tls->chain_der = all_certs;
|
||||
} else {
|
||||
mg_free(all_certs);
|
||||
}
|
||||
} else {
|
||||
if (mg_parse_pem(opts->cert, mg_str_s("CERTIFICATE"), &tls->cert_der) < 0) {
|
||||
MG_ERROR(("Failed to load certificate"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// parse PEM or DER EC key
|
||||
@@ -1755,10 +2413,51 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
|
||||
}
|
||||
memmove(tls->ec_key, key.buf + 7, 32);
|
||||
mg_free((void *) key.buf);
|
||||
} else if (mg_parse_pem(opts->key, mg_str_s("RSA PRIVATE KEY"), &key) == 0) {
|
||||
// RSA private key found, store it for later use
|
||||
tls->rsa_key_der = key;
|
||||
MG_INFO(("Parsed RSA private key: %d bytes", (int) key.len));
|
||||
|
||||
// parse and validate the key structure
|
||||
// we keep the DER buffer, rsa_key just points into it
|
||||
struct mg_rsa_key rsa_key;
|
||||
if (mg_rsa_parse_key((const uint8_t *) key.buf, key.len, &rsa_key) < 0) {
|
||||
MG_ERROR(("Failed to parse RSA private key structure"));
|
||||
mg_free((void *) key.buf);
|
||||
tls->rsa_key_der = mg_str_n(NULL, 0);
|
||||
mg_error(c, "Invalid RSA private key format");
|
||||
return;
|
||||
}
|
||||
|
||||
MG_VERBOSE(("RSA key components:"));
|
||||
MG_VERBOSE((" n (modulus): %d bytes", (int) rsa_key.n.len));
|
||||
MG_VERBOSE((" e (pubexp): %d bytes", (int) rsa_key.e.len));
|
||||
MG_VERBOSE((" d (privexp): %d bytes", (int) rsa_key.d.len));
|
||||
MG_VERBOSE((" p (prime1): %d bytes", (int) rsa_key.p.len));
|
||||
MG_VERBOSE((" q (prime2): %d bytes", (int) rsa_key.q.len));
|
||||
MG_VERBOSE((" dP: %d bytes", (int) rsa_key.dP.len));
|
||||
MG_VERBOSE((" dQ: %d bytes", (int) rsa_key.dQ.len));
|
||||
MG_VERBOSE((" qInv: %d bytes", (int) rsa_key.qInv.len));
|
||||
|
||||
// Copy parsed RSA key components to tls->rsa for signing operations
|
||||
tls->rsa = rsa_key;
|
||||
} else if (mg_parse_pem(opts->key, mg_str_s("PRIVATE KEY"), &key) == 0) {
|
||||
mg_error(c, "PKCS8 private key format is not supported");
|
||||
if (mg_parse_pkcs8_key((const uint8_t *) key.buf, key.len, tls) == 0) {
|
||||
if (tls->rsa.n.len > 0) {
|
||||
tls->rsa_key_der = key;
|
||||
MG_INFO(("Parsed PKCS#8 RSA private key: %d bytes", (int) key.len));
|
||||
} else {
|
||||
mg_free((void *) key.buf);
|
||||
MG_INFO(("Parsed PKCS#8 EC private key"));
|
||||
}
|
||||
} else {
|
||||
mg_free((void *) key.buf);
|
||||
mg_error(c, "Unsupported PKCS#8 private key format, algorithm, or curve");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
mg_error(c, "Expected EC PRIVATE KEY or PRIVATE KEY");
|
||||
mg_error(
|
||||
c, "Expected EC PRIVATE KEY, RSA PRIVATE KEY, or PRIVATE KEY (PKCS#8)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1766,8 +2465,16 @@ void mg_tls_free(struct mg_connection *c) {
|
||||
struct tls_data *tls = (struct tls_data *) c->tls;
|
||||
if (tls != NULL) {
|
||||
mg_iobuf_free(&tls->send);
|
||||
mg_free((void *) tls->cert_der.buf);
|
||||
if (tls->chain_der != NULL) {
|
||||
for (size_t i = 0; i < tls->chain_len; i++) {
|
||||
mg_free((void *) tls->chain_der[i].buf);
|
||||
}
|
||||
mg_free(tls->chain_der);
|
||||
} else {
|
||||
mg_free((void *) tls->cert_der.buf);
|
||||
}
|
||||
mg_free((void *) tls->ca_der.buf);
|
||||
mg_free((void *) tls->rsa_key_der.buf);
|
||||
}
|
||||
mg_free(c->tls);
|
||||
c->tls = NULL;
|
||||
@@ -1783,7 +2490,7 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
|
||||
if (!mg_tls_encrypt(c, (const uint8_t *) buf, len, MG_TLS_APP_DATA))
|
||||
return 0; // returning 0 means an OOM condition (iobuf couldn't resize),
|
||||
// yet this is so far recoverable, let the caller decide
|
||||
} // else, resend outstanding encrypted data in tls->send
|
||||
} // else, resend outstanding encrypted data in tls->send
|
||||
while (tls->send.len > 0 &&
|
||||
(n = mg_io_send(c, tls->send.buf, tls->send.len)) > 0) {
|
||||
mg_iobuf_del(&tls->send, 0, (size_t) n);
|
||||
|
||||
+45
-2
@@ -1520,7 +1520,6 @@ NS_INTERNAL bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts.
|
||||
*
|
||||
@@ -1533,6 +1532,7 @@ NS_INTERNAL bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp) {
|
||||
* @param qInv [in] CRT's qInv bigint
|
||||
* @return The result of the CRT operation
|
||||
*/
|
||||
#if 1
|
||||
NS_INTERNAL bigint *bi_crt(BI_CTX *ctx, bigint *bi, bigint *dP, bigint *dQ,
|
||||
bigint *p, bigint *q, bigint *qInv) {
|
||||
bigint *m1, *m2, *h;
|
||||
@@ -1559,7 +1559,6 @@ NS_INTERNAL bigint *bi_crt(BI_CTX *ctx, bigint *bi, bigint *dP, bigint *dQ,
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Proper lib usage:
|
||||
// - BI_CTX *c = bi_initialize()
|
||||
// - allocate bigints (e.g.: calling bi_import(), int_to_bi(), ...)
|
||||
@@ -1588,4 +1587,48 @@ int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp, size_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mg_rsa_crt_sign(const uint8_t *em, size_t em_len,
|
||||
const uint8_t *dP, size_t dP_len,
|
||||
const uint8_t *dQ, size_t dQ_len,
|
||||
const uint8_t *p, size_t p_len,
|
||||
const uint8_t *q, size_t q_len,
|
||||
const uint8_t *qInv, size_t qInv_len,
|
||||
uint8_t *signature, size_t sig_len) {
|
||||
BI_CTX *ctx;
|
||||
bigint *em_bi, *dP_bi, *dQ_bi, *p_bi, *q_bi, *qInv_bi, *result_bi;
|
||||
int ret = -1;
|
||||
|
||||
ctx = bi_initialize();
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
em_bi = bi_import(ctx, em, em_len);
|
||||
dP_bi = bi_import(ctx, dP, dP_len);
|
||||
dQ_bi = bi_import(ctx, dQ, dQ_len);
|
||||
p_bi = bi_import(ctx, p, p_len);
|
||||
q_bi = bi_import(ctx, q, q_len);
|
||||
qInv_bi = bi_import(ctx, qInv, qInv_len);
|
||||
|
||||
if (em_bi == NULL || dP_bi == NULL || dQ_bi == NULL ||
|
||||
p_bi == NULL || q_bi == NULL || qInv_bi == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
bi_set_mod(ctx, bi_clone(ctx, p_bi), BIGINT_P_OFFSET);
|
||||
bi_set_mod(ctx, bi_clone(ctx, q_bi), BIGINT_Q_OFFSET);
|
||||
|
||||
result_bi = bi_crt(ctx, em_bi, dP_bi, dQ_bi, p_bi, q_bi, qInv_bi);
|
||||
if (result_bi == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
bi_export(ctx, result_bi, signature, sig_len);
|
||||
ret = 0; // Success!
|
||||
cleanup:
|
||||
bi_free_mod(ctx, BIGINT_P_OFFSET); // cloned p_bi stored in mod context
|
||||
bi_free_mod(ctx, BIGINT_Q_OFFSET); // cloned q_bi stored in mod context
|
||||
bi_terminate(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* MG_TLS == MG_TLS_BUILTIN */
|
||||
+7
-1
@@ -3,5 +3,11 @@
|
||||
|
||||
#include "arch.h"
|
||||
int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp, size_t expsz, const uint8_t *msg, size_t msgsz, uint8_t *out, size_t outsz);
|
||||
|
||||
int mg_rsa_crt_sign(const uint8_t *em, size_t em_len,
|
||||
const uint8_t *dP, size_t dP_len,
|
||||
const uint8_t *dQ, size_t dQ_len,
|
||||
const uint8_t *p, size_t p_len,
|
||||
const uint8_t *q, size_t q_len,
|
||||
const uint8_t *qInv, size_t qInv_len,
|
||||
uint8_t *signature, size_t sig_len);
|
||||
#endif // TLS_RSA_H
|
||||
Reference in new issue
Block a user