示例#1
0
文件: pdkim.c 项目: puleglot/exim
static pdkim_signature *
pdkim_parse_sig_header(pdkim_ctx *ctx, char *raw_hdr)
{
pdkim_signature *sig ;
char *p, *q;
pdkim_str *cur_tag = NULL;
pdkim_str *cur_val = NULL;
BOOL past_hname = FALSE;
BOOL in_b_val = FALSE;
int where = PDKIM_HDR_LIMBO;
int i;
int old_pool = store_pool;

/* There is a store-reset between header & body reception
so cannot use the main pool. Any allocs done by Exim
memory-handling must use the perm pool. */

store_pool = POOL_PERM;

if (!(sig = malloc(sizeof(pdkim_signature)))) return NULL;
memset(sig, 0, sizeof(pdkim_signature));
sig->bodylength = -1;

if (!(sig->rawsig_no_b_val = malloc(strlen(raw_hdr)+1)))
  {
  free(sig);
  return NULL;
  }

q = sig->rawsig_no_b_val;

for (p = raw_hdr; ; p++)
  {
  char c = *p;

  /* Ignore FWS */
  if (c == '\r' || c == '\n')
    goto NEXT_CHAR;

  /* Fast-forward through header name */
  if (!past_hname)
    {
    if (c == ':') past_hname = TRUE;
    goto NEXT_CHAR;
    }

  if (where == PDKIM_HDR_LIMBO)
    {
    /* In limbo, just wait for a tag-char to appear */
    if (!(c >= 'a' && c <= 'z'))
      goto NEXT_CHAR;

    where = PDKIM_HDR_TAG;
    }

  if (where == PDKIM_HDR_TAG)
    {
    if (!cur_tag)
      cur_tag = pdkim_strnew(NULL);

    if (c >= 'a' && c <= 'z')
      pdkim_strncat(cur_tag, p, 1);

    if (c == '=')
      {
      if (strcmp(cur_tag->str, "b") == 0)
        {
	*q = '='; q++;
	in_b_val = TRUE;
	}
      where = PDKIM_HDR_VALUE;
      goto NEXT_CHAR;
      }
    }

  if (where == PDKIM_HDR_VALUE)
    {
    if (!cur_val)
      cur_val = pdkim_strnew(NULL);

    if (c == '\r' || c == '\n' || c == ' ' || c == '\t')
      goto NEXT_CHAR;

    if (c == ';' || c == '\0')
      {
      if (cur_tag->len > 0)
        {
	pdkim_strtrim(cur_val);

	DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag->str, cur_val->str);

	switch (cur_tag->str[0])
	  {
	  case 'b':
	    if (cur_tag->str[1] == 'h')
	      pdkim_decode_base64(US cur_val->str, &sig->bodyhash);
	    else
	      pdkim_decode_base64(US cur_val->str, &sig->sigdata);
	    break;
	  case 'v':
	      /* We only support version 1, and that is currently the
		 only version there is. */
	    if (strcmp(cur_val->str, PDKIM_SIGNATURE_VERSION) == 0)
	      sig->version = 1;
	    break;
	  case 'a':
	    for (i = 0; pdkim_algos[i]; i++)
	      if (strcmp(cur_val->str, pdkim_algos[i]) == 0)
	        {
		sig->algo = i;
		break;
		}
	    break;
	  case 'c':
	    for (i = 0; pdkim_combined_canons[i].str; i++)
	      if (strcmp(cur_val->str, pdkim_combined_canons[i].str) == 0)
	        {
		sig->canon_headers = pdkim_combined_canons[i].canon_headers;
		sig->canon_body    = pdkim_combined_canons[i].canon_body;
		break;
		}
	    break;
	  case 'q':
	    for (i = 0; pdkim_querymethods[i]; i++)
	      if (strcmp(cur_val->str, pdkim_querymethods[i]) == 0)
	        {
		sig->querymethod = i;
		break;
		}
	    break;
	  case 's':
	    sig->selector = strdup(cur_val->str); break;
	  case 'd':
	    sig->domain = strdup(cur_val->str); break;
	  case 'i':
	    sig->identity = pdkim_decode_qp(cur_val->str); break;
	  case 't':
	    sig->created = strtoul(cur_val->str, NULL, 10); break;
	  case 'x':
	    sig->expires = strtoul(cur_val->str, NULL, 10); break;
	  case 'l':
	    sig->bodylength = strtol(cur_val->str, NULL, 10); break;
	  case 'h':
	    sig->headernames = string_copy(cur_val->str); break;
	  case 'z':
	    sig->copiedheaders = pdkim_decode_qp(cur_val->str); break;
	  default:
	    DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
	    break;
	  }
	}
      pdkim_strclear(cur_tag);
      pdkim_strclear(cur_val);
      in_b_val = FALSE;
      where = PDKIM_HDR_LIMBO;
      }
    else
      pdkim_strncat(cur_val, p, 1);
    }

NEXT_CHAR:
  if (c == '\0')
    break;

  if (!in_b_val)
    *q++ = c;
  }

store_pool = old_pool;

/* Make sure the most important bits are there. */
if (!(sig->domain      && (*(sig->domain)      != '\0') &&
      sig->selector    && (*(sig->selector)    != '\0') &&
      sig->headernames && (*(sig->headernames) != '\0') &&
      sig->version))
  {
  pdkim_free_sig(sig);
  return NULL;
  }

*q = '\0';
/* Chomp raw header. The final newline must not be added to the signature. */
q--;
while (q > sig->rawsig_no_b_val  && (*q == '\r' || *q == '\n'))
  *q = '\0'; q--;	/*XXX questionable code layout; possible bug */

DEBUG(D_acl)
  {
  debug_printf(
	  "PDKIM >> Raw signature w/o b= tag value >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
  pdkim_quoteprint(sig->rawsig_no_b_val, strlen(sig->rawsig_no_b_val));
  debug_printf(
	  "PDKIM >> Sig size: %4d bits\n", sig->sigdata.len*8);
  debug_printf(
	  "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
  }

exim_sha_init(&sig->body_hash, sig->algo == PDKIM_ALGO_RSA_SHA1);
return sig;
}
示例#2
0
文件: pdkim.c 项目: puleglot/exim
static int
pdkim_update_bodyhash(pdkim_ctx *ctx, const char *data, int len)
{
pdkim_signature *sig = ctx->sig;
/* Cache relaxed version of data */
char *relaxed_data = NULL;
int   relaxed_len  = 0;

/* Traverse all signatures, updating their hashes. */
while (sig)
  {
  /* Defaults to simple canon (no further treatment necessary) */
  const char *canon_data = data;
  int         canon_len = len;

  if (sig->canon_body == PDKIM_CANON_RELAXED)
    {
    /* Relax the line if not done already */
    if (!relaxed_data)
      {
      BOOL seen_wsp = FALSE;
      const char *p;
      int q = 0;

      if (!(relaxed_data = malloc(len+1)))
	return PDKIM_ERR_OOM;

      for (p = data; *p; p++)
        {
	char c = *p;
	if (c == '\r')
	  {
	  if (q > 0 && relaxed_data[q-1] == ' ')
	    q--;
	  }
	else if (c == '\t' || c == ' ')
	  {
	  c = ' '; /* Turns WSP into SP */
	  if (seen_wsp)
	    continue;
	  seen_wsp = TRUE;
	  }
	else
	  seen_wsp = FALSE;
	relaxed_data[q++] = c;
	}
      relaxed_data[q] = '\0';
      relaxed_len = q;
      }
    canon_data = relaxed_data;
    canon_len  = relaxed_len;
    }

  /* Make sure we don't exceed the to-be-signed body length */
  if (  sig->bodylength >= 0
     && sig->signed_body_bytes + (unsigned long)canon_len > sig->bodylength
     )
    canon_len = sig->bodylength - sig->signed_body_bytes;

  if (canon_len > 0)
    {
    exim_sha_update(&sig->body_hash, canon_data, canon_len);
    sig->signed_body_bytes += canon_len;
    DEBUG(D_acl) pdkim_quoteprint(canon_data, canon_len);
    }

  sig = sig->next;
  }

if (relaxed_data) free(relaxed_data);
return PDKIM_OK;
}
示例#3
0
文件: pdkim.c 项目: ytrezq/exim
static pdkim_signature *
pdkim_parse_sig_header(pdkim_ctx *ctx, uschar * raw_hdr)
{
pdkim_signature *sig ;
uschar *p, *q;
uschar * cur_tag = NULL; int ts = 0, tl = 0;
uschar * cur_val = NULL; int vs = 0, vl = 0;
BOOL past_hname = FALSE;
BOOL in_b_val = FALSE;
int where = PDKIM_HDR_LIMBO;
int i;

sig = store_get(sizeof(pdkim_signature));
memset(sig, 0, sizeof(pdkim_signature));
sig->bodylength = -1;

q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1);

for (p = raw_hdr; ; p++)
  {
  char c = *p;

  /* Ignore FWS */
  if (c == '\r' || c == '\n')
    goto NEXT_CHAR;

  /* Fast-forward through header name */
  if (!past_hname)
    {
    if (c == ':') past_hname = TRUE;
    goto NEXT_CHAR;
    }

  if (where == PDKIM_HDR_LIMBO)
    {
    /* In limbo, just wait for a tag-char to appear */
    if (!(c >= 'a' && c <= 'z'))
      goto NEXT_CHAR;

    where = PDKIM_HDR_TAG;
    }

  if (where == PDKIM_HDR_TAG)
    {
    if (c >= 'a' && c <= 'z')
      cur_tag = string_catn(cur_tag, &ts, &tl, p, 1);

    if (c == '=')
      {
      cur_tag[tl] = '\0';
      if (Ustrcmp(cur_tag, "b") == 0)
        {
	*q++ = '=';
	in_b_val = TRUE;
	}
      where = PDKIM_HDR_VALUE;
      goto NEXT_CHAR;
      }
    }

  if (where == PDKIM_HDR_VALUE)
    {
    if (c == '\r' || c == '\n' || c == ' ' || c == '\t')
      goto NEXT_CHAR;

    if (c == ';' || c == '\0')
      {
      if (tl && vl)
        {
	cur_val[vl] = '\0';
	pdkim_strtrim(cur_val);

	DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag, cur_val);

	switch (*cur_tag)
	  {
	  case 'b':
	    if (cur_tag[1] == 'h')
	      pdkim_decode_base64(cur_val, &sig->bodyhash);
	    else
	      pdkim_decode_base64(cur_val, &sig->sigdata);
	    break;
	  case 'v':
	      /* We only support version 1, and that is currently the
		 only version there is. */
	    if (Ustrcmp(cur_val, PDKIM_SIGNATURE_VERSION) == 0)
	      sig->version = 1;
	    break;
	  case 'a':
	    for (i = 0; pdkim_algos[i]; i++)
	      if (Ustrcmp(cur_val, pdkim_algos[i]) == 0)
	        {
		sig->algo = i;
		break;
		}
	    break;
	  case 'c':
	    for (i = 0; pdkim_combined_canons[i].str; i++)
	      if (Ustrcmp(cur_val, pdkim_combined_canons[i].str) == 0)
	        {
		sig->canon_headers = pdkim_combined_canons[i].canon_headers;
		sig->canon_body    = pdkim_combined_canons[i].canon_body;
		break;
		}
	    break;
	  case 'q':
	    for (i = 0; pdkim_querymethods[i]; i++)
	      if (Ustrcmp(cur_val, pdkim_querymethods[i]) == 0)
	        {
		sig->querymethod = i;
		break;
		}
	    break;
	  case 's':
	    sig->selector = string_copy(cur_val); break;
	  case 'd':
	    sig->domain = string_copy(cur_val); break;
	  case 'i':
	    sig->identity = pdkim_decode_qp(cur_val); break;
	  case 't':
	    sig->created = strtoul(CS cur_val, NULL, 10); break;
	  case 'x':
	    sig->expires = strtoul(CS cur_val, NULL, 10); break;
	  case 'l':
	    sig->bodylength = strtol(CS cur_val, NULL, 10); break;
	  case 'h':
	    sig->headernames = string_copy(cur_val); break;
	  case 'z':
	    sig->copiedheaders = pdkim_decode_qp(cur_val); break;
	  default:
	    DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
	    break;
	  }
	}
      tl = 0;
      vl = 0;
      in_b_val = FALSE;
      where = PDKIM_HDR_LIMBO;
      }
    else
      cur_val = string_catn(cur_val, &vs, &vl, p, 1);
    }

NEXT_CHAR:
  if (c == '\0')
    break;

  if (!in_b_val)
    *q++ = c;
  }

/* Make sure the most important bits are there. */
if (!sig->version)
  return NULL;

*q = '\0';
/* Chomp raw header. The final newline must not be added to the signature. */
while (--q > sig->rawsig_no_b_val  && (*q == '\r' || *q == '\n'))
  *q = '\0';

DEBUG(D_acl)
  {
  debug_printf(
	  "PDKIM >> Raw signature w/o b= tag value >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
  pdkim_quoteprint(US sig->rawsig_no_b_val, Ustrlen(sig->rawsig_no_b_val));
  debug_printf(
	  "PDKIM >> Sig size: %4u bits\n", (unsigned) sig->sigdata.len*8);
  debug_printf(
	  "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
  }

exim_sha_init(&sig->body_hash, sig->algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256);
return sig;
}