예제 #1
0
static gboolean
read_public_dsa (EggBuffer *req, gsize *offset, gcry_sexp_t *sexp)
{
	gcry_mpi_t p, q, g, y;
	int gcry;

	if (!read_mpi (req, offset, &p) ||
	    !read_mpi (req, offset, &q) ||
	    !read_mpi (req, offset, &g) ||
	    !read_mpi (req, offset, &y))
		return FALSE;

	gcry = gcry_sexp_build (sexp, NULL, SEXP_PUBLIC_DSA, p, q, g, y);
	if (gcry) {
		g_warning ("couldn't parse incoming public DSA key: %s", gcry_strerror (gcry));
		return FALSE;
	}

	gcry_mpi_release (p);
	gcry_mpi_release (q);
	gcry_mpi_release (g);
	gcry_mpi_release (y);

	return TRUE;
}
예제 #2
0
static gboolean
parse_v4_algo_bits (const guchar **at,
                    const guchar *end,
                    guint8 algo,
                    guint16 *bits)
{
	switch (algo) {
	case GCR_OPENPGP_ALGO_RSA:
	case GCR_OPENPGP_ALGO_RSA_E:
	case GCR_OPENPGP_ALGO_RSA_S:
		if (!read_mpi (at, end, bits, NULL) ||
		    !read_mpi (at, end, NULL, NULL))
			return FALSE;
		return TRUE;
	case GCR_OPENPGP_ALGO_DSA:
		if (!read_mpi (at, end, bits, NULL) ||
		    !read_mpi (at, end, NULL, NULL) ||
		    !read_mpi (at, end, NULL, NULL) ||
		    !read_mpi (at, end, NULL, NULL))
			return FALSE;
		return TRUE;
	case GCR_OPENPGP_ALGO_ELG_E:
		if (!read_mpi (at, end, bits, NULL) ||
		    !read_mpi (at, end, NULL, NULL) ||
		    !read_mpi (at, end, NULL, NULL))
			return FALSE;
		return TRUE;
	default: /* Unsupported key */
		return FALSE;
	}
}
예제 #3
0
파일: parse.c 프로젝트: Ri0n/libotr
/* Parse a Key Exchange Message into a newly-allocated KeyExchMsg structure */
KeyExchMsg parse_keyexch(const char *msg)
{
    KeyExchMsg kem = NULL;
    size_t lenp;
    unsigned char *raw = decode(msg, &lenp);
    unsigned char *bufp = raw;
    if (!raw) goto inv;

    kem = calloc(1, sizeof(struct s_KeyExchMsg));
    if (!kem) {
	free(raw);
	goto inv;
    }

    kem->raw = raw;
    kem->sigstart = bufp;

    require_len(3);
    if (memcmp(bufp, "\x00\x01\x0a", 3)) goto inv;
    bufp += 3; lenp -= 3;

    require_len(1);
    kem->reply = *bufp;
    bufp += 1; lenp -= 1;

    read_mpi(kem->p);
    read_mpi(kem->q);
    read_mpi(kem->g);
    read_mpi(kem->e);

    read_int(kem->keyid);

    read_mpi(kem->y);

    kem->sigend = bufp;

    require_len(40);
    gcry_mpi_scan(&kem->r, GCRYMPI_FMT_USG, bufp, 20, NULL);
    gcry_mpi_scan(&kem->s, GCRYMPI_FMT_USG, bufp+20, 20, NULL);
    bufp += 40; lenp -= 40;

    if (lenp != 0) goto inv;

    return kem;
inv:
    free_keyexch(kem);
    return NULL;
}
예제 #4
0
static cdk_error_t
read_pubkey_enc (cdk_stream_t inp, size_t pktlen, cdk_pkt_pubkey_enc_t pke)
{
  size_t i, nenc;

  if (!inp || !pke)
    return CDK_Inv_Value;

  if (DEBUG_PKT)
    _cdk_log_debug ("read_pubkey_enc: %d octets\n", pktlen);

  if (pktlen < 12)
    return CDK_Inv_Packet;
  pke->version = cdk_stream_getc (inp);
  if (pke->version < 2 || pke->version > 3)
    return CDK_Inv_Packet;
  pke->keyid[0] = read_32 (inp);
  pke->keyid[1] = read_32 (inp);
  if (!pke->keyid[0] && !pke->keyid[1])
    pke->throw_keyid = 1;	/* RFC2440 "speculative" keyID */
  pke->pubkey_algo = _pgp_pub_algo_to_cdk (cdk_stream_getc (inp));
  nenc = cdk_pk_get_nenc (pke->pubkey_algo);
  if (!nenc)
    return CDK_Inv_Algo;
  for (i = 0; i < nenc; i++)
    {
      cdk_error_t rc = read_mpi (inp, &pke->mpi[i], 0);
      if (rc)
	return rc;
    }

  return 0;
}
예제 #5
0
static gboolean
parse_v3_rsa_bits_and_keyid (const guchar **at,
                             const guchar *end,
                             guint16 *bits,
                             gchar **keyid)
{
	guchar *n;
	gsize bytes;

	g_assert (bits);
	g_assert (keyid);

	/* Read in the modulus */
	if (!read_mpi (at, end, bits, &n))
		return FALSE;

	/* Last 64-bits of modulus are keyid */
	bytes = (*bits + 7) / 8;
	if (bytes < 8) {
		g_free (n);
		return FALSE;
	}

	*keyid = egg_hex_encode_full (n + (bytes - 8), 8, TRUE, 0, 0);
	return TRUE;
}
예제 #6
0
static gboolean
skip_signature_mpis (const guchar **at,
                     const guchar *end,
                     guint8 algo)
{
	switch (algo) {

	/* RSA signature value */
	case GCR_OPENPGP_ALGO_RSA:
		return read_mpi (at, end, NULL, NULL);

	/* DSA values r and s */
	case GCR_OPENPGP_ALGO_DSA:
		return read_mpi (at, end, NULL, NULL) &&
		       read_mpi (at, end, NULL, NULL);
	default:
		return FALSE;
	}
}
예제 #7
0
static gboolean
read_public_rsa (EggBuffer *req, gsize *offset, gcry_sexp_t *sexp)
{
	gcry_mpi_t n, e;
	int gcry;

	if (!read_mpi (req, offset, &e) ||
	    !read_mpi (req, offset, &n))
		return FALSE;

	gcry = gcry_sexp_build (sexp, NULL, SEXP_PUBLIC_RSA, n, e);
	if (gcry) {
		g_warning ("couldn't parse incoming public RSA key: %s", gcry_strerror (gcry));
		return FALSE;
	}

	gcry_mpi_release (n);
	gcry_mpi_release (e);

	return TRUE;
}
예제 #8
0
static cdk_error_t
read_public_key (cdk_stream_t inp, size_t pktlen, cdk_pkt_pubkey_t pk)
{
  size_t i, ndays, npkey;

  if (!inp || !pk)
    return CDK_Inv_Value;

  if (DEBUG_PKT)
    _cdk_log_debug ("read_public_key: %d octets\n", pktlen);

  pk->is_invalid = 1;		/* default to detect missing self signatures */
  pk->is_revoked = 0;
  pk->has_expired = 0;

  pk->version = cdk_stream_getc (inp);
  if (pk->version < 2 || pk->version > 4)
    return CDK_Inv_Packet_Ver;
  pk->timestamp = read_32 (inp);
  if (pk->version < 4)
    {
      ndays = read_16 (inp);
      if (ndays)
	pk->expiredate = pk->timestamp + ndays * 86400L;
    }

  pk->pubkey_algo = _pgp_pub_algo_to_cdk (cdk_stream_getc (inp));
  npkey = cdk_pk_get_npkey (pk->pubkey_algo);
  if (!npkey)
    {
      gnutls_assert ();
      _cdk_log_debug ("invalid public key algorithm %d\n", pk->pubkey_algo);
      return CDK_Inv_Algo;
    }
  for (i = 0; i < npkey; i++)
    {
      cdk_error_t rc = read_mpi (inp, &pk->mpi[i], 0);
      if (rc)
	return rc;
    }

  /* This value is just for the first run and will be
     replaced with the actual key flags from the self signature. */
  pk->pubkey_usage = 0;
  return 0;
}
예제 #9
0
파일: parse.c 프로젝트: Ri0n/libotr
/* Parse a D-H Key Message into a newly-allocated KeyMsg structure */
KeyMsg parse_key(const char *msg)
{
    KeyMsg kmsg = NULL;
    size_t lenp;
    unsigned char *raw = decode(msg, &lenp);
    unsigned char *bufp = raw;
    if (!raw) goto inv;

    kmsg = calloc(1, sizeof(struct s_KeyMsg));
    if (!kmsg) {
	free(raw);
	goto inv;
    }

    kmsg->raw = raw;

    require_len(3);

    kmsg->version = bufp[1];

    if (!memcmp(bufp, "\x00\x03\x0a", 3)) {
	bufp += 3; lenp -= 3;
	read_int(kmsg->sender_instance);
	read_int(kmsg->receiver_instance);
    } else if (!memcmp(bufp, "\x00\x02\x0a", 3)) {
	bufp += 3; lenp -= 3;
	kmsg->sender_instance = 0;
	kmsg->receiver_instance = 0;
    } else goto inv;

    read_mpi(kmsg->y);

    if (lenp != 0) goto inv;

    return kmsg;
inv:
    free_key(kmsg);
    return NULL;
}
예제 #10
0
파일: proto.c 프로젝트: Xara/Luna-Viewer
/* Accept an OTR Data Message in datamsg.  Decrypt it and put the
 * plaintext into *plaintextp, and any TLVs into tlvsp.  Put any
 * received flags into *flagsp (if non-NULL). */
gcry_error_t otrl_proto_accept_data(char **plaintextp, OtrlTLV **tlvsp,
	ConnContext *context, const char *datamsg, unsigned char *flagsp)
{
    char *otrtag, *endtag;
    gcry_error_t err;
    unsigned char *rawmsg = NULL;
    size_t msglen, rawlen, lenp;
    unsigned char *macstart, *macend;
    unsigned char *bufp;
    unsigned int sender_keyid, recipient_keyid;
    gcry_mpi_t sender_next_y = NULL;
    unsigned char ctr[8];
    unsigned int datalen, reveallen;
    unsigned char *data = NULL;
    unsigned char *nul = NULL;
    unsigned char givenmac[20];
    DH_sesskeys *sess;
    unsigned char version;

    *plaintextp = NULL;
    *tlvsp = NULL;
    if (flagsp) *flagsp = 0;
    otrtag = strstr(datamsg, "?OTR:");
    if (!otrtag) {
	goto invval;
    }
    endtag = strchr(otrtag, '.');
    if (endtag) {
	msglen = endtag-otrtag;
    } else {
	msglen = strlen(otrtag);
    }

    /* Base64-decode the message */
    rawlen = ((msglen-5) / 4) * 3;   /* maximum possible */
    rawmsg = malloc(rawlen);
    if (!rawmsg && rawlen > 0) {
	err = gcry_error(GPG_ERR_ENOMEM);
	goto err;
    }
    rawlen = otrl_base64_decode(rawmsg, otrtag+5, msglen-5);  /* actual size */

    bufp = rawmsg;
    lenp = rawlen;

    macstart = bufp;
    require_len(3);
    if (memcmp(bufp, "\x00\x01\x03", 3) && memcmp(bufp, "\x00\x02\x03", 3)) {
	/* Invalid header */
	goto invval;
    }
    version = bufp[1];
    bufp += 3; lenp -= 3;

    if (version == 2) {
	require_len(1);
	if (flagsp) *flagsp = bufp[0];
	bufp += 1; lenp -= 1;
    }
    read_int(sender_keyid);
    read_int(recipient_keyid);
    read_mpi(sender_next_y);
    require_len(8);
    memmove(ctr, bufp, 8);
    bufp += 8; lenp -= 8;
    read_int(datalen);
    require_len(datalen);
    data = malloc(datalen+1);
    if (!data) {
	err = gcry_error(GPG_ERR_ENOMEM);
	goto err;
    }
    memmove(data, bufp, datalen);
    data[datalen] = '\0';
    bufp += datalen; lenp -= datalen;
    macend = bufp;
    require_len(20);
    memmove(givenmac, bufp, 20);
    bufp += 20; lenp -= 20;
    read_int(reveallen);
    require_len(reveallen);
    /* Just skip over the revealed MAC keys, which we don't need.  They
     * were published for deniability of transcripts. */
    bufp += reveallen; lenp -= reveallen;

    /* That should be everything */
    if (lenp != 0) goto invval;

    /* We don't take any action on this message (especially rotating
     * keys) until we've verified the MAC on this message.  To that end,
     * we need to know which keys this message is claiming to use. */
    if (context->their_keyid == 0 ||
	    (sender_keyid != context->their_keyid &&
		sender_keyid != context->their_keyid - 1) ||
	    (recipient_keyid != context->our_keyid &&
	     recipient_keyid != context->our_keyid - 1) ||
	    sender_keyid == 0 || recipient_keyid == 0) {
	goto conflict;
    }

    if (sender_keyid == context->their_keyid - 1 &&
	    context->their_old_y == NULL) {
	goto conflict;
    }

    /* These are the session keys this message is claiming to use. */
    sess = &(context->sesskeys
	    [context->our_keyid - recipient_keyid]
	    [context->their_keyid - sender_keyid]);

    gcry_md_reset(sess->rcvmac);
    gcry_md_write(sess->rcvmac, macstart, macend-macstart);
    if (memcmp(givenmac, gcry_md_read(sess->rcvmac, GCRY_MD_SHA1), 20)) {
	/* The MACs didn't match! */
	goto conflict;
    }
    sess->rcvmacused = 1;

    /* Check to see that the counter is increasing; i.e. that this isn't
     * a replay. */
    if (otrl_dh_cmpctr(ctr, sess->rcvctr) <= 0) {
	goto conflict;
    }

    /* Decrypt the message */
    memmove(sess->rcvctr, ctr, 8);
    err = gcry_cipher_reset(sess->rcvenc);
    if (err) goto err;
    err = gcry_cipher_setctr(sess->rcvenc, sess->rcvctr, 16);
    if (err) goto err;
    err = gcry_cipher_decrypt(sess->rcvenc, data, datalen, NULL, 0);
    if (err) goto err;

    /* See if either set of keys needs rotating */

    if (recipient_keyid == context->our_keyid) {
	/* They're using our most recent key, so generate a new one */
	err = rotate_dh_keys(context);
	if (err) goto err;
    }

    if (sender_keyid == context->their_keyid) {
	/* They've sent us a new public key */
	err = rotate_y_keys(context, sender_next_y);
	if (err) goto err;
    }

    gcry_mpi_release(sender_next_y);
    *plaintextp = (char *)data;

    /* See if there are TLVs */
    nul = data;
    while (nul < data+datalen && *nul) ++nul;
    /* If we stopped before the end, skip the NUL we stopped at */
    if (nul < data+datalen) ++nul;
    *tlvsp = otrl_tlv_parse(nul, (data+datalen)-nul);

    free(rawmsg);
    return gcry_error(GPG_ERR_NO_ERROR);

invval:
    err = gcry_error(GPG_ERR_INV_VALUE);
    goto err;
conflict:
    err = gcry_error(GPG_ERR_CONFLICT);
    goto err;
err:
    gcry_mpi_release(sender_next_y);
    free(data);
    free(rawmsg);
    return err;
}
예제 #11
0
static cdk_error_t
read_signature (cdk_stream_t inp, size_t pktlen, cdk_pkt_signature_t sig)
{
  size_t nbytes;
  size_t i, size, nsig;
  cdk_error_t rc;

  if (!inp || !sig)
    return CDK_Inv_Value;

  if (DEBUG_PKT)
    _cdk_log_debug ("read_signature: %d octets\n", pktlen);

  if (pktlen < 16)
    return CDK_Inv_Packet;
  sig->version = cdk_stream_getc (inp);
  if (sig->version < 2 || sig->version > 4)
    return CDK_Inv_Packet_Ver;

  sig->flags.exportable = 1;
  sig->flags.revocable = 1;

  if (sig->version < 4)
    {
      if (cdk_stream_getc (inp) != 5)
	return CDK_Inv_Packet;
      sig->sig_class = cdk_stream_getc (inp);
      sig->timestamp = read_32 (inp);
      sig->keyid[0] = read_32 (inp);
      sig->keyid[1] = read_32 (inp);
      sig->pubkey_algo = _pgp_pub_algo_to_cdk (cdk_stream_getc (inp));
      sig->digest_algo = _pgp_hash_algo_to_gnutls (cdk_stream_getc (inp));
      sig->digest_start[0] = cdk_stream_getc (inp);
      sig->digest_start[1] = cdk_stream_getc (inp);
      nsig = cdk_pk_get_nsig (sig->pubkey_algo);
      if (!nsig)
	return CDK_Inv_Algo;
      for (i = 0; i < nsig; i++)
	{
	  rc = read_mpi (inp, &sig->mpi[i], 0);
	  if (rc)
	    return rc;
	}
    }
  else
    {
      sig->sig_class = cdk_stream_getc (inp);
      sig->pubkey_algo = _pgp_pub_algo_to_cdk (cdk_stream_getc (inp));
      sig->digest_algo = _pgp_hash_algo_to_gnutls (cdk_stream_getc (inp));
      sig->hashed_size = read_16 (inp);
      size = sig->hashed_size;
      sig->hashed = NULL;
      while (size > 0)
	{
	  rc = read_subpkt (inp, &sig->hashed, &nbytes);
	  if (rc)
	    return rc;
	  size -= nbytes;
	}
      sig->unhashed_size = read_16 (inp);
      size = sig->unhashed_size;
      sig->unhashed = NULL;
      while (size > 0)
	{
	  rc = read_subpkt (inp, &sig->unhashed, &nbytes);
	  if (rc)
	    return rc;
	  size -= nbytes;
	}

      rc = parse_sig_subpackets (sig);
      if (rc)
	return rc;

      sig->digest_start[0] = cdk_stream_getc (inp);
      sig->digest_start[1] = cdk_stream_getc (inp);
      nsig = cdk_pk_get_nsig (sig->pubkey_algo);
      if (!nsig)
	return CDK_Inv_Algo;
      for (i = 0; i < nsig; i++)
	{
	  rc = read_mpi (inp, &sig->mpi[i], 0);
	  if (rc)
	    return rc;
	}
    }

  return 0;
}
예제 #12
0
static cdk_error_t
read_secret_key (cdk_stream_t inp, size_t pktlen, cdk_pkt_seckey_t sk)
{
  size_t p1, p2, nread;
  int i, nskey;
  int rc;

  if (!inp || !sk || !sk->pk)
    return CDK_Inv_Value;

  if (DEBUG_PKT)
    _cdk_log_debug ("read_secret_key: %d octets\n", pktlen);

  p1 = cdk_stream_tell (inp);
  rc = read_public_key (inp, pktlen, sk->pk);
  if (rc)
    return rc;

  sk->s2k_usage = cdk_stream_getc (inp);
  sk->protect.sha1chk = 0;
  if (sk->s2k_usage == 254 || sk->s2k_usage == 255)
    {
      sk->protect.sha1chk = (sk->s2k_usage == 254);
      sk->protect.algo = _pgp_cipher_to_gnutls (cdk_stream_getc (inp));
      sk->protect.s2k = cdk_calloc (1, sizeof *sk->protect.s2k);
      if (!sk->protect.s2k)
	return CDK_Out_Of_Core;
      rc = read_s2k (inp, sk->protect.s2k);
      if (rc)
	return rc;
      /* refer to --export-secret-subkeys in gpg(1) */
      if (sk->protect.s2k->mode == CDK_S2K_GNU_EXT)
	sk->protect.ivlen = 0;
      else
	{
	  sk->protect.ivlen =
	    _gnutls_cipher_get_block_size (sk->protect.algo);
	  if (!sk->protect.ivlen)
	    return CDK_Inv_Packet;
	  rc = stream_read (inp, sk->protect.iv, sk->protect.ivlen, &nread);
	  if (rc)
	    return rc;
	  if (nread != sk->protect.ivlen)
	    return CDK_Inv_Packet;
	}
    }
  else
    sk->protect.algo = _pgp_cipher_to_gnutls (sk->s2k_usage);
  if (sk->protect.algo == GNUTLS_CIPHER_NULL)
    {
      sk->csum = 0;
      nskey = cdk_pk_get_nskey (sk->pk->pubkey_algo);
      if (!nskey)
	{
	  gnutls_assert ();
	  return CDK_Inv_Algo;
	}
      for (i = 0; i < nskey; i++)
	{
	  rc = read_mpi (inp, &sk->mpi[i], 1);
	  if (rc)
	    return rc;
	}
      sk->csum = read_16 (inp);
      sk->is_protected = 0;
    }
  else if (sk->pk->version < 4)
    {
      /* The length of each multiprecision integer is stored in plaintext. */
      nskey = cdk_pk_get_nskey (sk->pk->pubkey_algo);
      if (!nskey)
	{
	  gnutls_assert ();
	  return CDK_Inv_Algo;
	}
      for (i = 0; i < nskey; i++)
	{
	  rc = read_mpi (inp, &sk->mpi[i], 1);
	  if (rc)
	    return rc;
	}
      sk->csum = read_16 (inp);
      sk->is_protected = 1;
    }
  else
    {
      /* We need to read the rest of the packet because we do not
         have any information how long the encrypted mpi's are */
      p2 = cdk_stream_tell (inp);
      p2 -= p1;
      sk->enclen = pktlen - p2;
      if (sk->enclen < 2)
	return CDK_Inv_Packet;	/* at least 16 bits for the checksum! */
      sk->encdata = cdk_calloc (1, sk->enclen + 1);
      if (!sk->encdata)
	return CDK_Out_Of_Core;
      if (stream_read (inp, sk->encdata, sk->enclen, &nread))
	return CDK_Inv_Packet;
      /* Handle the GNU S2K extensions we know (just gnu-dummy right now): */
      if (sk->protect.s2k->mode == CDK_S2K_GNU_EXT)
	{
	  unsigned char gnumode;
	  if ((sk->enclen < strlen ("GNU") + 1) ||
	      (0 != memcmp ("GNU", sk->encdata, strlen ("GNU"))))
	    return CDK_Inv_Packet;
	  gnumode = sk->encdata[strlen ("GNU")];
	  /* we only handle gnu-dummy (mode 1).
	     mode 2 should refer to external smart cards.
	   */
	  if (gnumode != 1)
	    return CDK_Inv_Packet;
	  /* gnu-dummy should have no more data */
	  if (sk->enclen != strlen ("GNU") + 1)
	    return CDK_Inv_Packet;
	}
      nskey = cdk_pk_get_nskey (sk->pk->pubkey_algo);
      if (!nskey)
	{
	  gnutls_assert ();
	  return CDK_Inv_Algo;
	}
      /* We mark each MPI entry with NULL to indicate a protected key. */
      for (i = 0; i < nskey; i++)
	sk->mpi[i] = NULL;
      sk->is_protected = 1;
    }

  sk->is_primary = 1;
  _cdk_copy_pk_to_sk (sk->pk, sk);
  return 0;
}
예제 #13
0
파일: parse.c 프로젝트: Ri0n/libotr
/* Parse a Data Message into a newly-allocated DataMsg structure */
DataMsg parse_datamsg(const char *msg)
{
    DataMsg datam = NULL;
    size_t lenp;
    unsigned char *raw = decode(msg, &lenp);
    unsigned char *bufp = raw;
    unsigned char version;
    if (!raw) goto inv;

    datam = calloc(1, sizeof(struct s_DataMsg));
    if (!datam) {
	free(raw);
	goto inv;
    }

    datam->raw = raw;
    datam->rawlen = lenp;
    datam->macstart = bufp;

    require_len(3);
    if (memcmp(bufp, "\x00\x01\x03", 3) && memcmp(bufp, "\x00\x03\x03", 3) &&
	memcmp(bufp, "\x00\x02\x03", 3)) goto inv;

    version = bufp[1];

    datam->sender_instance = 0;
    datam->receiver_instance = 0;
    datam->version = version;
    datam->flags = -1;
    bufp += 3; lenp -= 3;

    if (version == 3) {
	read_int(datam->sender_instance);
	read_int(datam->receiver_instance);
    }

    if (version == 2 || version == 3) {
	require_len(1);
	datam->flags = bufp[0];
	bufp += 1; lenp -= 1;
    }

    read_int(datam->sender_keyid);
    read_int(datam->rcpt_keyid);
    read_mpi(datam->y);
    read_raw(datam->ctr, 8);
    read_int(datam->encmsglen);
    datam->encmsg = malloc(datam->encmsglen);
    if (!datam->encmsg && datam->encmsglen > 0) goto inv;
    read_raw(datam->encmsg, datam->encmsglen);
    datam->macend = bufp;
    read_raw(datam->mac, 20);
    read_int(datam->mackeyslen);
    datam->mackeys = malloc(datam->mackeyslen);

    if (!datam->mackeys && datam->mackeyslen > 0) goto inv;

    read_raw(datam->mackeys, datam->mackeyslen);
    if (lenp != 0) goto inv;

    return datam;
inv:
    free_datamsg(datam);
    return NULL;
}