zxid
view release on metacpan or search on metacpan
int siz = nonce + 2 + len + *zlen;
ROUND_UP(siz, nonce); /* Round up to block size */
p = ZX_ALLOC(cf->ctx, siz);
if (nonce)
zx_rand(p, nonce);
p[nonce] = (len >> 8) & 0xff;
p[nonce+1] = len & 0xff;
if (len) {
memcpy(p+nonce+2, sig, len);
ZX_FREE(cf->ctx, sig);
}
memcpy(p+nonce+2+len, zbuf, *zlen);
ZX_FREE(cf->ctx, zbuf);
*zlen += nonce + 2 + len;
return p;
}
/*() Write a line to a log, taking care of all formalities of locking and
* observing all special options for signing and encryption of the logs.
* Not usually called directly (but you can if you want to), this is the
* work horse behind zxlog().
*
* cf:: ZXID configuration object, used for memory allocation.
* c_path:: Path to the log file, as C string
* encflags:: Encryption flags. See LOG_ERR or LOG_ACT configuration options in zxidconf.h
* n:: length of log data
* logbuf:: The data that should be logged
*/
/* Called by: test_mode x12, zxlog_output x2 */
void zxlog_write_line(zxid_conf* cf, char* c_path, int encflags, int n, const char* logbuf)
{
EVP_PKEY* log_sign_pkey;
struct rsa_st* rsa_pkey;
struct aes_key_st aes_key;
int len = 0, blen, zlen;
char sigletter = 'P';
char encletter = 'P';
char* p;
char* sig = 0;
char* zbuf;
char* b64;
char sigbuf[28+4]; /* Space for "SP " and sha1 */
char keybuf[16];
char ivec[16];
if (n == -2)
n = strlen(logbuf);
if (encflags & 0x70) { /* Encrypt check */
zbuf = zx_zlib_raw_deflate(cf->ctx, n-1, logbuf, &zlen);
switch (encflags & 0x06) { /* Sign check */
case 0x02: /* Sx plain sha1 */
sigletter = 'S';
sig = ZX_ALLOC(cf->ctx, 20);
SHA1((unsigned char*)zbuf, zlen, (unsigned char*)sig);
len = 20;
break;
case 0x04: /* Rx RSA-SHA1 signature */
sigletter = 'R';
LOCK(cf->mx, "logsign wrln");
if (!(log_sign_pkey = cf->log_sign_pkey))
log_sign_pkey = cf->log_sign_pkey = zxid_read_private_key(cf, "logsign-nopw-cert.pem");
UNLOCK(cf->mx, "logsign wrln");
if (!log_sign_pkey)
break;
len = zxsig_data(cf->ctx, zlen, zbuf, &sig, log_sign_pkey, "enc log line", cf->blobsig_digest_algo);
break;
case 0x06: /* Dx DSA-SHA1 signature */
ERR("DSA-SHA1 sig not implemented in encrypted mode. Use RSA-SHA1 or none. %x", encflags);
break;
case 0: break; /* Px no signing */
}
switch (encflags & 0x70) {
case 0x10: /* xZ RFC1951 zip + safe base64 */
encletter = 'Z';
zbuf = zxlog_alloc_zbuf(cf, &zlen, zbuf, len, sig, 0);
break;
case 0x20: /* xA RSA-AES */
encletter = 'A';
zbuf = zxlog_alloc_zbuf(cf, &zlen, zbuf, len, sig, 16);
zx_rand(keybuf, 16);
AES_set_encrypt_key((unsigned char*)keybuf, 128, &aes_key);
memcpy(ivec, zbuf, sizeof(ivec));
AES_cbc_encrypt((unsigned char*)zbuf+16, (unsigned char*)zbuf+16, zlen-16, &aes_key, (unsigned char*)ivec, 1);
ROUND_UP(zlen, 16); /* Round up to block size */
LOCK(cf->mx, "logenc wrln");
if (!cf->log_enc_cert)
cf->log_enc_cert = zxid_read_cert(cf, "logenc-nopw-cert.pem");
rsa_pkey = zx_get_rsa_pub_from_cert(cf->log_enc_cert, "log_enc_cert");
UNLOCK(cf->mx, "logenc wrln");
if (!rsa_pkey)
break;
len = RSA_size(rsa_pkey);
sig = ZX_ALLOC(cf->ctx, len);
if (RSA_public_encrypt(16, (unsigned char*)keybuf, (unsigned char*)sig, rsa_pkey, RSA_PKCS1_OAEP_PADDING) < 0) {
ERR("RSA enc fail %x", encflags);
zx_report_openssl_err("zxlog rsa enc");
return;
}
p = ZX_ALLOC(cf->ctx, 2 + len + zlen);
p[0] = (len >> 8) & 0xff;
p[1] = len & 0xff;
memcpy(p+2, sig, len);
memcpy(p+2+len, zbuf, zlen);
ZX_FREE(cf->ctx, sig);
ZX_FREE(cf->ctx, zbuf);
zbuf = p;
zlen += 2 + len;
break;
case 0x30: /* xT RSA-3DES */
encletter = 'T';
ERR("Enc not implemented %x", encflags);
break;
case 0x40: /* xB AES */
encletter = 'B';
zbuf = zxlog_alloc_zbuf(cf, &zlen, zbuf, len, sig, 16);
if (!cf->log_symkey[0])
zx_get_symkey(cf, "logenc.key", cf->log_symkey);
AES_set_encrypt_key((unsigned char*)cf->log_symkey, 128, &aes_key);
memcpy(ivec, zbuf, sizeof(ivec));
AES_cbc_encrypt((unsigned char*)zbuf+16, (unsigned char*)zbuf+16, zlen-16, &aes_key, (unsigned char*)ivec, 1);
ROUND_UP(zlen, 16); /* Round up to block size */
break;
case 0x50: /* xU 3DES */
encletter = 'U';
ERR("Enc not implemented %x", encflags);
break;
default:
ERR("Enc not implemented %x", encflags);
break;
}
blen = SIMPLE_BASE64_LEN(zlen) + 3 + 1;
b64 = ZX_ALLOC(cf->ctx, blen);
b64[0] = sigletter;
b64[1] = encletter;
b64[2] = ' ';
p = base64_fancy_raw(zbuf, zlen, b64+3, safe_basis_64, 1<<31, 0, 0, '.');
blen = p-b64 + 1;
*p = '\n';
write2_or_append_lock_c_path(c_path, 0, 0, blen, b64, "zxlog enc", SEEK_END, O_APPEND);
return;
}
/* Plain text, possibly signed. */
switch (encflags & 0x06) {
case 0x02: /* SP plain sha1 */
strcpy(sigbuf, "SP ");
sha1_safe_base64(sigbuf+3, n-1, logbuf);
sigbuf[3+27] = ' ';
len = 3+27+1;
p = sigbuf;
break;
case 0x04: /* RP RSA-SHA1 signature */
LOCK(cf->mx, "logsign wrln");
if (!(log_sign_pkey = cf->log_sign_pkey))
log_sign_pkey = cf->log_sign_pkey = zxid_read_private_key(cf, "logsign-nopw-cert.pem");
UNLOCK(cf->mx, "logsign wrln");
if (!log_sign_pkey)
break;
zlen = zxsig_data(cf->ctx, n-1, logbuf, &zbuf, log_sign_pkey, "log line", cf->blobsig_digest_algo);
len = SIMPLE_BASE64_LEN(zlen) + 4;
sig = ZX_ALLOC(cf->ctx, len);
strcpy(sig, "RP ");
p = base64_fancy_raw(zbuf, zlen, sig+3, safe_basis_64, 1<<31, 0, 0, '.');
len = p-sig + 1;
*p = ' ';
p = sig;
break;
case 0x06: /* DP DSA-SHA1 signature */
ERR("DSA-SHA1 signature not implemented %x", encflags);
break;
case 0: /* Plain logging, no signing, no encryption. */
len = 5;
p = "PP - ";
break;
}
write2_or_append_lock_c_path(c_path, len, p, n, logbuf, "zxlog sig", SEEK_END, O_APPEND);
if (sig)
ZX_FREE(cf->ctx, sig);
}
/*() Helper function for formatting all kinds of logs.
* This is the real workhorse. */
static int zxlog_fmt(zxid_conf* cf, /* 1 */
int len, char* logbuf,
struct timeval* ourts, /* 2 null allowed, will use current time */
struct timeval* srcts, /* 3 null allowed, will use start of unix epoch... */
const char* ipport, /* 4 null allowed, -:- or cf->ipport if not given */
struct zx_str* entid, /* 5 null allowed, - if not given */
struct zx_str* msgid, /* 6 null allowed, - if not given */
struct zx_str* a7nid, /* 7 null allowed, - if not given */
struct zx_str* nid, /* 8 null allowed, - if not given */
const char* sigval, /* 9 null allowed, - if not given */
const char* res, /* 10 */
const char* op, /* 11 */
const char* arg, /* 12 null allowed, - if not given */
const char* fmt, /* 13 null allowed as format, ends the line */
va_list ap)
{
int n;
char* p;
char sha1_name[28];
struct tm ot;
struct tm st;
struct timeval ourtsdefault;
struct timeval srctsdefault;
/* Prepare values */
if (!ourts) {
ourts = &ourtsdefault;
GETTIMEOFDAY(ourts, 0);
}
if (!srcts) {
srcts = &srctsdefault;
if (!dest)
dest_len = 0;
if (dest_len == -1)
dest_len = strlen(dest);
else if (dest_len == -2)
dest_len = strchr(dest, '\n') - dest;
if (!eid)
eid_len = 0;
if (eid_len == -1)
eid_len = strlen(eid);
else if (eid_len == -2)
eid_len = strchr(eid, '\n') - eid;
if (!body)
body_len = 0;
if (body_len == -1)
body_len = strlen(body);
else if (body_len == -2)
body_len = strchr(body, '\n') - body;
/* Prepare values */
GETTIMEOFDAY(&ourts, 0);
GMTIME_R(ourts.tv_sec, ot);
/* Prepare timestamp prepended data for hashing */
len = ZXLOG_TIME_SIZ+1+mid_len+1+dest_len+1+eid_len+1+body_len;
buf = ZX_ALLOC(cf->ctx, len+1);
zlen = snprintf(buf, len+1, ZXLOG_TIME_FMT " %.*s %.*s %.*s %.*s",
ZXLOG_TIME_ARG(ot, ourts.tv_usec),
mid_len, mid_len?mid:"",
dest_len, dest_len?dest:"",
eid_len, eid_len?eid:"",
body_len, body_len?body:"");
ASSERTOPI(zlen, ==, len);
buf[len] = 0; /* must terminate manually as on win32 nul is not guaranteed */
ASSERT(sigbuf_len >= 3+ZXLOG_TIME_SIZ+1);
strcpy(sigbuf, "EP ");
memcpy(sigbuf+3, buf, ZXLOG_TIME_SIZ);
sigbuf[3+ZXLOG_TIME_SIZ] = ' ';
memcpy(sigbuf+3+ZXLOG_TIME_SIZ+1, mid, mid_len);
sigbuf[3+ZXLOG_TIME_SIZ+1+mid_len] = 0;
switch (cf->bus_rcpt & 0x06) {
case 0x02: /* SP plain sha */
if (sigbuf_len < 3+ZXLOG_TIME_SIZ+1+mid_len+1+27+1) { ERR("Too small sigbuf %d", sigbuf_len); break; }
D("sha len=%d input(%.*s)", len, len, buf);
sigbuf[3+ZXLOG_TIME_SIZ+1+mid_len] = ' ';
sha1_safe_base64(sigbuf+3+ZXLOG_TIME_SIZ+1+mid_len+1, len, buf);
sigbuf[3+ZXLOG_TIME_SIZ+1+mid_len+1+27] = 0;
sigbuf[0] = 'S';
break;
case 0x04: /* RP RSA-SHA signature (detected from key) */
case 0x06: /* RP DSA-SHA signature (detected from key) */
LOCK(cf->mx, "mint_receipt");
/* The sign_pkey is used instead of log_sign_pkey because metadata is used to distribute it. */
if (!cf->sign_pkey)
cf->sign_pkey = zxid_read_private_key(cf, "sign-nopw-cert.pem");
UNLOCK(cf->mx, "mint_receipt");
DD("sign_pkey=%p buf(%.*s) len=%d buf(%s)", cf->sign_pkey, len, buf, len, buf);
if (!cf->sign_pkey)
break;
zlen = zxsig_data(cf->ctx, len, buf, &zbuf, cf->sign_pkey, "receipt", cf->blobsig_digest_algo);
if (errmac_debug>2) HEXDUMP("zbuf:", zbuf, zbuf+zlen, 4096);
len = 3+ZXLOG_TIME_SIZ+1+mid_len+1+SIMPLE_BASE64_LEN(zlen)+1;
if (sigbuf_len < len) { ERR("Too small sigbuf_len=%d, need=%d", sigbuf_len, len); break; }
sigbuf[3+ZXLOG_TIME_SIZ+1+mid_len] = ' ';
p = base64_fancy_raw(zbuf, zlen, sigbuf+3+ZXLOG_TIME_SIZ+1+mid_len+1, safe_basis_64, 1<<31, 0, 0, '.');
*p = 0;
switch (EVP_PKEY_type(cf->sign_pkey->type)) {
case EVP_PKEY_RSA: sigbuf[0] = 'R'; break;
case EVP_PKEY_DSA: sigbuf[0] = 'D'; break;
case EVP_PKEY_EC: sigbuf[0] = 'C'; break;
default: sigbuf[0] = 'E'; ERR("Unknown pkey type=%d", EVP_PKEY_type(cf->sign_pkey->type));
}
break;
case 0: /* Plain logging, no signing, no encryption. */
sigbuf[0] = 'P';
break;
}
DD("body(%.*s) body_len=%d", body_len, body_len?body:"", body_len);
if (errmac_debug>1)
D("zx-rcpt-sig(%s) sigbuf_len=%d len=%d\nbuf(%s) buflen=%d %x %x", sigbuf, (int)strlen(sigbuf), len, buf, (int)strlen(buf), cf->bus_rcpt, cf->bus_rcpt&0x06);
else
D("zx-rcpt-sig(%s) %x", sigbuf, cf->bus_rcpt);
if (zbuf)
ZX_FREE(cf->ctx, zbuf);
ZX_FREE(cf->ctx, buf);
return sigbuf;
}
/*() Verify a zxbus receipt signature.
*
* cf:: ZXID configuration object, used for memory allocation and CoT mgmt
* eid:: EntityID of the receipt issuing party, used to lookup metadata
* sigbuf_len:: Length of signature buffer (from zx-rcpt-sig header) or -1 for strlen(sigbuf)
* sigbuf:: The receipt (from zx-rcpt-sig header)
* mid_len:: Length of message id (-1 to use strlen(mid))
* mid:: Message ID
* dest_len:: Length of destination (-1 to use strlen(dest))
* dest:: Destination channel for the receipt
* deid_len:: Length of destination entity id (-1 to use strlen(eid))
* deid:: Entity ID of receiving party
* body_len:: Length of data pertaining to receipt (-1 to use strlen(body))
* body:: Data pertaining to receipt
* return:: 0 (ZXSIG_OK) on success, nonzero on failure. */
/* Called by: stomp_got_ack, test_receipt x10, zxbus_send_cmdf */
int zxbus_verify_receipt(zxid_conf* cf, const char* eid, int sigbuf_len, char* sigbuf, int mid_len, const char* mid, int dest_len, const char* dest, int deid_len, const char* deid, int body_len, const char* body)
{
int ver = -4, len, zlen;
char* p;
char* buf;
char sig[1024];
char sha1[20];
zxid_entity* meta;
if (sigbuf_len == -1)
sigbuf_len = strlen(sigbuf);
else if (sigbuf_len == -2)
sigbuf_len = strchr(sigbuf, '\n') - sigbuf;
if (!mid)
mid_len = 0;
if (mid_len == -1)
mid_len = strlen(mid);
else if (mid_len == -2)
mid_len = strchr(mid, '\n') - mid;
if (!dest)
dest_len = 0;
if (dest_len == -1)
dest_len = strlen(dest);
else if (dest_len == -2)
dest_len = strchr(dest, '\n') - dest;
if (!deid)
deid_len = 0;
if (deid_len == -1)
deid_len = strlen(deid);
else if (deid_len == -2)
deid_len = strchr(deid, '\n') - deid;
if (!body)
body_len = 0;
if (body_len == -1)
body_len = strlen(body);
else if (body_len == -2)
body_len = strchr(body, '\n') - body;
DD("body(%.*s) body_len=%d", body_len, body_len?body:"", body_len);
D("zx-rcpt-sig(%.*s) sigbuf_len=%d", sigbuf_len, sigbuf, sigbuf_len);
len = ZXLOG_TIME_SIZ+1+mid_len+1+dest_len+1+deid_len+1+body_len;
//len = ZXLOG_TIME_SIZ+1+body_len;
buf = ZX_ALLOC(cf->ctx, len+1);
zlen = snprintf(buf, len+1, "%.*s %.*s %.*s %.*s %.*s",
ZXLOG_TIME_SIZ, sigbuf+3,
mid_len, mid_len?mid:"",
dest_len, dest_len?dest:"",
deid_len, deid_len?deid:"",
body_len, body_len?body:"");
ASSERTOPI(zlen, ==, len);
buf[len] = 0; /* must terminate manually as on win32 nul is not guaranteed */
switch (sigbuf[0]) {
case 'R':
case 'D':
case 'C':
meta = zxid_get_ent(cf, eid);
if (!meta) {
ERR("Unable to find metadata for eid(%s) in verify receipt", eid);
ver = -2;
break;
}
//D("check_private_key(%d)",X509_check_private_key(meta->sign_cert, cf->sign_pkey));
if (SIMPLE_BASE64_PESSIMISTIC_DECODE_LEN(sigbuf_len) > sizeof(sig)) {
ERR("Available signature decoding buffer is too short len=%d, need=%d", (int)sizeof(sig), SIMPLE_BASE64_PESSIMISTIC_DECODE_LEN(sigbuf_len));
ver = -3;
break;
}
p = sigbuf+3+ZXLOG_TIME_SIZ+1+mid_len+1;
DD("zx-rcpt-sig(%.*s) sigbuf_len=%d", sigbuf_len, sigbuf, sigbuf_len);
D("sigbuf(%.*s) len=%d sigbuf=%p lim=%p", (int)(sigbuf_len-(p-sigbuf)), p, (int)(sigbuf_len-(p-sigbuf)), p, sigbuf+sigbuf_len);
p = unbase64_raw(p, sigbuf+sigbuf_len, sig, zx_std_index_64);
ver = zxsig_verify_data(len, buf, p-sig, sig, meta->sign_cert, "rcpt vfy", cf->blobsig_digest_algo);
if (ver)
D("ver=%d buf(%.*s) len=%d", ver, len, buf, len);
break;
case 'S':
if (SIMPLE_BASE64_PESSIMISTIC_DECODE_LEN(sigbuf_len) > sizeof(sig)) {
ERR("Available signature decoding buffer is too short len=%d, need=%d", (int)sizeof(sig), SIMPLE_BASE64_PESSIMISTIC_DECODE_LEN(sigbuf_len));
ver = -3;
break;
}
p = sigbuf+3+ZXLOG_TIME_SIZ+1+mid_len+1;
unbase64_raw(p, sigbuf+sigbuf_len, sig, zx_std_index_64);
SHA1((unsigned char*)buf, len, (unsigned char*)sha1);
ver = memcmp(sig, sha1, 20); /* 0 on success */
if (ver) {
ERR("SHA1 mismatch in receipt %d",ver);
D("sha len=%d input(%.*s)", len, len, buf);
D("sigbuf(%.*s) len=%d sigbuf=%p lim=%p", (int)(sigbuf_len-(p-sigbuf)), p, (int)(sigbuf_len-(p-sigbuf)), p, sigbuf+sigbuf_len);
D("old sha1 %d", hexdmp("old sha1",sig,20,20));
D("new sha1 %d", hexdmp("new sha1",sha1,20,20));
}
break;
case 'P': D("P: no sig to check %d",0); ver = 0; break;
default:
ERR("Unsupported receipt signature algo(%c) sig(%.*s)", sigbuf[0], sigbuf_len, sigbuf);
}
ZX_FREE(cf->ctx, buf);
return ver;
}
int zxbus_persist_flag = 1;
/*() Attempt to persist a message.
* Persisting involves synchronous write and an atomic filesystem rename
* operation, ala Maildir. The persisted message is a file that contains
* the entire STOMP 1.1 PDU including headers and body. Filename is the sha1
* hash of the contents of the file.
*
* return:: 0 on failure, nonzero len of c_path on success.
* See also:: persist feature in zxbus_listen_msg() */
/* Called by: zxbus_persist */
int zxbus_persist_msg(zxid_conf* cf, int c_path_len, char* c_path, int dest_len, const char* dest, int data_len, const char* data)
{
int len;
const char* p;
char t_path[ZXID_MAX_BUF]; /* temp path before atomic rename */
if (dest_len < 1)
( run in 0.628 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )