zxid

 view release on metacpan or  search on metacpan

zxlog.c  view on Meta::CPAN

  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;

zxlog.c  view on Meta::CPAN


  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 )