Back to index

opendkim  2.6.6
dkim.c
Go to the documentation of this file.
00001 /*
00002 **  Copyright (c) 2005-2009 Sendmail, Inc. and its suppliers.
00003 **    All rights reserved.
00004 **
00005 **  Copyright (c) 2009-2012, The OpenDKIM Project.  All rights reserved.
00006 */
00007 
00008 #ifndef lint
00009 static char dkim_c_id[] = "@(#)$Id: dkim.c,v 1.70.2.1 2010/10/27 21:43:08 cm-msk Exp $";
00010 #endif /* !lint */
00011 
00012 #include "build-config.h"
00013 
00014 /* for Solaris */
00015 #ifndef _REENTRANT
00016 # define _REENTRANT
00017 #endif /* ! REENTRANT */
00018 
00019 /* system includes */
00020 #include <sys/param.h>
00021 #include <sys/types.h>
00022 #include <netinet/in.h>
00023 #include <arpa/inet.h>
00024 #include <arpa/nameser.h>
00025 #ifdef HAVE_STDBOOL_H
00026 # include <stdbool.h>
00027 #endif /* HAVE_STDBOOL_H */
00028 #include <netdb.h>
00029 #include <stdlib.h>
00030 #include <ctype.h>
00031 #include <errno.h>
00032 #include <assert.h>
00033 #include <string.h>
00034 #include <limits.h>
00035 #include <unistd.h>
00036 #ifndef USE_GNUTLS
00037 # include <pthread.h>
00038 #endif /* ! USE_GNUTLS */
00039 #include <resolv.h>
00040 #ifdef USE_TRE
00041 # ifdef TRE_PRE_080
00042 #  include <tre/regex.h>
00043 #  define tre_regcomp       regcomp
00044 #  define tre_regexec       regexec
00045 #  define tre_regaexec      regaexec
00046 #  define tre_regfree       regfree
00047 #  define tre_regerror      regerror
00048 # else /* TRE_PRE_080 */
00049 #  include <tre/tre.h>
00050 #  ifndef TRE_USE_SYSTEM_REGEX_H
00051 #   define regcomp   tre_regcomp
00052 #   define regexec   tre_regexec
00053 #   define regfree   tre_regfree
00054 #   define regerror  tre_regerror
00055 #  endif /* TRE_USE_SYSTEM_REGEX_H */
00056 # endif /* TRE_PRE_080 */
00057 #else /* USE_TRE */
00058 # include <regex.h>
00059 #endif /* USE_TRE */
00060 
00061 #ifdef __STDC__
00062 # include <stdarg.h>
00063 #else /* __STDC__ */
00064 # include <varargs.h>
00065 #endif /* _STDC_ */
00066 
00067 #ifdef USE_GNUTLS
00068 /* GnuTLS includes */
00069 # include <gnutls/gnutls.h>
00070 # include <gnutls/crypto.h>
00071 # include <gnutls/abstract.h>
00072 # include <gnutls/x509.h>
00073 #else /* USE_GNUTLS */
00074 /* OpenSSL includes */
00075 # include <openssl/opensslv.h>
00076 # include <openssl/pem.h>
00077 # include <openssl/rsa.h>
00078 # include <openssl/bio.h>
00079 # include <openssl/err.h>
00080 # include <openssl/sha.h>
00081 #endif /* USE_GNUTLS */
00082 
00083 /* libopendkim includes */
00084 #include "dkim-internal.h"
00085 #include "dkim-types.h"
00086 #include "dkim-tables.h"
00087 #include "dkim-keys.h"
00088 #include "dkim-policy.h"
00089 #include "dkim-report.h"
00090 #include "dkim-util.h"
00091 #include "dkim-canon.h"
00092 #include "dkim-dns.h"
00093 #ifdef QUERY_CACHE
00094 # include "dkim-cache.h"
00095 #endif /* QUERY_CACHE */
00096 #include "util.h"
00097 #include "base64.h"
00098 #include "dkim-strl.h"
00099 
00100 /* prototypes */
00101 void dkim_error __P((DKIM *, const char *, ...));
00102 
00103 /* macros */
00104 #define       DKIM_STATE_INIT             0
00105 #define       DKIM_STATE_HEADER    1
00106 #define       DKIM_STATE_EOH1             2
00107 #define       DKIM_STATE_EOH2             3
00108 #define       DKIM_STATE_BODY             4
00109 #define       DKIM_STATE_EOM1             5
00110 #define       DKIM_STATE_EOM2             6
00111 #define       DKIM_STATE_UNUSABLE  99
00112 
00113 #define       DKIM_CHUNKSTATE_INIT 0
00114 #define       DKIM_CHUNKSTATE_HEADER      1
00115 #define       DKIM_CHUNKSTATE_BODY 2
00116 #define       DKIM_CHUNKSTATE_DONE 3
00117 
00118 #define       DKIM_CRLF_UNKNOWN    (-1)
00119 #define       DKIM_CRLF_LF         0
00120 #define       DKIM_CRLF_CRLF              1
00121 
00122 #define       DKIM_PHASH(x)        ((x) - 32)
00123 
00124 #ifdef _FFR_DIFFHEADERS
00125 # define COST_INSERT        1
00126 # define COST_DELETE        1
00127 # define COST_SUBST         2
00128 #endif /* _FFR_DIFFHEADERS */
00129 
00130 #define       BUFRSZ               1024
00131 #define       CRLF                 "\r\n"
00132 #define       SP                   " "
00133 
00134 #define       DEFCLOCKDRIFT        300
00135 #define       DEFTIMEOUT           10
00136 #define       MINSIGLEN            8
00137 
00138 /* local definitions needed for DNS queries */
00139 #define MAXPACKET           8192
00140 #if defined(__RES) && (__RES >= 19940415)
00141 # define RES_UNC_T          char *
00142 #else /* __RES && __RES >= 19940415 */
00143 # define RES_UNC_T          unsigned char *
00144 #endif /* __RES && __RES >= 19940415 */
00145 
00146 #ifndef T_AAAA
00147 # define T_AAAA                    28
00148 #endif /* ! T_AAAA */
00149 
00150 /* need fast strtoul() and strtoull()? */
00151 #ifdef NEED_FAST_STRTOUL
00152 # define strtoul(x,y,z)            dkim_strtoul((x), (y), (z))
00153 # define strtoull(x,y,z)    dkim_strtoull((x), (y), (z))
00154 #endif /* NEED_FAST_STRTOUL */
00155 
00156 #define       CLOBBER(x)    if ((x) != NULL) \
00157                      { \
00158                             dkim_mfree(dkim->dkim_libhandle, dkim->dkim_closure, (x)); \
00159                             (x) = NULL; \
00160                      }
00161 
00162 #define       HCLOBBER(x)   if ((x) != NULL) \
00163                      { \
00164                             free((x)); \
00165                             (x) = NULL; \
00166                      }
00167 
00168 # define DSTRING_CLOBBER(x) if ((x) != NULL) \
00169                      { \
00170                             dkim_dstring_free((x)); \
00171                             (x) = NULL; \
00172                      }
00173 
00174 #ifdef USE_GNUTLS
00175 # define KEY_CLOBBER(x)     if ((x) != NULL) \
00176                      { \
00177                             gnutls_x509_privkey_deinit((x)); \
00178                             (x) = NULL; \
00179                      }
00180 
00181 # define PUBKEY_CLOBBER(x)  if ((x) != NULL) \
00182                      { \
00183                             gnutls_pubkey_deinit((x)); \
00184                             (x) = NULL; \
00185                      }
00186 
00187 # define PRIVKEY_CLOBBER(x) if ((x) != NULL) \
00188                      { \
00189                             gnutls_privkey_deinit((x)); \
00190                             (x) = NULL; \
00191                      }
00192 
00193 #else /* USE_GNUTLS */
00194 # define BIO_CLOBBER(x)     if ((x) != NULL) \
00195                      { \
00196                             BIO_free((x)); \
00197                             (x) = NULL; \
00198                      }
00199 
00200 # define RSA_CLOBBER(x)     if ((x) != NULL) \
00201                      { \
00202                             RSA_free((x)); \
00203                             (x) = NULL; \
00204                      }
00205 
00206 # define EVP_CLOBBER(x)     if ((x) != NULL) \
00207                      { \
00208                             EVP_PKEY_free((x)); \
00209                             (x) = NULL; \
00210                      }
00211 #endif /* ! USE_GNUTLS */
00212 
00213 /* macros */
00214 #define DKIM_ISLWSP(x)  ((x) == 011 || (x) == 013 || (x) == 014 || (x) == 040)
00215 
00216 /* list of headers which may contain the sender */
00217 const u_char *dkim_default_senderhdrs[] =
00218 {
00219        "from",
00220        NULL
00221 };
00222 
00223 /* recommended list of headers to sign, from RFC6376 Section 5.4 */
00224 const u_char *dkim_should_signhdrs[] =
00225 {
00226        "from",
00227        "reply-to",
00228        "subject",
00229        "date",
00230        "to",
00231        "cc",
00232        "resent-date",
00233        "resent-from",
00234        "resent-sender",
00235        "resent-to",
00236        "resent-cc",
00237        "in-reply-to",
00238        "references",
00239        "list-id",
00240        "list-help",
00241        "list-unsubscribe",
00242        "list-subscribe",
00243        "list-post",
00244        "list-owner",
00245        "list-archive",
00246        NULL
00247 };
00248 
00249 /* recommended list of headers not to sign, from RFC6376 Section 5.4 */
00250 const u_char *dkim_should_not_signhdrs[] =
00251 {
00252        "return-path",
00253        "received",
00254        "comments",
00255        "keywords",
00256        NULL
00257 };
00258 
00259 /* required list of headers to sign */
00260 const u_char *required_signhdrs[] =
00261 {
00262        "from",
00263        NULL
00264 };
00265 
00266 /* ========================= PRIVATE SECTION ========================= */
00267 
00268 /*
00269 **  DKIM_SET_FREE -- destroy a DKIM_SET 
00270 **
00271 **  Parameters:
00272 **     dkim -- DKIM context
00273 **     set  -- the set to destroy
00274 **
00275 **  Return value:
00276 **     None
00277 */
00278 
00279 static void
00280 dkim_set_free(DKIM *dkim, DKIM_SET *set)
00281 {
00282        int c;
00283        DKIM_PLIST *plist;
00284        DKIM_PLIST *pnext;
00285 
00286        assert(set != NULL);
00287 
00288        for (c = 0; c < NPRINTABLE; c++)
00289        {
00290               for (plist = set->set_plist[c]; plist != NULL; plist = pnext)
00291               {
00292                      pnext = plist->plist_next;
00293 
00294                      CLOBBER(plist);
00295               }
00296        }
00297 
00298        CLOBBER(set->set_data);
00299        CLOBBER(set);
00300 }
00301 
00302 /*
00303 **  DKIM_SET_FIRST -- return first set in a context
00304 **
00305 **  Parameters:
00306 **     dkim -- DKIM context
00307 **     type -- type to find, or DKIM_SETTYPE_ANY
00308 **
00309 **  Return value:
00310 **     Pointer to the first DKIM_SET in the context, or NULL if none.
00311 */
00312 
00313 static DKIM_SET *
00314 dkim_set_first(DKIM *dkim, dkim_set_t type)
00315 {
00316        DKIM_SET *set;
00317 
00318        assert(dkim != NULL);
00319 
00320        if (type == DKIM_SETTYPE_ANY)
00321               return dkim->dkim_sethead;
00322 
00323        for (set = dkim->dkim_sethead; set != NULL; set = set->set_next)
00324        {
00325               if (set->set_type == type)
00326                      return set;
00327        }
00328 
00329        return NULL;
00330 }
00331 
00332 /*
00333 **  DKIM_SET_NEXT -- return next set in a context
00334 **
00335 **  Parameters:
00336 **     set -- last set reported (i.e. starting point for this search)
00337 **     type -- type to find, or DKIM_SETTYPE_ANY
00338 **
00339 **  Return value:
00340 **     Pointer to the next DKIM_SET in the context, or NULL if none.
00341 */
00342 
00343 static DKIM_SET *
00344 dkim_set_next(DKIM_SET *cur, dkim_set_t type)
00345 {
00346        DKIM_SET *set;
00347 
00348        assert(cur != NULL);
00349 
00350        if (type == DKIM_SETTYPE_ANY)
00351               return cur->set_next;
00352 
00353        for (set = cur->set_next; set != NULL; set = set->set_next)
00354        {
00355               if (set->set_type == type)
00356                      return set;
00357        }
00358 
00359        return NULL;
00360 }
00361 
00362 /*
00363 **  DKIM_PARAM_GET -- get a parameter from a set
00364 **
00365 **  Parameters:
00366 **     set -- set to search
00367 **     param -- parameter to find
00368 **
00369 **  Return value:
00370 **     Pointer to the parameter requested, or NULL if it's not in the set.
00371 */
00372 
00373 static u_char *
00374 dkim_param_get(DKIM_SET *set, u_char *param)
00375 {
00376        DKIM_PLIST *plist;
00377 
00378        assert(set != NULL);
00379        assert(param != NULL);
00380 
00381        for (plist = set->set_plist[DKIM_PHASH(param[0])];
00382             plist != NULL;
00383             plist = plist->plist_next)
00384        {
00385               if (strcmp((char *) plist->plist_param, (char *) param) == 0)
00386                      return plist->plist_value;
00387        }
00388 
00389        return NULL;
00390 }
00391 
00392 /*
00393 **  DKIM_ADD_PLIST -- add an entry to a parameter-value set
00394 **
00395 **  Parameters:
00396 **     dkim -- DKIM context in which this is performed
00397 **     set -- set to modify
00398 **     param -- parameter
00399 **     value -- value
00400 **     force -- override existing value, if any
00401 **
00402 **  Return value:
00403 **     0 on success, -1 on failure.
00404 **
00405 **  Notes:
00406 **     Data is not copied; a reference to it is stored.
00407 */
00408 
00409 static int
00410 dkim_add_plist(DKIM *dkim, DKIM_SET *set, u_char *param, u_char *value,
00411                _Bool force)
00412 {
00413        DKIM_PLIST *plist;
00414 
00415        assert(dkim != NULL);
00416        assert(set != NULL);
00417        assert(param != NULL);
00418        assert(value != NULL);
00419 
00420        if (!isprint(param[0]))
00421        {
00422               dkim_error(dkim, "invalid parameter '%s'", param);
00423               return -1;
00424        }
00425 
00426        /* see if we have one already */
00427        for (plist = set->set_plist[DKIM_PHASH(param[0])];
00428             plist != NULL;
00429             plist = plist->plist_next)
00430        {
00431               if (strcasecmp((char *) plist->plist_param,
00432                              (char *) param) == 0)
00433                      break;
00434        }
00435 
00436        /* nope; make one and connect it */
00437        if (plist == NULL)
00438        {
00439               int n;
00440 
00441               plist = (DKIM_PLIST *) DKIM_MALLOC(dkim, sizeof(DKIM_PLIST));
00442               if (plist == NULL)
00443               {
00444                      dkim_error(dkim, "unable to allocate %d byte(s)",
00445                                 sizeof(DKIM_PLIST));
00446                      return -1;
00447               }
00448               force = TRUE;
00449               n = DKIM_PHASH(param[0]);
00450               plist->plist_next = set->set_plist[n];
00451               set->set_plist[n] = plist;
00452               plist->plist_param = param;
00453        }
00454 
00455        /* set the value if "force" was set (or this was a new entry) */
00456        if (force)
00457               plist->plist_value = value;
00458 
00459        return 0;
00460 }
00461 
00462 /*
00463 **  DKIM_PROCESS_SET -- process a parameter set, i.e. a string of the form
00464 **                      param=value[; param=value]*
00465 **
00466 **  Parameters:
00467 **     dkim -- DKIM context in which this is performed
00468 **     type -- a DKIM_SETTYPE constant
00469 **     str -- string to be scanned
00470 **     len -- number of bytes available at "str"
00471 **     udata -- arbitrary user data (not used)
00472 **     syntax -- only check syntax and don't add 'set' to dkim handle set
00473 **               list if TRUE
00474 **     name -- an optional "name" for this set
00475 **
00476 **  Return value:
00477 **     A DKIM_STAT constant.
00478 */
00479 
00480 DKIM_STAT
00481 dkim_process_set(DKIM *dkim, dkim_set_t type, u_char *str, size_t len,
00482                  void *udata, _Bool syntax, const char *name)
00483 {
00484        _Bool spaced;
00485        int state;
00486        int status;
00487        u_char *p;
00488        u_char *param;
00489        u_char *value;
00490        u_char *hcopy;
00491        DKIM_SET *set;
00492        const char *settype;
00493 
00494        assert(dkim != NULL);
00495        assert(str != NULL);
00496        assert(type == DKIM_SETTYPE_SIGNATURE ||
00497               type == DKIM_SETTYPE_SIGREPORT ||
00498               type == DKIM_SETTYPE_KEY ||
00499               type == DKIM_SETTYPE_POLICY);
00500 
00501        param = NULL;
00502        value = NULL;
00503        state = 0;
00504        spaced = FALSE;
00505 
00506        hcopy = (u_char *) DKIM_MALLOC(dkim, len + 1);
00507        if (hcopy == NULL)
00508        {
00509               dkim_error(dkim, "unable to allocate %d byte(s)", len + 1);
00510               return DKIM_STAT_INTERNAL;
00511        }
00512        strlcpy((char *) hcopy, (char *) str, len + 1);
00513 
00514        set = (DKIM_SET *) DKIM_MALLOC(dkim, sizeof(DKIM_SET));
00515        if (set == NULL)
00516        {
00517               DKIM_FREE(dkim, hcopy);
00518               dkim_error(dkim, "unable to allocate %d byte(s)",
00519                          sizeof(DKIM_SET));
00520               return DKIM_STAT_INTERNAL;
00521        }
00522 
00523        set->set_type = type;
00524        settype = dkim_code_to_name(settypes, type);
00525        set->set_name = name;
00526 
00527        if (!syntax)
00528        {
00529               if (dkim->dkim_sethead == NULL)
00530                      dkim->dkim_sethead = set;
00531               else
00532                      dkim->dkim_settail->set_next = set;
00533 
00534               dkim->dkim_settail = set;
00535        }
00536 
00537        set->set_next = NULL;
00538        memset(&set->set_plist, '\0', sizeof set->set_plist);
00539        set->set_data = hcopy;
00540        set->set_udata = udata;
00541        set->set_bad = FALSE;
00542 
00543        for (p = hcopy; *p != '\0'; p++)
00544        {
00545               if (!isascii(*p) || (!isprint(*p) && !isspace(*p)))
00546               {
00547                      dkim_error(dkim,
00548                                 "invalid character (ASCII 0x%02x at offset %d) in %s data",
00549                                 *p, p - hcopy, settype);
00550                      if (syntax)
00551                             dkim_set_free(dkim, set);
00552                      else
00553                             set->set_bad = TRUE;
00554                      return DKIM_STAT_SYNTAX;
00555               }
00556 
00557               switch (state)
00558               {
00559                 case 0:                          /* before param */
00560                      if (isspace(*p))
00561                      {
00562                             continue;
00563                      }
00564                      else if (isalnum(*p))
00565                      {
00566                             param = p;
00567                             state = 1;
00568                      }
00569                      else
00570                      {
00571                             dkim_error(dkim,
00572                                        "syntax error in %s data (ASCII 0x%02x at offset %d)",
00573                                        settype, *p, p - hcopy);
00574                             if (syntax)
00575                                    dkim_set_free(dkim, set);
00576                             else
00577                                    set->set_bad = TRUE;
00578                             return DKIM_STAT_SYNTAX;
00579                      }
00580                      break;
00581 
00582                 case 1:                          /* in param */
00583                      if (isspace(*p))
00584                      {
00585                             spaced = TRUE;
00586                      }
00587                      else if (*p == '=')
00588                      {
00589                             *p = '\0';
00590                             state = 2;
00591                             spaced = FALSE;
00592                      }
00593                      else if (*p == ';' || spaced)
00594                      {
00595                             dkim_error(dkim,
00596                                        "syntax error in %s data (ASCII 0x%02x at offset %d)",
00597                                        settype, *p, p - hcopy);
00598                             if (syntax)
00599                                    dkim_set_free(dkim, set);
00600                             else
00601                                    set->set_bad = TRUE;
00602                             return DKIM_STAT_SYNTAX;
00603                      }
00604                      break;
00605 
00606                 case 2:                          /* before value */
00607                      if (isspace(*p))
00608                      {
00609                             continue;
00610                      }
00611                      else if (*p == ';')         /* empty value */
00612                      {
00613                             *p = '\0';
00614                             value = p;
00615 
00616                             /* collapse the parameter */
00617                             dkim_collapse(param);
00618 
00619                             /* create the DKIM_PLIST entry */
00620                             status = dkim_add_plist(dkim, set, param,
00621                                                     value, TRUE);
00622                             if (status == -1)
00623                             {
00624                                    if (syntax)
00625                                           dkim_set_free(dkim, set);
00626                                    else
00627                                           set->set_bad = TRUE;
00628                                    return DKIM_STAT_INTERNAL;
00629                             }
00630 
00631                             /* reset */
00632                             param = NULL;
00633                             value = NULL;
00634                             state = 0;
00635                      }
00636                      else
00637                      {
00638                             value = p;
00639                             state = 3;
00640                      }
00641                      break;
00642 
00643                 case 3:                          /* in value */
00644                      if (*p == ';')
00645                      {
00646                             *p = '\0';
00647 
00648                             /* collapse the parameter and value */
00649                             dkim_collapse(param);
00650                             dkim_collapse(value);
00651 
00652                             /* create the DKIM_PLIST entry */
00653                             status = dkim_add_plist(dkim, set, param,
00654                                                     value, TRUE);
00655                             if (status == -1)
00656                             {
00657                                    if (syntax)
00658                                           dkim_set_free(dkim, set);
00659                                    else
00660                                           set->set_bad = TRUE;
00661                                    return DKIM_STAT_INTERNAL;
00662                             }
00663 
00664                             /* reset */
00665                             param = NULL;
00666                             value = NULL;
00667                             state = 0;
00668                      }
00669                      break;
00670 
00671                 default:                         /* shouldn't happen */
00672                      assert(0);
00673               }
00674        }
00675 
00676        switch (state)
00677        {
00678          case 0:                                 /* before param */
00679          case 3:                                 /* in value */
00680               /* parse the data found, if any */
00681               if (value != NULL)
00682               {
00683                      /* collapse the parameter and value */
00684                      dkim_collapse(param);
00685                      dkim_collapse(value);
00686 
00687                      /* create the DKIM_PLIST entry */
00688                      status = dkim_add_plist(dkim, set, param, value, TRUE);
00689                      if (status == -1)
00690                      {
00691                             if (syntax)
00692                                    dkim_set_free(dkim, set);
00693                             else
00694                                    set->set_bad = TRUE;
00695                             return DKIM_STAT_INTERNAL;
00696                      }
00697               }
00698               break;
00699 
00700          case 2:                                 /* before value */
00701               /* create an empty DKIM_PLIST entry */
00702               status = dkim_add_plist(dkim, set, param, (u_char *) "", TRUE);
00703               if (status == -1)
00704               {
00705                      if (syntax)
00706                             dkim_set_free(dkim, set);
00707                      else
00708                             set->set_bad = TRUE;
00709                      return DKIM_STAT_INTERNAL;
00710               }
00711               break;
00712 
00713          case 1:                                 /* after param */
00714               dkim_error(dkim, "tag without value at end of %s data",
00715                          settype);
00716               if (syntax)
00717                      dkim_set_free(dkim, set);
00718               else
00719                      set->set_bad = TRUE;
00720               return DKIM_STAT_SYNTAX;
00721 
00722          default:                                /* shouldn't happen */
00723               assert(0);
00724        }
00725 
00726        /* load up defaults, assert requirements */
00727        switch (set->set_type)
00728        {
00729          case DKIM_SETTYPE_SIGREPORT:
00730               /* check validity of "rp" */
00731               value = dkim_param_get(set, (u_char *) "rp");
00732               if (value != NULL)
00733               {
00734                      unsigned int tmp = 0;
00735 
00736                      tmp = (unsigned int) strtoul(value, (char **) &p, 10);
00737                      if (tmp > 100 || *p != '\0')
00738                      {
00739                             dkim_error(dkim,
00740                                        "invalid parameter(s) in %s data",
00741                                        settype);
00742                             if (syntax)
00743                                    dkim_set_free(dkim, set);
00744                             else
00745                                    set->set_bad = TRUE;
00746                             return DKIM_STAT_SYNTAX;
00747                      }
00748               }
00749               break;
00750               
00751          case DKIM_SETTYPE_SIGNATURE:
00752               /* make sure required stuff is here */
00753               if (dkim_param_get(set, (u_char *) "s") == NULL ||
00754                   dkim_param_get(set, (u_char *) "h") == NULL ||
00755                   dkim_param_get(set, (u_char *) "d") == NULL ||
00756                   dkim_param_get(set, (u_char *) "b") == NULL ||
00757                   dkim_param_get(set, (u_char *) "v") == NULL ||
00758                   dkim_param_get(set, (u_char *) "a") == NULL)
00759               {
00760                      dkim_error(dkim, "missing parameter(s) in %s data",
00761                                 settype);
00762                      if (syntax)
00763                             dkim_set_free(dkim, set);
00764                      else
00765                             set->set_bad = TRUE;
00766                      return DKIM_STAT_SYNTAX;
00767               }
00768 
00769               /* test validity of "t" and "x" */
00770               value = dkim_param_get(set, (u_char *) "t");
00771               if (value != NULL)
00772               {
00773                      uint64_t tmp = 0;
00774                      char *end;
00775 
00776                      errno = 0;
00777 
00778                      if (value[0] == '-')
00779                      {
00780                             errno = ERANGE;
00781                             tmp = (uint64_t) -1;
00782                      }
00783                      else if (value[0] == '\0')
00784                      {
00785                             errno = EINVAL;
00786                             tmp = (uint64_t) -1;
00787                      }
00788                      else
00789                      {
00790                             tmp = strtoull((char *) value, &end, 10);
00791                      }
00792 
00793                      if (tmp == (uint64_t) -1 || errno != 0 ||
00794                          *end != '\0')
00795                      {
00796                             dkim_error(dkim,
00797                                        "invalid \"t\" value in %s data",
00798                                        settype);
00799                             if (syntax)
00800                                    dkim_set_free(dkim, set);
00801                             else
00802                                    set->set_bad = TRUE;
00803                             return DKIM_STAT_SYNTAX;
00804                      }
00805               }
00806 
00807               value = dkim_param_get(set, (u_char *) "x");
00808               if (value != NULL)
00809               {
00810                      uint64_t tmp = 0;
00811                      char *end;
00812 
00813                      errno = 0;
00814 
00815                      if (value[0] == '-')
00816                      {
00817                             errno = ERANGE;
00818                             tmp = (uint64_t) -1;
00819                      }
00820                      else if (value[0] == '\0')
00821                      {
00822                             errno = EINVAL;
00823                             tmp = (uint64_t) -1;
00824                      }
00825                      else
00826                      {
00827                             tmp = strtoull((char *) value, &end, 10);
00828                      }
00829 
00830                      if (tmp == (uint64_t) -1 || errno != 0 ||
00831                          *end != '\0')
00832                      {
00833                             dkim_error(dkim,
00834                                        "invalid \"x\" value in %s data",
00835                                        settype);
00836                             if (syntax)
00837                                    dkim_set_free(dkim, set);
00838                             else
00839                                    set->set_bad = TRUE;
00840                             return DKIM_STAT_SYNTAX;
00841                      }
00842               }
00843 
00844               if (syntax)
00845               {
00846                      dkim_set_free(dkim, set);
00847                      return DKIM_STAT_OK;
00848               }
00849 
00850               /* default for "c" */
00851               status = dkim_add_plist(dkim, set, (u_char *) "c",
00852                                       (u_char *) "simple/simple",
00853                                       FALSE);
00854               if (status == -1)
00855               {
00856                      set->set_bad = TRUE;
00857                      return DKIM_STAT_INTERNAL;
00858               }
00859 
00860               /* default for "q" */
00861               status = dkim_add_plist(dkim, set, (u_char *) "q",
00862                                       (u_char *) "dns/txt", FALSE);
00863               if (status == -1)
00864               {
00865                      set->set_bad = TRUE;
00866                      return DKIM_STAT_INTERNAL;
00867               }
00868 
00869               break;
00870 
00871          case DKIM_SETTYPE_POLICY:
00872               if (dkim_param_get(set, (u_char *) "dkim") == NULL)
00873               {
00874                      dkim_error(dkim, "missing parameter(s) in %s data",
00875                                 settype);
00876                      if (syntax)
00877                             dkim_set_free(dkim, set);
00878                      else
00879                             set->set_bad = TRUE;
00880                      return DKIM_STAT_SYNTAX;
00881               }
00882 
00883               break;
00884 
00885          case DKIM_SETTYPE_KEY:
00886               if (syntax)
00887               {
00888                      dkim_set_free(dkim, set);
00889                      return DKIM_STAT_OK;
00890               }
00891 
00892               status = dkim_add_plist(dkim, set, (u_char *) "k",
00893                                       (u_char *) "rsa", FALSE);
00894               if (status == -1)
00895               {
00896                      set->set_bad = TRUE;
00897                      return DKIM_STAT_INTERNAL;
00898               }
00899 
00900               break;
00901                      
00902          default:
00903               assert(0);
00904        }
00905 
00906        return DKIM_STAT_OK;
00907 }
00908 
00909 /*
00910 **  DKIM_PRIVKEY_LOAD -- attempt to load a private key for later use
00911 **
00912 **  Parameters:
00913 **     dkim -- DKIM handle
00914 **
00915 **  Return value:
00916 **     A DKIM_STAT_* constant.
00917 */
00918 
00919 DKIM_STAT
00920 dkim_privkey_load(DKIM *dkim)
00921 {
00922 #ifdef USE_GNUTLS
00923        int status;
00924 #endif /* USE_GNUTLS */
00925        struct dkim_rsa *rsa;
00926 
00927        assert(dkim != NULL);
00928 
00929        if (dkim->dkim_mode != DKIM_MODE_SIGN)
00930               return DKIM_STAT_INVALID;
00931 
00932        if (dkim->dkim_signalg != DKIM_SIGN_RSASHA1 &&
00933            dkim->dkim_signalg != DKIM_SIGN_RSASHA256)
00934               return DKIM_STAT_INVALID;
00935 
00936        rsa = (struct dkim_rsa *) dkim->dkim_keydata;
00937 
00938        if (rsa == NULL)
00939        {
00940               rsa = DKIM_MALLOC(dkim, sizeof(struct dkim_rsa));
00941               if (rsa == NULL)
00942               {
00943                      dkim_error(dkim, "unable to allocate %d byte(s)",
00944                                 sizeof(struct dkim_rsa));
00945                      return DKIM_STAT_NORESOURCE;
00946               }
00947               memset(rsa, '\0', sizeof(struct dkim_rsa));
00948        }
00949 
00950        dkim->dkim_keydata = rsa;
00951 
00952 #ifdef USE_GNUTLS
00953        rsa->rsa_keydata.data = dkim->dkim_key;
00954        rsa->rsa_keydata.size = dkim->dkim_keylen;
00955 #else /* USE_GNUTLS */
00956        if (rsa->rsa_keydata == NULL)
00957        {
00958               rsa->rsa_keydata = BIO_new_mem_buf(dkim->dkim_key,
00959                                                  dkim->dkim_keylen);
00960               if (rsa->rsa_keydata == NULL)
00961               {
00962                      dkim_error(dkim, "BIO_new_mem_buf() failed");
00963                      return DKIM_STAT_NORESOURCE;
00964               }
00965        }
00966 #endif /* USE_GNUTLS */
00967 
00968 #ifdef USE_GNUTLS 
00969        if (gnutls_x509_privkey_init(&rsa->rsa_key) != GNUTLS_E_SUCCESS)
00970        {
00971               dkim_error(dkim, "gnutls_x509_privkey_init() failed");
00972               return DKIM_STAT_NORESOURCE;
00973        }
00974 
00975        status = gnutls_x509_privkey_import(rsa->rsa_key, &rsa->rsa_keydata,
00976                                            GNUTLS_X509_FMT_PEM);
00977        if (status != GNUTLS_E_SUCCESS)
00978        {
00979               status = gnutls_x509_privkey_import(rsa->rsa_key,
00980                                                   &rsa->rsa_keydata,
00981                                                    GNUTLS_X509_FMT_DER);
00982        }
00983 
00984        if (status != GNUTLS_E_SUCCESS)
00985        {
00986               dkim_error(dkim, "gnutls_x509_privkey_import() failed");
00987               return DKIM_STAT_NORESOURCE;
00988        }
00989 
00990        if (gnutls_privkey_init(&rsa->rsa_privkey) != GNUTLS_E_SUCCESS)
00991        {
00992               dkim_error(dkim, "gnutls_privkey_init() failed");
00993               return DKIM_STAT_NORESOURCE;
00994        }
00995 
00996        if (gnutls_privkey_import_x509(rsa->rsa_privkey, rsa->rsa_key,
00997                                       0) != GNUTLS_E_SUCCESS)
00998        {
00999               dkim_error(dkim,
01000                          "gnutls_privkey_import_x509() failed");
01001               (void) gnutls_privkey_deinit(rsa->rsa_privkey);
01002               return DKIM_STAT_NORESOURCE;
01003        }
01004 
01005        (void) gnutls_privkey_get_pk_algorithm(rsa->rsa_privkey,
01006                                               &rsa->rsa_keysize);
01007 
01008 #else /* USE_GNUTLS */
01009 
01010        if (strncmp((char *) dkim->dkim_key, "-----", 5) == 0)
01011        {                                         /* PEM */
01012               rsa->rsa_pkey = PEM_read_bio_PrivateKey(rsa->rsa_keydata, NULL,
01013                                                       NULL, NULL);
01014 
01015               if (rsa->rsa_pkey == NULL)
01016               {
01017                      dkim_error(dkim, "PEM_read_bio_PrivateKey() failed");
01018                      BIO_free(rsa->rsa_keydata);
01019                      rsa->rsa_keydata = NULL;
01020                      return DKIM_STAT_NORESOURCE;
01021               }
01022        }
01023        else
01024        {                                         /* DER */
01025               rsa->rsa_pkey = d2i_PrivateKey_bio(rsa->rsa_keydata, NULL);
01026 
01027               if (rsa->rsa_pkey == NULL)
01028               {
01029                      dkim_error(dkim, "d2i_PrivateKey_bio() failed");
01030                      BIO_free(rsa->rsa_keydata);
01031                      rsa->rsa_keydata = NULL;
01032                      return DKIM_STAT_NORESOURCE;
01033               }
01034        }
01035 
01036        rsa->rsa_rsa = EVP_PKEY_get1_RSA(rsa->rsa_pkey);
01037        if (rsa->rsa_rsa == NULL)
01038        {
01039               dkim_error(dkim, "EVP_PKEY_get1_RSA() failed");
01040               BIO_free(rsa->rsa_keydata);
01041               rsa->rsa_keydata = NULL;
01042               return DKIM_STAT_NORESOURCE;
01043        }
01044 
01045        rsa->rsa_keysize = RSA_size(rsa->rsa_rsa) * 8;
01046        rsa->rsa_pad = RSA_PKCS1_PADDING;
01047        rsa->rsa_rsaout = DKIM_MALLOC(dkim, rsa->rsa_keysize / 8);
01048        if (rsa->rsa_rsaout == NULL)
01049        {
01050               dkim_error(dkim, "unable to allocate %d byte(s)",
01051                                 rsa->rsa_keysize / 8);
01052               RSA_free(rsa->rsa_rsa);
01053               rsa->rsa_rsa = NULL;
01054               BIO_free(rsa->rsa_keydata);
01055               rsa->rsa_keydata = NULL;
01056               return DKIM_STAT_NORESOURCE;
01057        }
01058 #endif /* USE_GNUTLS */
01059 
01060        return DKIM_STAT_OK;
01061 }
01062 
01063 /*
01064 **  DKIM_CHECK_REQUIREDHDRS -- see if all requried headers are present
01065 **
01066 **  Parameters:
01067 **     dkim -- DKIM handle
01068 **
01069 **  Return value:
01070 **     Pointer to the name of a header that's absent, or NULL if all
01071 **     are present.
01072 */
01073 
01074 static const unsigned char *
01075 dkim_check_requiredhdrs(DKIM *dkim)
01076 {
01077        _Bool found;
01078        int c;
01079        size_t len;
01080        struct dkim_header *hdr;
01081 
01082        assert(dkim != NULL);
01083 
01084        for (c = 0; required_signhdrs[c] != NULL; c++)
01085        {
01086               found = FALSE;
01087               len = strlen((char *) required_signhdrs[c]);
01088 
01089               for (hdr = dkim->dkim_hhead; hdr != NULL; hdr = hdr->hdr_next)
01090               {
01091                      if (hdr->hdr_namelen == len &&
01092                          strncasecmp((char *) hdr->hdr_text,
01093                                      (char *) required_signhdrs[c],
01094                                      len) == 0)
01095                      {
01096                             found = TRUE;
01097                             break;
01098                      }
01099               }
01100 
01101               if (!found)
01102                      return required_signhdrs[c];
01103        }
01104 
01105        return NULL;
01106 }
01107 
01108 /*
01109 **  DKIM_SET_GETUDATA -- retrieve user data associated with a set
01110 **
01111 **  Parameters:
01112 **     set -- a DKIM_SET handle
01113 **
01114 **  Return value:
01115 **     Stored opaque handle, if any; NULL otherwise.
01116 */
01117 
01118 static void *
01119 dkim_set_getudata(DKIM_SET *set)
01120 {
01121        assert(set != NULL);
01122 
01123        return set->set_udata;
01124 }
01125 
01126 /*
01127 **  DKIM_GET_HEADER -- find a header in a queue of headers
01128 **
01129 **  Parameters:
01130 **     dkim -- DKIM handle
01131 **     name -- name of the header to find
01132 **     namelen -- length of the header name at "name" (or 0)
01133 **     inst -- instance to find (0 == first/any)
01134 **
01135 **  Return value:
01136 **     Pointer to a (struct dkim_header), or NULL if not found.
01137 */
01138 
01139 static struct dkim_header *
01140 dkim_get_header(DKIM *dkim, u_char *name, size_t namelen, int inst)
01141 {
01142        size_t len;
01143        struct dkim_header *hdr;
01144 
01145        assert(dkim != NULL);
01146        assert(name != NULL);
01147 
01148        if (namelen == 0)
01149               len = strlen((char *) name);
01150        else
01151               len = namelen;
01152 
01153        for (hdr = dkim->dkim_hhead; hdr != NULL; hdr = hdr->hdr_next)
01154        {
01155               if (hdr->hdr_namelen == len &&
01156                   strncasecmp((char *) hdr->hdr_text,
01157                               (char *) name, len) == 0)
01158               {
01159                      if (inst == 0)
01160                             return hdr;
01161                      else
01162                             inst--;
01163               }
01164        }
01165 
01166        return NULL;
01167 }
01168 
01169 /*
01170 **  DKIM_KEY_SMTP -- return TRUE iff a parameter set defines an SMTP key
01171 **
01172 **  Parameters:
01173 **     set -- set to be checked
01174 **
01175 **  Return value:
01176 **     TRUE iff "set" contains an "s" parameter whose value is either
01177 **     "email" or "*".
01178 */
01179 
01180 static _Bool
01181 dkim_key_smtp(DKIM_SET *set)
01182 {
01183        u_char *val;
01184        char *last;
01185        u_char *p;
01186        char buf[BUFRSZ + 1];
01187 
01188        assert(set != NULL);
01189        assert(set->set_type == DKIM_SETTYPE_KEY);
01190 
01191        val = dkim_param_get(set, (u_char * ) "s");
01192 
01193        if (val == NULL)
01194               return TRUE;
01195 
01196        strlcpy(buf, (char *) val, sizeof buf);
01197 
01198        for (p = (u_char *) strtok_r(buf, ":", &last);
01199             p != NULL;
01200             p = (u_char *) strtok_r(NULL, ":", &last))
01201        {
01202               if (strcmp((char *) p, "*") == 0 ||
01203                   strcasecmp((char *) p, "email") == 0)
01204                      return TRUE;
01205        }
01206 
01207        return FALSE;
01208 }
01209 
01210 /*
01211 **  DKIM_KEY_HASHOK -- return TRUE iff a signature's hash is in the approved
01212 **                     list of hashes for a given key
01213 **
01214 **  Parameters:
01215 **     sig -- DKIM_SIGINFO handle
01216 **     hashlist -- colon-separated approved hash list
01217 **
01218 **  Return value:
01219 **     TRUE iff a particular hash is in the approved list of hashes.
01220 */
01221 
01222 static _Bool
01223 dkim_key_hashok(DKIM_SIGINFO *sig, u_char *hashlist)
01224 {
01225        int hashalg;
01226        u_char *x, *y;
01227        u_char tmp[BUFRSZ + 1];
01228 
01229        assert(sig != NULL);
01230 
01231        if (hashlist == NULL)
01232               return TRUE;
01233 
01234        x = NULL;
01235        memset(tmp, '\0', sizeof tmp);
01236 
01237        y = hashlist;
01238        for (;;)
01239        {
01240               if (*y == ':' || *y == '\0')
01241               {
01242                      if (x != NULL)
01243                      {
01244                             strlcpy((char *) tmp, (char *) x, sizeof tmp);
01245                             tmp[y - x] = '\0';
01246                             hashalg = dkim_name_to_code(hashes,
01247                                                         (char *) tmp);
01248                             if (hashalg == sig->sig_hashtype)
01249                                    return TRUE;
01250                      }
01251 
01252                      x = NULL;
01253               }
01254               else if (x == NULL)
01255               {
01256                      x = y;
01257               }
01258 
01259               if (*y == '\0')
01260                      return FALSE;
01261               y++;
01262        }
01263 
01264        /* NOTREACHED */
01265 }
01266 
01267 /*
01268 **  DKIM_KEY_HASHESOK -- return TRUE iff this key supports at least one
01269 **                       hash method we know about (or doesn't specify)
01270 **
01271 **  Parameters:
01272 **     hashlist -- colon-separated list of hashes (or NULL)
01273 **
01274 **  Return value:
01275 **     TRUE iff this key supports at least one hash method we know about
01276 **     (or doesn't specify)
01277 */
01278 
01279 static _Bool
01280 dkim_key_hashesok(DKIM_LIB *lib, u_char *hashlist)
01281 {
01282        u_char *x, *y;
01283        u_char tmp[BUFRSZ + 1];
01284 
01285        assert(lib != NULL);
01286 
01287        if (hashlist == NULL)
01288               return TRUE;
01289 
01290        x = NULL;
01291        memset(tmp, '\0', sizeof tmp);
01292 
01293        y = hashlist;
01294        for (;;)
01295        {
01296               if (*y == ':' || *y == '\0')
01297               {
01298                      if (x != NULL)
01299                      {
01300                             int hashcode;
01301 
01302                             strlcpy((char *) tmp, (char *) x, sizeof tmp);
01303                             tmp[y - x] = '\0';
01304 
01305                             hashcode = dkim_name_to_code(hashes,
01306                                                          (char *) tmp);
01307 
01308                             if (hashcode != -1 &&
01309                                 (hashcode != DKIM_HASHTYPE_SHA256 ||
01310                                  dkim_libfeature(lib, DKIM_FEATURE_SHA256)))
01311                                    return TRUE;
01312                      }
01313 
01314                      x = NULL;
01315               }
01316               else if (x == NULL)
01317               {
01318                      x = y;
01319               }
01320 
01321               if (*y == '\0')
01322                      return FALSE;
01323               y++;
01324        }
01325 
01326        /* NOTREACHED */
01327 }
01328 
01329 #if 0
01330 /*
01331 **  DKIM_SIG_SIGNEROK -- return TRUE iff the signer is specified in a signed
01332 **                       sender header
01333 **
01334 **  Parameters:
01335 **     dkim -- DKIM handle
01336 **     set -- signature set to be checked
01337 **     hdrs -- names of sender headers
01338 **
01339 **  Return value:
01340 **     TRUE iff the value of the "i" parameter appears in a signed sender
01341 **     header.
01342 **
01343 **  Note:
01344 **     This essentially detects third-party signatures.  It's not of use
01345 **     yet until SSP addresses this question.
01346 */
01347 
01348 static _Bool
01349 dkim_sig_signerok(DKIM *dkim, DKIM_SET *set, u_char **hdrs)
01350 {
01351        int status;
01352        int c;
01353        int clen;
01354        struct dkim_header *cur;
01355        u_char *colon;
01356        char *i;
01357        char *user;
01358        char *domain;
01359        char buf[MAXADDRESS + 1];
01360        char addr[MAXADDRESS + 1];
01361        char signer[MAXADDRESS + 1];
01362 
01363        assert(dkim != NULL);
01364        assert(set != NULL);
01365        assert(set->set_type == DKIM_SETTYPE_SIGNATURE);
01366 
01367        i = dkim_param_get(set, "i");
01368 
01369        assert(i != NULL);
01370 
01371        memset(signer, '\0', sizeof signer);
01372        (void) dkim_qp_decode(i, signer, sizeof signer - 1);
01373 
01374        /* for each header in the "sender header" list */
01375        for (c = 0; hdrs[c] != NULL; c++)
01376        {
01377               /* for each header in the message */
01378               for (cur = dkim->dkim_hhead; cur != NULL; cur = cur->hdr_next)
01379               {
01380                      /* skip unsigned headers */
01381                      if ((cur->hdr_flags & DKIM_HDR_SIGNED) == 0)
01382                             continue;
01383 
01384                      /* determine header name size */
01385                      colon = strchr(cur->hdr_text, ':');
01386                      if (colon == NULL)
01387                             clen = strlen(cur->hdr_text);
01388                      else
01389                             clen = colon - cur->hdr_text;
01390 
01391                      /* if this is a sender header */
01392                      if (strncasecmp(hdrs[c], cur->hdr_text, clen) == 0)
01393                      {
01394                             if (colon == NULL)
01395                                    colon = cur->hdr_text;
01396                             else
01397                                    colon += 1;
01398 
01399                             strlcpy(buf, colon, sizeof buf);
01400 
01401                             status = dkim_mail_parse(buf, &user, &domain);
01402                             if (status != 0 || domain == NULL ||
01403                                 user == NULL || user[0] == '\0' ||
01404                                 domain[0] == '\0')
01405                                    continue;
01406 
01407                             snprintf(addr, sizeof addr, "%s@%s",
01408                                      user, domain);
01409 
01410                             /* see if the sender matches "i" */
01411                             if (dkim_addrcmp(addr, signer) == 0)
01412                                    return TRUE;
01413                      }
01414               }
01415        }
01416 
01417        return FALSE;
01418 }
01419 #endif /* 0 */
01420 
01421 /*
01422 **  DKIM_SIG_HDRLISTOK -- return TRUE iff a header list contained at least
01423 **                        all of those headers which MUST be signed
01424 **
01425 **  Parameters:
01426 **     dkim -- DKIM handle
01427 **     hdrlist -- header list to be checked
01428 **
01429 **  Return value:
01430 **     1 if the header list meets spec requirements,
01431 **     0 if not,
01432 **     -1 on error
01433 */
01434 
01435 static _Bool
01436 dkim_sig_hdrlistok(DKIM *dkim, u_char *hdrlist)
01437 {
01438        _Bool in = FALSE;
01439        _Bool found;
01440        int c;
01441        int d;
01442        int nh;
01443        u_char *p;
01444        u_char **ptrs;
01445        u_char tmp[DKIM_MAXHEADER + 1];
01446 
01447        assert(dkim != NULL);
01448        assert(hdrlist != NULL);
01449 
01450        strlcpy((char *) tmp, (char *) hdrlist, sizeof tmp);
01451 
01452        /* figure out how many headers were named */
01453        c = 0;
01454        for (p = tmp; *p != '\0'; p++)
01455        {
01456               if (*p == ':')
01457               {
01458                      in = FALSE;
01459               }
01460               else if (isascii(*p) && !isspace(*p) && !in)
01461               {
01462                      c++;
01463                      in = TRUE;
01464               }
01465        }
01466 
01467        nh = c;
01468 
01469        /* allocate an array of pointers to them */
01470        ptrs = DKIM_MALLOC(dkim, sizeof(u_char *) * nh);
01471        if (ptrs == NULL)
01472        {
01473               dkim_error(dkim, "unable to allocate %d byte(s)",
01474                          sizeof(u_char *) * nh);
01475               return -1;
01476        }
01477 
01478        /* set the pointers */
01479        c = 0;
01480        in = FALSE;
01481        for (p = tmp; *p != '\0'; p++)
01482        {
01483               if (*p == ':')
01484               {
01485                      *p = '\0';
01486                      in = FALSE;
01487               }
01488               else if (isascii(*p) && !isspace(*p) && !in)
01489               {
01490                      ptrs[c++] = p;
01491                      in = TRUE;
01492               }
01493        }
01494 
01495        /* verify that each required header was represented */
01496        for (d = 0; ; d++)
01497        {
01498               if (required_signhdrs[d] == NULL)
01499                      break;
01500 
01501               found = FALSE;
01502 
01503               for (c = 0; c < nh; c++)
01504               {
01505                      if (strcasecmp((char *) required_signhdrs[d],
01506                                     (char *) ptrs[c]) == 0)
01507                      {
01508                             found = TRUE;
01509                             break;
01510                      }
01511               }
01512 
01513               if (!found)
01514               {
01515                      DKIM_FREE(dkim, ptrs);
01516 
01517                      return 0;
01518               }
01519        }
01520 
01521        DKIM_FREE(dkim, ptrs);
01522 
01523        return 1;
01524 }
01525 
01526 /*
01527 **  DKIM_SIG_DOMAINOK -- return TRUE iff a signature appears to have valid
01528 **                       domain correlation; that is, "i" must be the same
01529 **                       domain as or a subdomain of "d"
01530 **
01531 **  Parameters:
01532 **     dkim -- DKIM handle
01533 **     set -- signature set to be checked
01534 **
01535 **  Return value:
01536 **     TRUE iff the "i" parameter and the "d" parameter match up.
01537 */
01538 
01539 static _Bool
01540 dkim_sig_domainok(DKIM *dkim, DKIM_SET *set)
01541 {
01542        char *at;
01543        char *dot;
01544        u_char *i;
01545        u_char *d;
01546        u_char addr[MAXADDRESS + 1];
01547 
01548        assert(dkim != NULL);
01549        assert(set != NULL);
01550        assert(set->set_type == DKIM_SETTYPE_SIGNATURE);
01551 
01552        i = dkim_param_get(set, (u_char *) "i");
01553        d = dkim_param_get(set, (u_char *) "d");
01554 
01555        assert(d != NULL);
01556 
01557        memset(addr, '\0', sizeof addr);
01558 
01559        if (i == NULL)
01560               snprintf((char *) addr, sizeof addr, "@%s", d);
01561        else
01562               dkim_qp_decode(i, addr, sizeof addr - 1);
01563 
01564        at = strchr((char *) addr, '@');
01565        if (at == NULL)
01566               return FALSE;
01567 
01568        if (strcasecmp(at + 1, (char *) d) == 0)
01569               return TRUE;
01570 
01571        for (dot = strchr(at, '.'); dot != NULL; dot = strchr(dot + 1, '.'))
01572        {
01573               if (strcasecmp(dot + 1, (char *) d) == 0)
01574               {
01575                      dkim->dkim_subdomain = TRUE;
01576                      return TRUE;
01577               }
01578        }
01579 
01580        return FALSE;
01581 }
01582 
01583 /*
01584 **  DKIM_SIG_EXPIRED -- return TRUE iff a signature appears to have expired
01585 **
01586 **  Parameters:
01587 **     set -- signature set to be checked
01588 **     drift -- seconds of drift allowed
01589 **
01590 **  Return value:
01591 **     TRUE iff "set" contains an "x=" parameter which indicates a time
01592 **     which has passed.
01593 **
01594 **  Notes:
01595 **     Syntax is not checked here.  It's checked in dkim_process_set().
01596 */
01597 
01598 static _Bool
01599 dkim_sig_expired(DKIM_SET *set, uint64_t drift)
01600 {
01601        time_t now;
01602        uint64_t expire;
01603        uint64_t nowl;
01604        u_char *val;
01605 
01606        assert(set != NULL);
01607        assert(set->set_type == DKIM_SETTYPE_SIGNATURE);
01608 
01609        val = dkim_param_get(set, (u_char *) "x");
01610        if (val == NULL)
01611               return FALSE;
01612 
01613        if (sizeof(uint64_t) == sizeof(unsigned long long))
01614               expire = strtoull((char *) val, NULL, 10);
01615        else if (sizeof(uint64_t) == sizeof(unsigned long))
01616               expire = strtoul((char *) val, NULL, 10);
01617        else
01618               expire = (unsigned int) strtoul((char *) val, NULL, 10);
01619 
01620        (void) time(&now);
01621        nowl = (uint64_t) now;
01622 
01623        return (nowl >= expire + drift);
01624 }
01625 
01626 /*
01627 **  DKIM_SIG_TIMESTAMPSOK -- return TRUE iff a signature appears to have
01628 **                           both a timestamp and an expiration date and they
01629 **                           are properly ordered
01630 **
01631 **  Parameters:
01632 **     set -- signature set to be checked
01633 **
01634 **  Return value:
01635 **     TRUE: - "set" contains both a "t=" parameter and an "x=" parameter
01636 **             and the latter is greater than the former
01637 **           - "set" is missing either "t=" or "x=" (or both)
01638 **     FALSE: otherwise
01639 **
01640 **  Notes:
01641 **     Syntax is not checked here.  It's checked in dkim_process_set().
01642 */
01643 
01644 static _Bool
01645 dkim_sig_timestampsok(DKIM_SET *set)
01646 {
01647        uint64_t signtime;
01648        uint64_t expire;
01649        u_char *val;
01650 
01651        assert(set != NULL);
01652        assert(set->set_type == DKIM_SETTYPE_SIGNATURE);
01653 
01654        val = dkim_param_get(set, (u_char *) "t");
01655        if (val == NULL)
01656               return TRUE;
01657        if (sizeof(uint64_t) == sizeof(unsigned long long))
01658               signtime = strtoull((char *) val, NULL, 10);
01659        else if (sizeof(uint64_t) == sizeof(unsigned long))
01660               signtime = strtoul((char *) val, NULL, 10);
01661        else
01662               signtime = (unsigned int) strtoul((char *) val, NULL, 10);
01663 
01664        val = dkim_param_get(set, (u_char *) "x");
01665        if (val == NULL)
01666               return TRUE;
01667        if (sizeof(uint64_t) == sizeof(unsigned long long))
01668               expire = strtoull((char *) val, NULL, 10);
01669        else if (sizeof(uint64_t) == sizeof(unsigned long))
01670               expire = strtoul((char *) val, NULL, 10);
01671        else
01672               expire = (unsigned int) strtoul((char *) val, NULL, 10);
01673 
01674        return (signtime < expire);
01675 }
01676 
01677 /*
01678 **  DKIM_SIG_FUTURE -- return TRUE iff a signature appears to have been
01679 **                     generated in the future
01680 **
01681 **  Parameters:
01682 **     set -- signature set to be checked
01683 **     drift -- seconds of drift allowed
01684 **
01685 **  Return value:
01686 **     TRUE iff "set" contains a "t=" parameter which indicates a time
01687 **     in the future.
01688 **
01689 **  Notes:
01690 **     Syntax is not checked here.  It's checked in dkim_process_set().
01691 */
01692 
01693 static _Bool
01694 dkim_sig_future(DKIM_SET *set, uint64_t drift)
01695 {
01696        uint64_t signtime;
01697        uint64_t nowl;
01698        time_t now;
01699        u_char *val;
01700 
01701        assert(set != NULL);
01702        assert(set->set_type == DKIM_SETTYPE_SIGNATURE);
01703 
01704        val = dkim_param_get(set, (u_char *) "t");
01705        if (val == NULL)
01706               return FALSE;
01707 
01708        if (sizeof(uint64_t) == sizeof(unsigned long long))
01709               signtime = strtoull((char *) val, NULL, 10);
01710        else if (sizeof(uint64_t) == sizeof(unsigned long))
01711               signtime = strtoul((char *) val, NULL, 10);
01712        else
01713               signtime = (unsigned int) strtoul((char *) val, NULL, 10);
01714 
01715        (void) time(&now);
01716        nowl = (uint64_t) now;
01717 
01718        return (nowl < signtime - drift);
01719 }
01720 
01721 /*
01722 **  DKIM_SIG_VERSIONOK -- return TRUE iff a signature appears to have a version
01723 **                        we can accept
01724 **
01725 **  Parameters:
01726 **     dkim -- DKIM handle
01727 **     set -- signature set to be checked
01728 **
01729 **  Return value:
01730 **     TRUE iff "set" appears to be based on a version of DKIM that is
01731 **     supported by this API.
01732 */
01733 
01734 static _Bool
01735 dkim_sig_versionok(DKIM *dkim, DKIM_SET *set)
01736 {
01737        char *v;
01738 
01739        assert(set != NULL);
01740        assert(set->set_type == DKIM_SETTYPE_SIGNATURE);
01741 
01742        v = (char *) dkim_param_get(set, (u_char *) "v");
01743 
01744        assert(v != NULL);
01745 
01746        /* check for DKIM_VERSION_SIG */
01747        if (strcmp(v, DKIM_VERSION_SIG) == 0)
01748               return TRUE;
01749 
01750        /* check for DKIM_VERSION_SIGOLD if allowed */
01751        if ((dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_ACCEPTV05) &&
01752            strcmp(v, DKIM_VERSION_SIGOLD) == 0)
01753               return TRUE;
01754 
01755        return FALSE;
01756 }
01757 
01758 /*
01759 **  DKIM_SIGLIST_SETUP -- create a signature list and load the elements
01760 **
01761 **  Parameters:
01762 **     dkim -- DKIM handle
01763 **
01764 **  Return value:
01765 **     A DKIM_STAT_* constant.
01766 */
01767 
01768 DKIM_STAT
01769 dkim_siglist_setup(DKIM *dkim)
01770 {
01771        _Bool bsh;
01772        int c;
01773        int hashtype = DKIM_HASHTYPE_UNKNOWN;
01774        int hstatus;
01775        size_t b64siglen;
01776        size_t len;
01777        DKIM_STAT status;
01778        ssize_t signlen = (ssize_t) -1;
01779        uint64_t drift;
01780        dkim_canon_t bodycanon;
01781        dkim_canon_t hdrcanon;
01782        dkim_alg_t signalg;
01783        DKIM_SET *set;
01784        DKIM_LIB *lib;
01785        DKIM_CANON *hc;
01786        DKIM_CANON *bc;
01787        u_char *param;
01788        u_char *hdrlist;
01789 
01790        assert(dkim != NULL);
01791 
01792        lib = dkim->dkim_libhandle;
01793        drift = lib->dkiml_clockdrift;
01794 
01795        bsh = ((lib->dkiml_flags & DKIM_LIBFLAGS_BADSIGHANDLES) != 0);
01796 
01797        len = dkim->dkim_sigcount * sizeof(DKIM_SIGINFO *);
01798        dkim->dkim_siglist = DKIM_MALLOC(dkim, len);
01799        if (dkim->dkim_siglist == NULL)
01800        {
01801               dkim_error(dkim, "unable to allocate %d byte(s)", len);
01802               return DKIM_STAT_NORESOURCE;
01803        }
01804 
01805        /* allocate the siginfo elements */
01806        for (c = 0; c < dkim->dkim_sigcount; c++)
01807        {
01808               dkim->dkim_siglist[c] = DKIM_MALLOC(dkim,
01809                                                   sizeof(DKIM_SIGINFO));
01810               if (dkim->dkim_siglist[c] == NULL)
01811               {
01812                      int n;
01813 
01814                      dkim_error(dkim,
01815                                 "unable to allocate %d byte(s)",
01816                                 sizeof(DKIM_SIGINFO));
01817                      for (n = 0; n < c; n++)
01818                             DKIM_FREE(dkim, dkim->dkim_siglist[n]);
01819                      return DKIM_STAT_NORESOURCE;
01820               }
01821 
01822               memset(dkim->dkim_siglist[c], '\0', sizeof(DKIM_SIGINFO));
01823        }
01824 
01825        /* populate the elements */
01826        for (set = dkim_set_first(dkim, DKIM_SETTYPE_SIGNATURE), c = 0;
01827             set != NULL && c < dkim->dkim_sigcount;
01828             set = dkim_set_next(set, DKIM_SETTYPE_SIGNATURE), c++)
01829        {
01830               /* cope with bad ones */
01831               if (set->set_bad && !bsh)
01832               {
01833                      c--;
01834                      continue;
01835               }
01836 
01837               dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_UNKNOWN;
01838               dkim->dkim_siglist[c]->sig_dnssec_key = DKIM_DNSSEC_UNKNOWN;
01839 
01840               /* store the set */
01841               dkim->dkim_siglist[c]->sig_taglist = set;
01842 
01843               /* override query method? */
01844               if (lib->dkiml_querymethod != DKIM_QUERY_UNKNOWN)
01845                      dkim->dkim_siglist[c]->sig_query = lib->dkiml_querymethod;
01846 
01847               /* critical stuff: signing domain */
01848               param = dkim_param_get(set, (u_char *) "d");
01849               if (param == NULL)
01850               {
01851                      dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_MISSING_D;
01852                      continue;
01853               }
01854               else if (param[0] == '\0')
01855               {
01856                      dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_EMPTY_D;
01857                      continue;
01858               }
01859               dkim->dkim_siglist[c]->sig_domain = param;
01860 
01861               /* critical stuff: selector */
01862               param = dkim_param_get(set, (u_char *) "s");
01863               if (param == NULL)
01864               {
01865                      dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_MISSING_S;
01866                      continue;
01867               }
01868               else if (param[0] == '\0')
01869               {
01870                      dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_EMPTY_S;
01871                      continue;
01872               }
01873               dkim->dkim_siglist[c]->sig_selector = param;
01874 
01875               /* some basic checks first */
01876               param = dkim_param_get(set, (u_char *) "v");
01877               if (param == NULL)
01878               {
01879                      dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_MISSING_V;
01880                      continue;
01881               }
01882               else if (param[0] == '\0')
01883               {
01884                      dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_EMPTY_V;
01885                      continue;
01886               }
01887               else if (!dkim_sig_versionok(dkim, set))
01888               {
01889                      dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_VERSION;
01890                      continue;
01891               }
01892               else if (!dkim_sig_domainok(dkim, set))
01893               {
01894                      dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_DOMAIN;
01895                      continue;
01896               }
01897               else if (dkim_sig_expired(set, drift))
01898               {
01899                      dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_EXPIRED;
01900                      continue;
01901               }
01902               else if (dkim_sig_future(set, drift))
01903               {
01904                      dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_FUTURE;
01905                      continue;
01906               }
01907               else if (!dkim_sig_timestampsok(set))
01908               {
01909                      dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_TIMESTAMPS;
01910                      continue;
01911               }
01912 
01913               /* determine canonicalizations */
01914               param = dkim_param_get(set, (u_char *) "c");
01915               if (param == NULL)
01916               {
01917                      hdrcanon = DKIM_CANON_SIMPLE;
01918                      bodycanon = DKIM_CANON_SIMPLE;
01919               }
01920               else
01921               {
01922                      char *q;
01923                      char value[BUFRSZ + 1];
01924 
01925                      strlcpy(value, (char *) param, sizeof value);
01926 
01927                      q = strchr(value, '/');
01928                      if (q != NULL)
01929                             *q = '\0';
01930 
01931                      hdrcanon = dkim_name_to_code(canonicalizations, value);
01932                      if (hdrcanon == -1)
01933                      {
01934                             dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_INVALID_HC;
01935                             continue;
01936                      }
01937 
01938                      if (q == NULL)
01939                      {
01940                             bodycanon = DKIM_CANON_SIMPLE;
01941                      }
01942                      else
01943                      {
01944                             bodycanon = dkim_name_to_code(canonicalizations,
01945                                                           q + 1);
01946 
01947                             if (bodycanon == -1)
01948                             {
01949                                    dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_INVALID_BC;
01950                                    continue;
01951                             }
01952                      }
01953               }
01954 
01955               /* determine hash type */
01956               param = dkim_param_get(set, (u_char *) "a");
01957               if (param == NULL)
01958               {
01959                      dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_MISSING_A;
01960                      continue;
01961               }
01962               else
01963               {
01964                      signalg = dkim_name_to_code(algorithms,
01965                                                  (char *) param);
01966 
01967                      if (signalg == -1)
01968                      {
01969                             dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_INVALID_A;
01970                             continue;
01971                      }
01972 
01973                      switch (signalg)
01974                      {
01975                        case DKIM_SIGN_RSASHA1:
01976                             hashtype = DKIM_HASHTYPE_SHA1;
01977                             break;
01978 
01979                        case DKIM_SIGN_RSASHA256:
01980                             if (dkim_libfeature(lib, DKIM_FEATURE_SHA256))
01981                             {
01982                                    hashtype = DKIM_HASHTYPE_SHA256;
01983                             }
01984                             else
01985                             {
01986                                    dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_INVALID_A;
01987                                    continue;
01988                             }
01989                             break;
01990 
01991                        default:
01992                             assert(0);
01993                             /* NOTREACHED */
01994                      }
01995 
01996                      dkim->dkim_siglist[c]->sig_signalg = signalg;
01997                      dkim->dkim_siglist[c]->sig_hashtype = hashtype;
01998               }
01999 
02000               /* determine header list */
02001               param = dkim_param_get(set, (u_char *) "h");
02002               if (param == NULL)
02003               {
02004                      dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_MISSING_H;
02005                      continue;
02006               }
02007               else if (param[0] == '\0')
02008               {
02009                      dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_EMPTY_H;
02010                      continue;
02011               }
02012 
02013               hstatus = dkim_sig_hdrlistok(dkim, param);
02014               if (hstatus == 0)
02015               {
02016                      dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_INVALID_H;
02017                      continue;
02018               }
02019               else if (hstatus == -1)
02020               {
02021                      return DKIM_STAT_NORESOURCE;
02022               }
02023 
02024               hdrlist = param;
02025 
02026               /* determine signing length */
02027               param = dkim_param_get(set, (u_char *) "l");
02028               if (param != NULL)
02029               {
02030                      char *q;
02031 
02032                      errno = 0;
02033                      if (param[0] == '-')
02034                      {
02035                             errno = ERANGE;
02036                             signlen = ULONG_MAX;
02037                      }
02038                      else
02039                      {
02040                             signlen = (ssize_t) strtoul((char *) param,
02041                                                       &q, 10);
02042                      }
02043 
02044                      if (signlen == ULONG_MAX || errno != 0 || *q != '\0')
02045                      {
02046                             dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_INVALID_L;
02047                             continue;
02048                      }
02049               }
02050 
02051               /* query method */
02052               param = dkim_param_get(set, (u_char *) "q");
02053               if (param != NULL)
02054               {
02055                      _Bool bad_qo = FALSE;
02056                      dkim_query_t q = (dkim_query_t) -1;
02057                      u_char *p;
02058                      char *last;
02059                      u_char *opts;
02060                      u_char tmp[BUFRSZ + 1];
02061                      u_char qtype[BUFRSZ + 1];
02062 
02063                      strlcpy((char *) qtype, (char *) param, sizeof qtype);
02064 
02065                      for (p = (u_char *) strtok_r((char *) qtype, ":",
02066                                                   &last);
02067                           p != NULL;
02068                           p = (u_char *) strtok_r(NULL, ":", &last))
02069                      {
02070                             opts = (u_char *) strchr((char *) p, '/');
02071                             if (opts != NULL)
02072                             {
02073                                    strlcpy((char *) tmp, (char *) p,
02074                                            sizeof tmp);
02075                                    p = tmp;
02076                                    opts = (u_char *) strchr((char *) tmp,
02077                                                             '/');
02078                                    if (opts != NULL)
02079                                    {
02080                                           *opts = '\0';
02081                                           opts++;
02082                                    }
02083                             }
02084 
02085                             /* unknown type */
02086                             q = dkim_name_to_code(querytypes, (char *) p);
02087                             if (q == (dkim_query_t) -1)
02088                                    continue;
02089 
02090                             if (q == DKIM_QUERY_DNS)
02091                             {
02092                                    /* "txt" option required (also default) */
02093                                    if (opts != NULL &&
02094                                        strcmp((char *) opts, "txt") != 0)
02095                                    {
02096                                           bad_qo = TRUE;
02097                                           continue;
02098                                    }
02099                             }
02100 
02101                             break;
02102                      }
02103 
02104                      if (q == (dkim_query_t) -1)
02105                      {
02106                             dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_INVALID_Q;
02107                             continue;
02108                      }
02109                      else if (bad_qo)
02110                      {
02111                             dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_INVALID_QO;
02112                             continue;
02113                      }
02114 
02115                      dkim->dkim_siglist[c]->sig_query = q;
02116               }
02117 
02118               /* override query method? */
02119               if (lib->dkiml_querymethod != DKIM_QUERY_UNKNOWN)
02120                      dkim->dkim_siglist[c]->sig_query = lib->dkiml_querymethod;
02121 
02122               /* timestamp */
02123               param = dkim_param_get(set, (u_char *) "t");
02124               if (param == NULL)
02125               {
02126                      dkim->dkim_siglist[c]->sig_timestamp = 0;
02127               }
02128               else
02129               {
02130                      if (sizeof(uint64_t) == sizeof(unsigned long long))
02131                      {
02132                             dkim->dkim_siglist[c]->sig_timestamp = strtoull((char *) param,
02133                                                                             NULL,
02134                                                                             10);
02135                      }
02136                      else if (sizeof(uint64_t) == sizeof(unsigned long))
02137                      {
02138                             dkim->dkim_siglist[c]->sig_timestamp = strtoul((char *) param,
02139                                                                            NULL,
02140                                                                            10);
02141                      }
02142                      else
02143                      {
02144                             dkim->dkim_siglist[c]->sig_timestamp = (unsigned int) strtoul((char *) param,
02145                                                                                           NULL,
02146                                                                                           10);
02147                      }
02148               }
02149 
02150               /* body hash */
02151               param = dkim_param_get(set, (u_char *) "bh");
02152               if (param == NULL)
02153               {
02154                      dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_MISSING_BH;
02155                      continue;
02156               }
02157               else if (param[0] == '\0')
02158               {
02159                      dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_EMPTY_BH;
02160                      continue;
02161               }
02162 
02163               /* signature */
02164               param = dkim_param_get(set, (u_char *) "b");
02165               if (param == NULL)
02166               {
02167                      dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_MISSING_B;
02168                      continue;
02169               }
02170               else if (param[0] == '\0')
02171               {
02172                      dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_EMPTY_B;
02173                      continue;
02174               }
02175 
02176               b64siglen = strlen((char *) param);
02177               dkim->dkim_siglist[c]->sig_sig = DKIM_MALLOC(dkim,
02178                                                            b64siglen);
02179               if (dkim->dkim_siglist[c]->sig_sig == NULL)
02180               {
02181                      dkim_error(dkim,
02182                                 "unable to allocate %d byte(s)",
02183                                 b64siglen);
02184                      return DKIM_STAT_NORESOURCE;
02185               }
02186 
02187               status = dkim_base64_decode(param,
02188                                           dkim->dkim_siglist[c]->sig_sig,
02189                                           b64siglen);
02190               if (status < 0)
02191               {
02192                      dkim->dkim_siglist[c]->sig_error = DKIM_SIGERROR_CORRUPT_B;
02193                      continue;
02194               }
02195               else
02196               {
02197                      dkim->dkim_siglist[c]->sig_siglen = status;
02198               }
02199 
02200               /* canonicalization handle for the headers */
02201               status = dkim_add_canon(dkim, TRUE, hdrcanon, hashtype,
02202                                       hdrlist, dkim_set_getudata(set),
02203                                       0, &hc);
02204               if (status != DKIM_STAT_OK)
02205                      return status;
02206               dkim->dkim_siglist[c]->sig_hdrcanon = hc;
02207               dkim->dkim_siglist[c]->sig_hdrcanonalg = hdrcanon;
02208 
02209               /* canonicalization handle for the body */
02210               status = dkim_add_canon(dkim, FALSE, bodycanon,
02211                                       hashtype, NULL, NULL, signlen,
02212                                       &bc);
02213               if (status != DKIM_STAT_OK)
02214                      return status;
02215               dkim->dkim_siglist[c]->sig_bodycanon = bc;
02216               dkim->dkim_siglist[c]->sig_bodycanonalg = bodycanon;
02217 
02218               /* the rest */
02219               dkim->dkim_siglist[c]->sig_bh = DKIM_SIGBH_UNTESTED;
02220               dkim->dkim_siglist[c]->sig_flags = 0;
02221 
02222               /* allow the user to generate its handle */
02223               if (lib->dkiml_sig_handle != NULL)
02224                      dkim->dkim_siglist[c]->sig_context = lib->dkiml_sig_handle(dkim->dkim_closure);
02225 
02226               /* populate the user handle */
02227               if (lib->dkiml_sig_tagvalues != NULL)
02228               {
02229                      u_int n;
02230                      dkim_param_t pcode;
02231                      struct dkim_plist *plist;
02232                      void *user;
02233 
02234                      user = dkim->dkim_siglist[c]->sig_context;
02235 
02236                      for (n = 0; n < NPRINTABLE; n++)
02237                      {
02238                             for (plist = set->set_plist[n];
02239                                  plist != NULL;
02240                                  plist = plist->plist_next)
02241                             {
02242                                    pcode = dkim_name_to_code(sigparams,
02243                                                              (char *) plist->plist_param);
02244 
02245                                    (void) lib->dkiml_sig_tagvalues(user,
02246                                                                    pcode,
02247                                                                    plist->plist_param,
02248                                                                    plist->plist_value);
02249                             }
02250                      }
02251               }
02252        }
02253 
02254        return DKIM_STAT_OK;
02255 }
02256 
02257 /*
02258 **  DKIM_GENSIGHDR -- generate a signature header
02259 **
02260 **  Parameters:
02261 **     dkim -- DKIM handle
02262 **     sig -- DKIM_SIGINFO handle
02263 **     dstr -- dstring to which to write
02264 **     delim -- delimiter
02265 **
02266 **  Return value:
02267 **     Number of bytes written to "dstr", or <= 0 on error.
02268 */
02269 
02270 static size_t
02271 dkim_gensighdr(DKIM *dkim, DKIM_SIGINFO *sig, struct dkim_dstring *dstr,
02272                char *delim)
02273 {
02274        _Bool firsthdr;
02275        _Bool nosigner = FALSE;
02276        int n;
02277        int status;
02278        int delimlen;
02279        size_t hashlen;
02280        size_t tmplen;
02281        char *format;
02282        u_char *hash;
02283        struct dkim_header *hdr;
02284        _Bool *always = NULL;
02285        u_char tmp[DKIM_MAXHEADER + 1];
02286        u_char b64hash[DKIM_MAXHEADER + 1];
02287 
02288        assert(dkim != NULL);
02289        assert(sig != NULL);
02290        assert(dstr != NULL);
02291        assert(delim != NULL);
02292 
02293        delimlen = strlen(delim);
02294 
02295        n = dkim->dkim_libhandle->dkiml_nalwayshdrs * sizeof(_Bool);
02296        if (n > 0)
02297        {
02298               always = DKIM_MALLOC(dkim, n);
02299               if (always == NULL)
02300                      return 0;
02301               memset(always, '\0', n);
02302        }
02303 
02304        /* bail if we were asked to generate an invalid signature */
02305        if (dkim->dkim_signer != NULL)
02306        {
02307               _Bool match = FALSE;
02308               u_char *sd;
02309 
02310               sd = strchr(dkim->dkim_signer, '@');
02311               if (sd == NULL)
02312               {
02313                      dkim_error(dkim, "syntax error in signer value");
02314                      return 0;
02315               }
02316 
02317               if (strcasecmp(sd + 1, sig->sig_domain) == 0)
02318               {
02319                      match = TRUE;
02320               }
02321               else
02322               {
02323                      for (sd = strchr(sd + 1, '.');
02324                           sd != NULL && !match;
02325                           sd = strchr(sd + 1, '.'))
02326                      {
02327                             if (strcasecmp(sd + 1, sig->sig_domain) == 0)
02328                                    match = TRUE;
02329                      }
02330               }
02331 
02332               if (!match)
02333               {
02334                      if ((dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_DROPSIGNER) == 0)
02335                      {
02336                             dkim_error(dkim,
02337                                        "d=/i= mismatch on signature generation");
02338                             return 0;
02339                      }
02340                      else
02341                      {
02342                             nosigner = TRUE;
02343                      }
02344               }
02345        }
02346 
02347        /*
02348        **  We need to generate a DKIM-Signature: header template
02349        **  and include it in the canonicalization.
02350        */
02351 
02352        /* basic required stuff */
02353        if (sizeof(sig->sig_timestamp) == sizeof(unsigned long long))
02354               format = "v=%s;%sa=%s;%sc=%s/%s;%sd=%s;%ss=%s;%st=%llu";
02355        else if (sizeof(sig->sig_timestamp) == sizeof(unsigned long))
02356               format = "v=%s;%sa=%s;%sc=%s/%s;%sd=%s;%ss=%s;%st=%lu";
02357        else 
02358               format = "v=%s;%sa=%s;%sc=%s/%s;%sd=%s;%ss=%s;%st=%u";
02359 
02360        tmplen = dkim_dstring_printf(dstr, format,
02361                                     DKIM_VERSION_SIG, delim,
02362                                     dkim_code_to_name(algorithms,
02363                                                       sig->sig_signalg),
02364                                     delim,
02365                                     dkim_code_to_name(canonicalizations,
02366                                                       sig->sig_hdrcanonalg),
02367                                     dkim_code_to_name(canonicalizations,
02368                                                       sig->sig_bodycanonalg),
02369                                     delim,
02370                                     sig->sig_domain, delim,
02371                                     sig->sig_selector, delim,
02372                                     sig->sig_timestamp);
02373 
02374        if (dkim->dkim_libhandle->dkiml_sigttl != 0)
02375        {
02376               uint64_t expire;
02377 
02378               expire = sig->sig_timestamp + dkim->dkim_libhandle->dkiml_sigttl;
02379               if (sizeof(expire) == sizeof(unsigned long long))
02380                      dkim_dstring_printf(dstr, ";%sx=%llu", delim, expire);
02381               else if (sizeof(expire) == sizeof(unsigned long))
02382                      dkim_dstring_printf(dstr, ";%sx=%lu", delim, expire);
02383               else
02384                      dkim_dstring_printf(dstr, ";%sx=%u", delim, expire);
02385        }
02386 
02387        if (dkim->dkim_signer != NULL && !nosigner)
02388        {
02389               dkim_dstring_printf(dstr, ";%si=%s", delim,
02390                                   dkim->dkim_signer);
02391        }
02392 
02393        if (dkim->dkim_xtags != NULL)
02394        {
02395               struct dkim_xtag *x;
02396 
02397               for (x = dkim->dkim_xtags; x != NULL; x = x->xt_next)
02398               {
02399                      dkim_dstring_printf(dstr, ";%s%s=%s", delim,
02400                                          x->xt_tag, x->xt_value);
02401               }
02402        }
02403 
02404        memset(b64hash, '\0', sizeof b64hash);
02405 
02406        status = dkim_canon_closebody(dkim);
02407        if (status != DKIM_STAT_OK)
02408        {
02409               if (always != NULL)
02410                      (void) DKIM_FREE(dkim, always);
02411               return 0;
02412        }
02413 
02414        status = dkim_canon_getfinal(sig->sig_bodycanon, &hash, &hashlen);
02415        if (status != DKIM_STAT_OK)
02416        {
02417               dkim_error(dkim, "dkim_canon_getfinal() failed");
02418               if (always != NULL)
02419                      (void) DKIM_FREE(dkim, always);
02420               return (size_t) -1;
02421        }
02422 
02423        status = dkim_base64_encode(hash, hashlen,
02424                                    b64hash, sizeof b64hash);
02425 
02426        dkim_dstring_printf(dstr, ";%sbh=%s", delim, b64hash);
02427 
02428        /* l= */
02429        if (dkim->dkim_partial)
02430        {
02431               dkim_dstring_printf(dstr, ";%sl=%lu", delim,
02432                                   (u_long) sig->sig_bodycanon->canon_wrote);
02433        }
02434 
02435        /* h= */
02436        for (n = 0; n < dkim->dkim_libhandle->dkiml_nalwayshdrs; n++)
02437               always[n] = TRUE;
02438 
02439        firsthdr = TRUE;
02440 
02441        for (hdr = dkim->dkim_hhead; hdr != NULL; hdr = hdr->hdr_next)
02442        {
02443               if ((hdr->hdr_flags & DKIM_HDR_SIGNED) == 0)
02444                      continue;
02445 
02446               if (!firsthdr)
02447               {
02448                      dkim_dstring_cat1(dstr, ':');
02449               }
02450               else
02451               {
02452                      dkim_dstring_cat1(dstr, ';');
02453                      dkim_dstring_catn(dstr, (u_char *) delim, delimlen);
02454                      dkim_dstring_catn(dstr, (u_char *) "h=", 2);
02455               }
02456 
02457               firsthdr = FALSE;
02458 
02459               dkim_dstring_catn(dstr, hdr->hdr_text, hdr->hdr_namelen);
02460 
02461               if (dkim->dkim_libhandle->dkiml_alwayshdrs != NULL)
02462               {
02463                      u_char **ah = dkim->dkim_libhandle->dkiml_alwayshdrs;
02464 
02465                      for (n = 0; ah[n] != NULL; n++)
02466                      {
02467                             if (strncasecmp((char *) hdr->hdr_text,
02468                                             (char *) ah[n],
02469                                             hdr->hdr_namelen) == 0)
02470                             {
02471                                    always[n] = FALSE;
02472                                    break;
02473                             }
02474                      }
02475               }
02476        }
02477 
02478        /* apply any "always sign" list */
02479        if (dkim->dkim_libhandle->dkiml_alwayshdrs != NULL)
02480        {
02481               u_char **ah = dkim->dkim_libhandle->dkiml_alwayshdrs;
02482 
02483               for (n = 0; ah[n] != NULL; n++)
02484               {
02485                      if (always[n])
02486                      {
02487                             if (!firsthdr)
02488                             {
02489                                    dkim_dstring_cat1(dstr, ':');
02490                             }
02491                             else
02492                             {
02493                                    dkim_dstring_cat1(dstr, ';');
02494                                    dkim_dstring_catn(dstr,
02495                                                      (u_char *) delim,
02496                                                      delimlen);
02497                                    dkim_dstring_catn(dstr,
02498                                                      (u_char *) "h=", 2);
02499                             }
02500 
02501                             firsthdr = FALSE;
02502 
02503                             dkim_dstring_cat(dstr, ah[n]);
02504                      }
02505               }
02506        }
02507 
02508 #ifdef _FFR_OVERSIGN
02509        if (dkim->dkim_libhandle->dkiml_oversignhdrs != NULL)
02510        {
02511               if (firsthdr)
02512               {
02513                      dkim_dstring_cat1(dstr, ';');
02514                      dkim_dstring_catn(dstr, delim, delimlen);
02515                      dkim_dstring_catn(dstr, "h=", 2);
02516               }
02517               else
02518               {
02519                      dkim_dstring_cat1(dstr, ':');
02520               }
02521 
02522               for (n = 0;
02523                    dkim->dkim_libhandle->dkiml_oversignhdrs[n] != NULL;
02524                    n++)
02525               {
02526                      if (n != 0)
02527                             dkim_dstring_cat1(dstr, ':');
02528 
02529                      dkim_dstring_cat(dstr,
02530                                       dkim->dkim_libhandle->dkiml_oversignhdrs[n]);
02531               }
02532        }
02533 #endif /* _FFR_OVERSIGN */
02534 
02535        /* if diagnostic headers were requested, include 'em */
02536        if (dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_ZTAGS)
02537        {
02538               _Bool first;
02539               int status;
02540               size_t len;
02541               u_char *p;
02542               u_char *q;
02543               u_char *end;
02544               u_char *hend;
02545               u_char *colon;
02546               unsigned char name[DKIM_MAXHEADER + 1];
02547 
02548               dkim_dstring_cat1(dstr, ';');
02549               dkim_dstring_catn(dstr, (u_char *) delim, delimlen);
02550               dkim_dstring_catn(dstr, (u_char *) "z=", 2);
02551 
02552               first = TRUE;
02553               end = tmp + sizeof tmp - 1;
02554 
02555               for (hdr = dkim->dkim_hhead; hdr != NULL; hdr = hdr->hdr_next)
02556               {
02557                      /* apply "skip" header and "sign" header lists */
02558                      hend = hdr->hdr_text + hdr->hdr_textlen;
02559                      colon = memchr(hdr->hdr_text, ':', hdr->hdr_textlen);
02560                      if (colon != NULL)
02561                      {
02562                             hend = colon;
02563 
02564                             while (hend > hdr->hdr_text &&
02565                                    isascii(*(hend - 1)) &&
02566                                    isspace(*(hend - 1)))
02567                                    hend--;
02568                      }
02569 
02570                      strlcpy((char *) name, (char *) hdr->hdr_text,
02571                              sizeof name);
02572                      if (hend != NULL)
02573                             name[hend - hdr->hdr_text] = '\0';
02574 
02575                      if (dkim->dkim_libhandle->dkiml_skipre)
02576                      {
02577                             status = regexec(&dkim->dkim_libhandle->dkiml_skiphdrre,
02578                                              (char *) name, 0, NULL, 0);
02579 
02580                             if (status == 0)
02581                                    continue;
02582                             else
02583                                    assert(status == REG_NOMATCH);
02584                      }
02585 
02586                      if (dkim->dkim_libhandle->dkiml_signre)
02587                      {
02588                             status = regexec(&dkim->dkim_libhandle->dkiml_hdrre,
02589                                              (char *) name, 0, NULL, 0);
02590 
02591                             if (status == REG_NOMATCH)
02592                                    continue;
02593                             else
02594                                    assert(status == 0);
02595                      }
02596 
02597                      q = tmp;
02598                      len = 0;
02599 
02600                      if (!first)
02601                      {
02602                             *q = '|';
02603                             q++;
02604                             len++;
02605                      }
02606 
02607                      first = FALSE;
02608 
02609                      for (p = hdr->hdr_text; *p != '\0'; p++)
02610                      {
02611                             if (q >= end)
02612                                    break;
02613 
02614                             if ((*p >= 0x21 && *p <= 0x3a) ||
02615                                 *p == 0x3c ||
02616                                 (*p >= 0x3e && *p <= 0x7e))
02617                             {
02618                                    *q = *p;
02619                                    q++;
02620                                    len++;
02621                             }
02622                             else if (q < end - 4)
02623                             {
02624                                    snprintf((char *) q, 4,
02625                                             "=%02X", *p);
02626                                    q += 3;
02627                                    len += 3;
02628                             }
02629                      }
02630 
02631                      dkim_dstring_catn(dstr, tmp, len);
02632               }
02633        }
02634 
02635        /* and finally, an empty b= */
02636        dkim_dstring_cat1(dstr, ';');
02637        dkim_dstring_catn(dstr, (u_char *) delim, delimlen);
02638        dkim_dstring_catn(dstr, (u_char *) "b=", 2);
02639 
02640        if (always != NULL)
02641               DKIM_FREE(dkim, always);
02642 
02643        return dkim_dstring_len(dstr);
02644 }
02645 
02646 /*
02647 **  DKIM_GETSENDER -- determine sender and store it in the handle
02648 **
02649 **  Parameters:
02650 **     dkim -- DKIM handle
02651 **     hdrs -- list of header names to find
02652 **
02653 **  Return value:
02654 **     A DKIM_STAT_* constant.
02655 */
02656 
02657 static DKIM_STAT
02658 dkim_getsender(DKIM *dkim, u_char **hdrs)
02659 {
02660        int c;
02661        size_t hlen;
02662        DKIM_STAT status;
02663        unsigned char *domain;
02664        unsigned char *user;
02665        struct dkim_header *sender = NULL;
02666        struct dkim_header *cur;
02667 
02668        assert(dkim != NULL);
02669        assert(hdrs != NULL);
02670 
02671        if (dkim->dkim_sender != NULL)
02672               return DKIM_STAT_OK;
02673 
02674        for (c = 0; hdrs[c] != NULL; c++)
02675        {
02676               hlen = strlen((char *) hdrs[c]);
02677 
02678               for (cur = dkim->dkim_hhead; cur != NULL; cur = cur->hdr_next)
02679               {
02680                      if (hlen == cur->hdr_namelen &&
02681                          strncasecmp((char *) hdrs[c],
02682                                      (char *) cur->hdr_text,
02683                                      hlen) == 0)
02684                      {
02685                             sender = cur;
02686                             break;
02687                      }
02688               }
02689        }
02690 
02691        if (sender == NULL)
02692        {
02693               dkim_error(dkim, "no sender headers detected");
02694               return DKIM_STAT_SYNTAX;
02695        }
02696        dkim->dkim_senderhdr = sender;
02697 
02698        if (sender->hdr_colon == NULL)
02699        {
02700               dkim_error(dkim, "syntax error in headers");
02701               return DKIM_STAT_SYNTAX;
02702        }
02703 
02704        dkim->dkim_sender = dkim_strdup(dkim, sender->hdr_colon + 1, 0);
02705        if (dkim->dkim_sender == NULL)
02706               return DKIM_STAT_NORESOURCE;
02707 
02708        status = dkim_mail_parse(dkim->dkim_sender, &user, &domain);
02709        if (status != 0 || domain == NULL || user == NULL ||
02710            domain[0] == '\0' || user[0] == '\0')
02711        {
02712               dkim_error(dkim, "can't determine sender address");
02713               return DKIM_STAT_SYNTAX;
02714        }
02715 
02716        if (dkim->dkim_domain == NULL)
02717        {
02718               dkim->dkim_domain = dkim_strdup(dkim, domain, 0);
02719               if (dkim->dkim_domain == NULL)
02720                      return DKIM_STAT_NORESOURCE;
02721        }
02722 
02723        dkim->dkim_user = dkim_strdup(dkim, user, 0);
02724        if (dkim->dkim_user == NULL)
02725               return DKIM_STAT_NORESOURCE;
02726 
02727        return DKIM_STAT_OK;
02728 }
02729 
02730 /*
02731 **  DKIM_GET_POLICY -- request and parse a domain's policy record
02732 **
02733 **  Parameters:
02734 **     dkim -- DKIM handle
02735 **     query -- string to query
02736 **     excheck -- existence check rather than TXT query
02737 **     qstatus -- query status (returned)
02738 **     policy -- policy found (returned)
02739 **     pflags -- policy flags (returned) (unused)
02740 **
02741 **  Return value:
02742 **     A DKIM_STAT_* constant.
02743 */
02744 
02745 static DKIM_STAT
02746 dkim_get_policy(DKIM *dkim, u_char *query, _Bool excheck, int *qstatus,
02747                 dkim_policy_t *policy, u_int *pflags)
02748 {
02749        int status = 0;
02750        int qstat = NOERROR;
02751        unsigned int lpflags;
02752        dkim_policy_t lpolicy;
02753        DKIM_STAT pstatus;
02754        unsigned char buf[BUFRSZ + 1];
02755 
02756        assert(dkim != NULL);
02757        assert(query != NULL);
02758        assert(qstatus != NULL);
02759        assert(policy != NULL);
02760        assert(pflags != NULL);
02761 
02762        if (dkim->dkim_libhandle->dkiml_policy_lookup != NULL)
02763        {
02764               DKIM_CBSTAT cbstatus;
02765 
02766               cbstatus = dkim->dkim_libhandle->dkiml_policy_lookup(dkim,
02767                                                                    query,
02768                                                                    excheck,
02769                                                                    buf,
02770                                                                    sizeof buf,
02771                                                                    &qstat);
02772 
02773               switch (cbstatus)
02774               {
02775                 case DKIM_CBSTAT_CONTINUE:
02776                      status = 1;
02777                      break;
02778 
02779                 case DKIM_CBSTAT_REJECT:
02780                      return DKIM_STAT_CBREJECT;
02781 
02782                 case DKIM_CBSTAT_TRYAGAIN:
02783                      return DKIM_STAT_CBTRYAGAIN;
02784 
02785                 case DKIM_CBSTAT_NOTFOUND:
02786                      break;
02787 
02788                 case DKIM_CBSTAT_ERROR:
02789                      return DKIM_STAT_CBERROR;
02790 
02791                 default:
02792                      return DKIM_STAT_CBINVALID;
02793               }
02794        }
02795        else
02796        {
02797               switch (dkim->dkim_libhandle->dkiml_querymethod)
02798               {
02799                 case DKIM_QUERY_UNKNOWN:
02800                 case DKIM_QUERY_DNS:
02801                      status = dkim_get_policy_dns(dkim, query, excheck,
02802                                                   buf, sizeof buf, &qstat);
02803                      break;
02804 
02805                 case DKIM_QUERY_FILE:
02806                      status = dkim_get_policy_file(dkim, query, buf,
02807                                                    sizeof buf, &qstat);
02808                      break;
02809 
02810                 default:
02811                      assert(0);
02812                      /* just to silence -Wall */
02813                      return -1;
02814               }
02815        }
02816 
02817        if (status == -1)
02818               return DKIM_STAT_CANTVRFY;
02819        else if (status == 0)
02820               qstat = NXDOMAIN;
02821 
02822        *qstatus = qstat;
02823 
02824        if (!excheck && qstat == NOERROR && status == 1)
02825        {
02826               u_char *p;
02827               struct dkim_set *set;
02828 
02829               pstatus = dkim_process_set(dkim, DKIM_SETTYPE_POLICY,
02830                                          buf, strlen((char *) buf),
02831                                          NULL, FALSE, NULL);
02832               if ((dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_REPORTBADADSP) == 0 &&
02833                   pstatus == DKIM_STAT_SYNTAX)
02834               {
02835                      *policy = DKIM_POLICY_DEFAULT;
02836                      *qstatus = NXDOMAIN;
02837                      *pflags = 0;
02838               }
02839               else if (pstatus != DKIM_STAT_OK)
02840               {
02841                      return pstatus;
02842               }
02843 
02844               lpolicy = DKIM_POLICY_DEFAULT;
02845               lpflags = 0;
02846 
02847               set = dkim_set_first(dkim, DKIM_SETTYPE_POLICY);
02848 
02849               p = dkim_param_get(set, (u_char *) "dkim");
02850               if (p != NULL)
02851                      lpolicy = dkim_name_to_code(policies, (char *) p);
02852 
02853               *policy = lpolicy;
02854               *pflags = lpflags;
02855        }
02856 
02857        return DKIM_STAT_OK;
02858 }
02859 
02860 /*
02861 **  DKIM_GET_KEY -- acquire a public key used for verification
02862 **
02863 **  Parameters:
02864 **     dkim -- DKIM handle
02865 **     sig -- DKIM_SIGINFO handle
02866 **     test -- skip signature-specific validity checks
02867 **
02868 **  Return value:
02869 **     A DKIM_STAT_* constant.
02870 */
02871 
02872 DKIM_STAT
02873 dkim_get_key(DKIM *dkim, DKIM_SIGINFO *sig, _Bool test)
02874 {
02875        _Bool gotkey = FALSE;                     /* key stored */
02876        _Bool gotset = FALSE;                     /* set parsed */
02877        _Bool gotreply = FALSE;                   /* reply received */
02878        int status;
02879        int c;
02880        DKIM_SIGINFO *osig;
02881        struct dkim_set *set = NULL;
02882        struct dkim_set *nextset;
02883        unsigned char *p;
02884        unsigned char buf[BUFRSZ + 1];
02885 
02886        assert(dkim != NULL);
02887        assert(sig != NULL);
02888        assert(sig->sig_selector != NULL);
02889        assert(sig->sig_domain != NULL);
02890 
02891        memset(buf, '\0', sizeof buf);
02892 
02893        /* see if one of the other signatures already has the key we need */
02894        for (c = 0; c < dkim->dkim_sigcount; c++)
02895        {
02896               osig = dkim->dkim_siglist[c];
02897 
02898               /* don't self-search */
02899               if (sig == osig)
02900                      continue;
02901 
02902               /* skip unprocessed signatures */
02903               if ((osig->sig_flags & DKIM_SIGFLAG_PROCESSED) == 0)
02904                      continue;
02905 
02906               /* skip unless selector and domain match */
02907               if (strcmp((char *) osig->sig_domain,
02908                          (char *) sig->sig_domain) != 0 ||
02909                   strcmp((char *) osig->sig_selector,
02910                          (char *) sig->sig_selector) != 0)
02911                      continue;
02912 
02913               /* we got a match!  copy the key data (if any)... */
02914               if (osig->sig_key != NULL)
02915               {
02916                      sig->sig_key = DKIM_MALLOC(dkim, osig->sig_b64keylen);
02917                      if (sig->sig_key == NULL)
02918                      {
02919                             dkim_error(dkim,
02920                                        "unable to allocate %d byte(s)",
02921                                        osig->sig_b64keylen);
02922                             return DKIM_STAT_NORESOURCE;
02923                      }
02924 
02925                      memcpy(sig->sig_key, osig->sig_key,
02926                             osig->sig_b64keylen);
02927 
02928                      sig->sig_keylen = osig->sig_keylen;
02929 
02930                      gotkey = TRUE;
02931               }
02932 
02933               /* ...and the key tag list (if any) */
02934               if (osig->sig_keytaglist != NULL)
02935               {
02936                      sig->sig_keytaglist = osig->sig_keytaglist;
02937                      set = sig->sig_keytaglist;
02938 
02939                      gotset = TRUE;
02940                      gotreply = TRUE;
02941               }
02942 
02943               break;
02944        }
02945 
02946        /* try a local function if there was one defined */
02947        if (!gotkey && dkim->dkim_libhandle->dkiml_key_lookup != NULL)
02948        {
02949               DKIM_CBSTAT cbstatus;
02950 
02951               cbstatus = dkim->dkim_libhandle->dkiml_key_lookup(dkim,
02952                                                                 sig,
02953                                                                 buf,
02954                                                                 sizeof buf);
02955               switch (cbstatus)
02956               {
02957                 case DKIM_CBSTAT_CONTINUE:
02958                      gotreply = TRUE;
02959                      break;
02960 
02961                 case DKIM_CBSTAT_REJECT:
02962                      return DKIM_STAT_CBREJECT;
02963 
02964                 case DKIM_CBSTAT_TRYAGAIN:
02965                      return DKIM_STAT_CBTRYAGAIN;
02966 
02967                 case DKIM_CBSTAT_NOTFOUND:
02968                      return DKIM_STAT_NOKEY;
02969 
02970                 case DKIM_CBSTAT_ERROR:
02971                      return DKIM_STAT_CBERROR;
02972 
02973                 default:
02974                      return DKIM_STAT_CBINVALID;
02975               }
02976        }
02977 
02978        /* if no local function or it returned no result, make the query */
02979        if (!gotreply)
02980        {
02981               /* use appropriate get method */
02982               switch (sig->sig_query)
02983               {
02984                 case DKIM_QUERY_DNS:
02985                      status = (int) dkim_get_key_dns(dkim, sig, buf,
02986                                                      sizeof buf);
02987                      if (status != (int) DKIM_STAT_OK)
02988                             return (DKIM_STAT) status;
02989                      break;
02990 
02991                 case DKIM_QUERY_FILE:
02992                      status = (int) dkim_get_key_file(dkim, sig, buf,
02993                                                       sizeof buf);
02994                      if (status != (int) DKIM_STAT_OK)
02995                             return (DKIM_STAT) status;
02996                      break;
02997 
02998                 default:
02999                      assert(0);
03000               }
03001        }
03002 
03003        /* decode the payload */
03004        if (!gotset)
03005        {
03006               if (buf[0] == '\0')
03007               {
03008                      dkim_error(dkim, "empty key record");
03009                      return DKIM_STAT_SYNTAX;
03010               }
03011 
03012               status = dkim_process_set(dkim, DKIM_SETTYPE_KEY, buf,
03013                                         strlen((char *) buf), NULL, FALSE,
03014                                         NULL);
03015               if (status != DKIM_STAT_OK)
03016                      return status;
03017 
03018               /* get the last key */
03019               set = dkim_set_first(dkim, DKIM_SETTYPE_KEY);
03020               assert(set != NULL);
03021               for (;;)
03022               {
03023                      nextset = dkim_set_next(set, DKIM_SETTYPE_KEY);
03024                      if (nextset == NULL)
03025                             break;
03026                      set = nextset;
03027               }
03028               assert(set != NULL);
03029 
03030               sig->sig_keytaglist = set;
03031        }
03032 
03033        /* verify key version first */
03034        p = dkim_param_get(set, (u_char *) "v");
03035        if (p != NULL && strcmp((char *) p, DKIM_VERSION_KEY) != 0)
03036        {
03037               dkim_error(dkim, "invalid key version '%s'", p);
03038               sig->sig_error = DKIM_SIGERROR_KEYVERSION;
03039               return DKIM_STAT_SYNTAX;
03040        }
03041 
03042        /* then make sure the hash type is something we can handle */
03043        p = dkim_param_get(set, (u_char *) "h");
03044        if (!dkim_key_hashesok(dkim->dkim_libhandle, p))
03045        {
03046               dkim_error(dkim, "unknown hash '%s'", p);
03047               sig->sig_error = DKIM_SIGERROR_KEYUNKNOWNHASH;
03048               return DKIM_STAT_SYNTAX;
03049        }
03050        /* ...and that this key is approved for this signature's hash */
03051        else if (!test && !dkim_key_hashok(sig, p))
03052        {
03053               dkim_error(dkim, "signature-key hash mismatch");
03054               sig->sig_error = DKIM_SIGERROR_KEYHASHMISMATCH;
03055               return DKIM_STAT_CANTVRFY;
03056        }
03057 
03058        /* make sure it's a key designated for e-mail */
03059        if (!dkim_key_smtp(set))
03060        {
03061               dkim_error(dkim, "key type mismatch");
03062               sig->sig_error = DKIM_SIGERROR_NOTEMAILKEY;
03063               return DKIM_STAT_CANTVRFY;
03064        }
03065 
03066        /* then key type */
03067        p = dkim_param_get(set, (u_char *) "k");
03068        if (p == NULL)
03069        {
03070               dkim_error(dkim, "key type missing");
03071               sig->sig_error = DKIM_SIGERROR_KEYTYPEMISSING;
03072               return DKIM_STAT_SYNTAX;
03073        }
03074        else if (dkim_name_to_code(keytypes, (char *) p) == -1)
03075        {
03076               dkim_error(dkim, "unknown key type '%s'", p);
03077               sig->sig_error = DKIM_SIGERROR_KEYTYPEUNKNOWN;
03078               return DKIM_STAT_SYNTAX;
03079        }
03080 
03081        if (!gotkey)
03082        {
03083               /* decode the key */
03084               sig->sig_b64key = dkim_param_get(set, (u_char *) "p");
03085               if (sig->sig_b64key == NULL)
03086               {
03087                      dkim_error(dkim, "key missing");
03088                      return DKIM_STAT_SYNTAX;
03089               }
03090               else if (sig->sig_b64key[0] == '\0')
03091               {
03092                      return DKIM_STAT_REVOKED;
03093               }
03094               sig->sig_b64keylen = strlen((char *) sig->sig_b64key);
03095 
03096               sig->sig_key = DKIM_MALLOC(dkim, sig->sig_b64keylen);
03097               if (sig->sig_key == NULL)
03098               {
03099                      dkim_error(dkim, "unable to allocate %d byte(s)",
03100                                 sig->sig_b64keylen);
03101                      return DKIM_STAT_NORESOURCE;
03102               }
03103 
03104               status = dkim_base64_decode(sig->sig_b64key, sig->sig_key,
03105                                           sig->sig_b64keylen);
03106               if (status < 0)
03107               {
03108                      dkim_error(dkim, "key missing");
03109                      return DKIM_STAT_SYNTAX;
03110               }
03111 
03112               sig->sig_keylen = status;
03113        }
03114 
03115        /* store key flags */
03116        p = dkim_param_get(set, (u_char *) "t");
03117        if (p != NULL)
03118        {
03119               u_int flag;
03120               char *t;
03121               char *last;
03122               char tmp[BUFRSZ + 1];
03123 
03124               strlcpy(tmp, (char *) p, sizeof tmp);
03125 
03126               for (t = strtok_r(tmp, ":", &last);
03127                    t != NULL;
03128                    t = strtok_r(NULL, ":", &last))
03129               {
03130                      flag = (u_int) dkim_name_to_code(keyflags, t);
03131                      if (flag != (u_int) -1)
03132                             sig->sig_flags |= flag;
03133               }
03134        }
03135 
03136        return DKIM_STAT_OK;
03137 }
03138 
03139 /*
03140 **  DKIM_HEADERCHECK -- check header validity
03141 **
03142 **  Parameters:
03143 **     dkim -- DKIM handle
03144 **
03145 **  Return value:
03146 **     TRUE iff the header meets sanity checks.
03147 */
03148 
03149 static _Bool
03150 dkim_headercheck(DKIM *dkim)
03151 {
03152        struct dkim_header *hdr;
03153 
03154        assert(dkim != NULL);
03155 
03156        if ((dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_STRICTHDRS) != 0)
03157        {
03158               /* Date (must be exactly one) */
03159               hdr = dkim_get_header(dkim, "Date", 4, 0);
03160               if (hdr == NULL)
03161               {
03162                      dkim_error(dkim, "Date: header field absent");
03163                      return FALSE;
03164               }
03165 
03166               hdr = dkim_get_header(dkim, "Date", 4, 1);
03167               if (hdr != NULL)
03168               {
03169                      dkim_error(dkim,
03170                                 "multiple Date: header fields present");
03171                      return FALSE;
03172               }
03173 
03174               /* From (must be exactly one) */
03175               hdr = dkim_get_header(dkim, "From", 4, 0);
03176               if (hdr == NULL)
03177               {
03178                      dkim_error(dkim, "From: header field absent");
03179                      return FALSE;
03180               }
03181 
03182               hdr = dkim_get_header(dkim, "From", 4, 1);
03183               if (hdr != NULL)
03184               {
03185                      dkim_error(dkim,
03186                                 "multiple From: header fields present");
03187                      return FALSE;
03188               }
03189 
03190               /* Sender (no more than one) */
03191               hdr = dkim_get_header(dkim, "Sender", 6, 1);
03192               if (hdr != NULL)
03193               {
03194                      dkim_error(dkim,
03195                                 "multiple Sender: header fields present");
03196                      return FALSE;
03197               }
03198 
03199               /* Reply-To (no more than one) */
03200               hdr = dkim_get_header(dkim, "Reply-To", 8, 1);
03201               if (hdr != NULL)
03202               {
03203                      dkim_error(dkim,
03204                                 "multiple Reply-To: header fields present");
03205                      return FALSE;
03206               }
03207 
03208               /* To (no more than one) */
03209               hdr = dkim_get_header(dkim, "To", 2, 1);
03210               if (hdr != NULL)
03211               {
03212                      dkim_error(dkim,
03213                                 "multiple To: header fields present");
03214                      return FALSE;
03215               }
03216 
03217               /* Cc (no more than one) */
03218               hdr = dkim_get_header(dkim, "Cc", 2, 1);
03219               if (hdr != NULL)
03220               {
03221                      dkim_error(dkim,
03222                                 "multiple Cc: header fields present");
03223                      return FALSE;
03224               }
03225 
03226               /* Bcc (should we even bother?) */
03227               hdr = dkim_get_header(dkim, "Bcc", 3, 1);
03228               if (hdr != NULL)
03229               {
03230                      dkim_error(dkim,
03231                                 "multiple Bcc: header fields present");
03232                      return FALSE;
03233               }
03234 
03235               /* Message-ID (no more than one) */
03236               hdr = dkim_get_header(dkim, "Message-ID", 10, 1);
03237               if (hdr != NULL)
03238               {
03239                      dkim_error(dkim,
03240                                 "multiple Message-ID: header fields present");
03241                      return FALSE;
03242               }
03243 
03244               /* In-Reply-To (no more than one) */
03245               hdr = dkim_get_header(dkim, "In-Reply-To", 11, 1);
03246               if (hdr != NULL)
03247               {
03248                      dkim_error(dkim,
03249                                 "multiple In-Reply-To: header fields present");
03250                      return FALSE;
03251               }
03252 
03253               /* References (no more than one) */
03254               hdr = dkim_get_header(dkim, "References", 10, 1);
03255               if (hdr != NULL)
03256               {
03257                      dkim_error(dkim,
03258                                 "multiple References: header fields present");
03259                      return FALSE;
03260               }
03261 
03262               /* Subject (no more than one) */
03263               hdr = dkim_get_header(dkim, "Subject", 7, 1);
03264               if (hdr != NULL)
03265               {
03266                      dkim_error(dkim,
03267                                 "multiple Subject: header fields present");
03268                      return FALSE;
03269               }
03270        }
03271 
03272        return TRUE;
03273 }
03274 
03275 /*
03276 **  DKIM_EOH_SIGN -- declare end-of-headers; prepare for signing
03277 ** 
03278 **  Parameters:
03279 **     dkim -- DKIM handle
03280 **
03281 **  Return value:
03282 **     A DKIM_STAT_* constant.
03283 */
03284 
03285 static DKIM_STAT
03286 dkim_eoh_sign(DKIM *dkim)
03287 {
03288        _Bool keep;
03289        _Bool tmp;
03290        u_char *hn = NULL;
03291        DKIM_STAT status;
03292        int hashtype = DKIM_HASHTYPE_UNKNOWN;
03293        DKIM_CANON *bc;
03294        DKIM_CANON *hc;
03295        DKIM_LIB *lib;
03296 
03297        assert(dkim != NULL);
03298 
03299 #ifdef _FFR_RESIGN
03300        if (dkim->dkim_hdrbind)
03301               return DKIM_STAT_INVALID;
03302 #endif /* _FFR_RESIGN */
03303 
03304        if (dkim->dkim_state >= DKIM_STATE_EOH2)
03305               return DKIM_STAT_INVALID;
03306        if (dkim->dkim_state < DKIM_STATE_EOH2)
03307               dkim->dkim_state = DKIM_STATE_EOH2;
03308 
03309        lib = dkim->dkim_libhandle;
03310        assert(lib != NULL);
03311 
03312        tmp = ((lib->dkiml_flags & DKIM_LIBFLAGS_TMPFILES) != 0);
03313        keep = ((lib->dkiml_flags & DKIM_LIBFLAGS_KEEPFILES) != 0);
03314 
03315        dkim->dkim_version = lib->dkiml_version;
03316 
03317        /* check for header validity */
03318        if (!dkim_headercheck(dkim))
03319        {
03320               dkim->dkim_state = DKIM_STATE_UNUSABLE;
03321               return DKIM_STAT_SYNTAX;
03322        }
03323 
03324        /*
03325        **  Verify that all the required headers are present and
03326        **  marked for signing.
03327        */
03328 
03329        hn = (u_char *) dkim_check_requiredhdrs(dkim);
03330        if (hn != NULL)
03331        {
03332               dkim_error(dkim, "required header \"%s\" not found", hn);
03333               dkim->dkim_state = DKIM_STATE_UNUSABLE;
03334               return DKIM_STAT_SYNTAX;
03335        }
03336 
03337        /* determine hash type */
03338        switch (dkim->dkim_signalg)
03339        {
03340          case DKIM_SIGN_RSASHA1:
03341               hashtype = DKIM_HASHTYPE_SHA1;
03342               break;
03343 
03344          case DKIM_SIGN_RSASHA256:
03345               hashtype = DKIM_HASHTYPE_SHA256;
03346               break;
03347 
03348          default:
03349               assert(0);
03350               /* NOTREACHED */
03351        }
03352 
03353        if (dkim->dkim_siglist == NULL)
03354        {
03355               /* initialize signature and canonicalization for signing */
03356               dkim->dkim_siglist = DKIM_MALLOC(dkim, sizeof(DKIM_SIGINFO **));
03357               if (dkim->dkim_siglist == NULL)
03358               {
03359                      dkim_error(dkim, "failed to allocate %d byte(s)",
03360                                 sizeof(DKIM_SIGINFO *));
03361                      return DKIM_STAT_NORESOURCE;
03362               }
03363 
03364               dkim->dkim_siglist[0] = DKIM_MALLOC(dkim,
03365                                                   sizeof(struct dkim_siginfo));
03366               if (dkim->dkim_siglist[0] == NULL)
03367               {
03368                      dkim_error(dkim, "failed to allocate %d byte(s)",
03369                                 sizeof(struct dkim_siginfo));
03370                      return DKIM_STAT_NORESOURCE;
03371               }
03372               dkim->dkim_sigcount = 1;
03373               memset(dkim->dkim_siglist[0], '\0',
03374                      sizeof(struct dkim_siginfo));
03375               dkim->dkim_siglist[0]->sig_domain = dkim->dkim_domain;
03376               dkim->dkim_siglist[0]->sig_selector = dkim->dkim_selector;
03377               dkim->dkim_siglist[0]->sig_hashtype = hashtype;
03378               dkim->dkim_siglist[0]->sig_signalg = dkim->dkim_signalg;
03379 
03380               status = dkim_add_canon(dkim, TRUE, dkim->dkim_hdrcanonalg,
03381                                       hashtype, NULL, NULL, 0, &hc);
03382               if (status != DKIM_STAT_OK)
03383                      return status;
03384 
03385               status = dkim_add_canon(dkim, FALSE, dkim->dkim_bodycanonalg,
03386                                       hashtype, NULL, NULL,
03387                                       dkim->dkim_signlen, &bc);
03388               if (status != DKIM_STAT_OK)
03389                      return status;
03390 
03391               dkim->dkim_siglist[0]->sig_hdrcanon = hc;
03392               dkim->dkim_siglist[0]->sig_hdrcanonalg = dkim->dkim_hdrcanonalg;
03393               dkim->dkim_siglist[0]->sig_bodycanon = bc;
03394               dkim->dkim_siglist[0]->sig_bodycanonalg = dkim->dkim_bodycanonalg;
03395 
03396               if (dkim->dkim_libhandle->dkiml_fixedtime != 0)
03397               {
03398                      dkim->dkim_siglist[0]->sig_timestamp = dkim->dkim_libhandle->dkiml_fixedtime;
03399               }
03400               else
03401               {
03402                      time_t now;
03403 
03404                      (void) time(&now);
03405 
03406                      dkim->dkim_siglist[0]->sig_timestamp = (uint64_t) now;
03407               }
03408        }
03409 
03410        /* initialize all canonicalizations */
03411        status = dkim_canon_init(dkim, tmp, keep);
03412        if (status != DKIM_STAT_OK)
03413               return status;
03414 
03415        /* run the headers */
03416        status = dkim_canon_runheaders(dkim);
03417        if (status != DKIM_STAT_OK)
03418               return status;
03419 
03420        return DKIM_STAT_OK;
03421 }
03422 
03423 /*
03424 **  DKIM_EOH_VERIFY -- declare end-of-headers; set up verification
03425 ** 
03426 **  Parameters:
03427 **     dkim -- DKIM handle
03428 **
03429 **  Return value:
03430 **     A DKIM_STAT_* constant.
03431 */
03432 
03433 static DKIM_STAT
03434 dkim_eoh_verify(DKIM *dkim)
03435 {
03436        _Bool keep;
03437        _Bool tmp;
03438        _Bool bsh;
03439        DKIM_STAT status;
03440        int c;
03441        DKIM_LIB *lib;
03442        DKIM_SET *set;
03443 
03444        assert(dkim != NULL);
03445 
03446        if (dkim->dkim_state >= DKIM_STATE_EOH2)
03447               return DKIM_STAT_INVALID;
03448        if (dkim->dkim_state < DKIM_STATE_EOH1)
03449               dkim->dkim_state = DKIM_STATE_EOH1;
03450 
03451        lib = dkim->dkim_libhandle;
03452        assert(lib != NULL);
03453 
03454        bsh = ((lib->dkiml_flags & DKIM_LIBFLAGS_BADSIGHANDLES) != 0);
03455        tmp = ((lib->dkiml_flags & DKIM_LIBFLAGS_TMPFILES) != 0);
03456        keep = ((lib->dkiml_flags & DKIM_LIBFLAGS_KEEPFILES) != 0);
03457 
03458        /* populate some stuff like dkim_sender, dkim_domain, dkim_user */
03459        status = dkim_getsender(dkim, dkim->dkim_libhandle->dkiml_senderhdrs);
03460        if (status != DKIM_STAT_OK && !bsh)
03461        {
03462               dkim->dkim_state = DKIM_STATE_UNUSABLE;
03463               return status;
03464        }
03465 
03466        /* check for header validity */
03467        if (!dkim_headercheck(dkim))
03468        {
03469               dkim->dkim_state = DKIM_STATE_UNUSABLE;
03470               return DKIM_STAT_SYNTAX;
03471        }
03472 
03473        /* allocate the siginfo array if not already done */
03474        if (dkim->dkim_siglist == NULL)
03475        {
03476               /* count the signatures */
03477               for (set = dkim_set_first(dkim, DKIM_SETTYPE_SIGNATURE);
03478                    set != NULL;
03479                    set = dkim_set_next(set, DKIM_SETTYPE_SIGNATURE))
03480               {
03481                      if (!set->set_bad || bsh)
03482                             dkim->dkim_sigcount++;
03483               }
03484 
03485               /* if no signatures, return such */
03486               if (dkim->dkim_sigcount == 0)
03487               {
03488                      dkim->dkim_skipbody = TRUE;
03489                      return DKIM_STAT_NOSIG;
03490               }
03491 
03492               status = dkim_siglist_setup(dkim);
03493               if (status != DKIM_STAT_OK)
03494                      return status;
03495 
03496               /* initialize all discovered canonicalizations */
03497               status = dkim_canon_init(dkim, tmp, keep);
03498               if (status != DKIM_STAT_OK)
03499                      return status;
03500        }
03501 
03502        /* call the prescreen callback, if defined */
03503        if (lib->dkiml_prescreen != NULL && !dkim->dkim_eoh_reentry)
03504        {
03505               status = lib->dkiml_prescreen(dkim,
03506                                             dkim->dkim_siglist,
03507                                             dkim->dkim_sigcount);
03508               switch (status)
03509               {
03510                 case DKIM_CBSTAT_CONTINUE:
03511                      break;
03512 
03513                 case DKIM_CBSTAT_REJECT:
03514                      return DKIM_STAT_CBREJECT;
03515 
03516                 case DKIM_CBSTAT_TRYAGAIN:
03517                      return DKIM_STAT_CBTRYAGAIN;
03518 
03519                 case DKIM_CBSTAT_ERROR:
03520                      return DKIM_STAT_CBERROR;
03521 
03522                 default:
03523                      return DKIM_STAT_CBINVALID;
03524               }
03525        }
03526 
03527        dkim->dkim_state = DKIM_STATE_EOH2;
03528 
03529        /* if set to ignore everything, treat message as unsigned */
03530        set = NULL;
03531        for (c = 0; c < dkim->dkim_sigcount; c++)
03532        {
03533               if (!(dkim->dkim_siglist[c]->sig_flags & DKIM_SIGFLAG_IGNORE))
03534               {
03535                      set = dkim->dkim_siglist[c]->sig_taglist;
03536                      break;
03537               }
03538        }
03539 
03540        if (set == NULL)
03541        {
03542               dkim->dkim_skipbody = TRUE;
03543               return DKIM_STAT_NOSIG;
03544        }
03545 
03546        /* run the headers */
03547        if (!dkim->dkim_eoh_reentry)
03548        {
03549               status = dkim_canon_runheaders(dkim);
03550               if (status != DKIM_STAT_OK)
03551                      return status;
03552        }
03553 
03554        /* do public key verification of all still-enabled signatures here */
03555        if ((lib->dkiml_flags & DKIM_LIBFLAGS_DELAYSIGPROC) == 0)
03556        {
03557               for (c = 0; c < dkim->dkim_sigcount; c++)
03558               {
03559                      if (!(dkim->dkim_siglist[c]->sig_flags & DKIM_SIGFLAG_PROCESSED) &&
03560                          !(dkim->dkim_siglist[c]->sig_flags & DKIM_SIGFLAG_IGNORE) &&
03561                          dkim->dkim_siglist[c]->sig_error == DKIM_SIGERROR_UNKNOWN)
03562                      {
03563                             status = dkim_sig_process(dkim,
03564                                                       dkim->dkim_siglist[c]);
03565                             if (status != DKIM_STAT_OK)
03566                             {
03567                                    if (status == DKIM_STAT_CBTRYAGAIN)
03568                                           dkim->dkim_eoh_reentry = TRUE;
03569 
03570                                    return status;
03571                             }
03572                      }
03573               }
03574        }
03575 
03576        /*
03577        **  Possible short-circuit here if all signatures are:
03578        **  - marked to be ignored
03579        **  - definitely invalid
03580        **  - verification attempted but failed
03581        */
03582 
03583        if ((lib->dkiml_flags & DKIM_LIBFLAGS_EOHCHECK) != 0)
03584        {
03585               _Bool good = FALSE;
03586               DKIM_SIGINFO *sig;
03587 
03588               for (c = 0; c < dkim->dkim_sigcount; c++)
03589               {
03590                      sig = dkim->dkim_siglist[c];
03591 
03592                      /* ignored? */
03593                      if ((sig->sig_flags & DKIM_SIGFLAG_IGNORE) != 0)
03594                             continue;
03595 
03596                      /* had a processing error? */
03597                      if (sig->sig_error != DKIM_SIGERROR_UNKNOWN &&
03598                          sig->sig_error != DKIM_SIGERROR_OK)
03599                             continue;
03600 
03601                      /* processed but didn't pass? */
03602                      if ((sig->sig_flags & DKIM_SIGFLAG_PROCESSED) != 0 &&
03603                          (sig->sig_flags & DKIM_SIGFLAG_PASSED) == 0)
03604                             continue;
03605 
03606                      /* OK we had a good one */
03607                      good = TRUE;
03608                      break;
03609               }
03610 
03611               /* no good ones */
03612               if (!good)
03613               {
03614                      /* report error on the last one */
03615                      if (sig->sig_error != DKIM_SIGERROR_UNKNOWN &&
03616                          sig->sig_error != DKIM_SIGERROR_OK)
03617                      {
03618                             dkim_error(dkim,
03619                                        dkim_code_to_name(sigerrors,
03620                                                          sig->sig_error));
03621                      }
03622 
03623                      return DKIM_STAT_CANTVRFY;
03624               }
03625        }
03626 
03627        return DKIM_STAT_OK;
03628 }
03629 
03630 /*
03631 **  DKIM_EOM_SIGN -- declare end-of-body; complete signing
03632 **
03633 **  Parameters:
03634 **     dkim -- DKIM handle
03635 **
03636 **  Return value:
03637 **     A DKIM_STAT_* constant.
03638 */
03639 
03640 static DKIM_STAT
03641 dkim_eom_sign(DKIM *dkim)
03642 {
03643        int status;
03644        u_int l;
03645        size_t diglen;
03646        size_t siglen = 0;
03647        size_t len;
03648        DKIM_STAT ret;
03649        u_char *digest;
03650        u_char *sighdr;
03651        u_char *signature = NULL;
03652        DKIM_SIGINFO *sig;
03653        DKIM_CANON *hc;
03654        struct dkim_dstring *tmphdr;
03655        struct dkim_rsa *rsa = NULL;
03656        struct dkim_header hdr;
03657 
03658        assert(dkim != NULL);
03659 
03660 #ifdef _FFR_RESIGN
03661        if (dkim->dkim_resign != NULL)
03662        {
03663               if (dkim->dkim_hdrbind)
03664               {
03665                      if (dkim->dkim_state != DKIM_STATE_INIT ||
03666                          dkim->dkim_resign->dkim_state != DKIM_STATE_EOM2)
03667                             return DKIM_STAT_INVALID;
03668               }
03669               else
03670               {
03671                      if (dkim->dkim_state < DKIM_STATE_EOH1 ||
03672                          dkim->dkim_resign->dkim_state != DKIM_STATE_EOM2)
03673                             return DKIM_STAT_INVALID;
03674               }
03675        }
03676        else if (dkim->dkim_state >= DKIM_STATE_EOM2 ||
03677                 dkim->dkim_state < DKIM_STATE_EOH1)
03678        {
03679               return DKIM_STAT_INVALID;
03680        }
03681 #else /* _FFR_RESIGN */
03682        if (dkim->dkim_state >= DKIM_STATE_EOM2 ||
03683            dkim->dkim_state < DKIM_STATE_EOH1)
03684               return DKIM_STAT_INVALID;
03685 #endif /* _FFR_RESIGN */
03686 
03687        if (dkim->dkim_chunkstate != DKIM_CHUNKSTATE_INIT &&
03688            dkim->dkim_chunkstate != DKIM_CHUNKSTATE_DONE)
03689               return DKIM_STAT_INVALID;
03690 
03691        if (dkim->dkim_state < DKIM_STATE_EOM2)
03692               dkim->dkim_state = DKIM_STATE_EOM2;
03693 
03694 #ifdef _FFR_RESIGN
03695        /*
03696        **  Verify that all the required headers are present and
03697        **  marked for signing.
03698        */
03699 
03700        if (dkim->dkim_resign != NULL)
03701        {
03702               char *hn;
03703 
03704               if (dkim->dkim_hdrbind)
03705                      dkim->dkim_hhead = dkim->dkim_resign->dkim_hhead;
03706 
03707               hn = (u_char *) dkim_check_requiredhdrs(dkim);
03708               if (hn != NULL)
03709               {
03710                      dkim_error(dkim, "required header \"%s\" not found",
03711                                 hn);
03712                      dkim->dkim_state = DKIM_STATE_UNUSABLE;
03713                      return DKIM_STAT_SYNTAX;
03714               }
03715        }
03716 #endif /* _FFR_RESIGN */
03717 
03718        /* finalize body canonicalizations */
03719        status = dkim_canon_closebody(dkim);
03720        if (status != DKIM_STAT_OK)
03721               return status;
03722 
03723        dkim->dkim_bodydone = TRUE;
03724 
03725        /* set signature timestamp */
03726        if (dkim->dkim_libhandle->dkiml_fixedtime != 0)
03727        {
03728               dkim->dkim_timestamp = dkim->dkim_libhandle->dkiml_fixedtime;
03729        }
03730        else
03731        {
03732               time_t now;
03733 
03734               (void) time(&now);
03735               dkim->dkim_timestamp = (uint64_t) now;
03736        }
03737 
03738        /* sign with l= if requested */
03739        if ((dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_SIGNLEN) != 0)
03740               dkim->dkim_partial = TRUE;
03741 
03742        /* get signature and canonicalization handles */
03743        assert(dkim->dkim_siglist != NULL);
03744        assert(dkim->dkim_siglist[0] != NULL);
03745        sig = dkim->dkim_siglist[0];
03746        hc = sig->sig_hdrcanon;
03747 
03748        if (dkim->dkim_keydata == NULL)
03749        {
03750               if (dkim_privkey_load(dkim) != DKIM_STAT_OK)
03751                      return DKIM_STAT_NORESOURCE;
03752        }
03753 
03754        rsa = dkim->dkim_keydata;
03755 #ifdef USE_GNUTLS
03756        if (rsa->rsa_privkey == NULL)
03757 #else /* USE_GNUTLS */
03758        if (rsa->rsa_rsa == NULL)
03759 #endif /* USE_GNUTLS */
03760        {
03761               dkim_error(dkim, "private key load failed");
03762               return DKIM_STAT_NORESOURCE;
03763        }
03764 
03765        sig->sig_keybits = rsa->rsa_keysize;
03766        sig->sig_signature = dkim->dkim_keydata;
03767        sig->sig_flags |= DKIM_SIGFLAG_KEYLOADED;
03768 
03769        switch (sig->sig_signalg)
03770        {
03771          case DKIM_SIGN_RSASHA1:
03772          case DKIM_SIGN_RSASHA256:
03773          {
03774               assert(sig->sig_hashtype == DKIM_HASHTYPE_SHA1 ||
03775                      sig->sig_hashtype == DKIM_HASHTYPE_SHA256);
03776 
03777               if (sig->sig_hashtype == DKIM_HASHTYPE_SHA256)
03778               {
03779                      assert(dkim_libfeature(dkim->dkim_libhandle,
03780                                              DKIM_FEATURE_SHA256));
03781               }
03782 
03783               sig->sig_signature = (void *) dkim->dkim_keydata;
03784               sig->sig_keytype = DKIM_KEYTYPE_RSA;
03785 
03786               break;
03787          }
03788 
03789          default:
03790               assert(0);
03791        }
03792 
03793        /* construct the DKIM signature header to be canonicalized */
03794        tmphdr = dkim_dstring_new(dkim, BUFRSZ, MAXBUFRSZ);
03795        if (tmphdr == NULL)
03796               return DKIM_STAT_NORESOURCE;
03797 
03798        dkim_dstring_catn(tmphdr, (u_char *) DKIM_SIGNHEADER ": ",
03799                          sizeof DKIM_SIGNHEADER + 1);
03800 
03801        ret = dkim_getsighdr_d(dkim, dkim_dstring_len(tmphdr), &sighdr, &len);
03802        if (ret != DKIM_STAT_OK)
03803        {
03804               dkim_dstring_free(tmphdr);
03805               return ret;
03806        }
03807 
03808        dkim_dstring_catn(tmphdr, sighdr, len);
03809        len = dkim_dstring_len(tmphdr);
03810 
03811        hdr.hdr_text = dkim_dstring_get(tmphdr);
03812        hdr.hdr_colon = hdr.hdr_text + DKIM_SIGNHEADER_LEN;
03813        hdr.hdr_namelen = DKIM_SIGNHEADER_LEN;
03814        hdr.hdr_textlen = len;
03815        hdr.hdr_flags = 0;
03816        hdr.hdr_next = NULL;
03817 
03818        /* canonicalize */
03819 #ifdef _FFR_RESIGN
03820        if (dkim->dkim_resign != NULL && dkim->dkim_hdrbind)
03821               dkim->dkim_canonhead = dkim->dkim_resign->dkim_canonhead;
03822 #endif /* _FFR_RESIGN */
03823        dkim_canon_signature(dkim, &hdr);
03824 
03825        dkim_dstring_free(tmphdr);
03826 
03827        /* finalize */
03828        ret = dkim_canon_getfinal(hc, &digest, &diglen);
03829        if (ret != DKIM_STAT_OK)
03830        {
03831               dkim_error(dkim, "dkim_canon_getfinal() failed");
03832               return DKIM_STAT_INTERNAL;
03833        }
03834 
03835        /* compute and store the signature */
03836        switch (sig->sig_signalg)
03837        {
03838 #ifdef USE_GNUTLS
03839          case DKIM_SIGN_RSASHA1:
03840          case DKIM_SIGN_RSASHA256:
03841          {
03842               int alg;
03843               gnutls_datum_t dd;
03844               struct dkim_rsa *rsa;
03845 
03846               rsa = (struct dkim_rsa *) sig->sig_signature;
03847 
03848               dd.data = digest;
03849               dd.size = diglen;
03850 
03851               if (sig->sig_signalg == DKIM_SIGN_RSASHA1)
03852                      alg = GNUTLS_DIG_SHA1;
03853               else
03854                      alg = GNUTLS_DIG_SHA256;
03855 
03856               status = gnutls_privkey_sign_hash(rsa->rsa_privkey, alg, 0,
03857                                                 &dd, &rsa->rsa_rsaout);
03858               if (status != GNUTLS_E_SUCCESS)
03859               {
03860                      dkim_error(dkim,
03861                                 "signature generation failed (status %d)",
03862                                 status);
03863                      return DKIM_STAT_INTERNAL;
03864               }
03865 
03866               signature = rsa->rsa_rsaout.data;
03867               siglen = rsa->rsa_rsaout.size;
03868 
03869               break;
03870          }
03871 #else /* USE_GNUTLS */
03872          case DKIM_SIGN_RSASHA1:
03873          case DKIM_SIGN_RSASHA256:
03874          {
03875               int nid;
03876               struct dkim_rsa *rsa;
03877 
03878               rsa = (struct dkim_rsa *) sig->sig_signature;
03879 
03880               nid = NID_sha1;
03881 
03882               if (dkim_libfeature(dkim->dkim_libhandle,
03883                                   DKIM_FEATURE_SHA256) &&
03884                   sig->sig_hashtype == DKIM_HASHTYPE_SHA256)
03885                      nid = NID_sha256;
03886 
03887               status = RSA_sign(nid, digest, diglen,
03888                                  rsa->rsa_rsaout, &l, rsa->rsa_rsa);
03889               if (status != 1 || l == 0)
03890               {
03891                      RSA_free(rsa->rsa_rsa);
03892                      rsa->rsa_rsa = NULL;
03893                      BIO_free(rsa->rsa_keydata);
03894                      rsa->rsa_keydata = NULL;
03895                      dkim_error(dkim,
03896                                 "signature generation failed (status %d, length %d)",
03897                                 status, l);
03898                      return DKIM_STAT_INTERNAL;
03899               }
03900 
03901               rsa->rsa_rsaoutlen = l;
03902 
03903               signature = rsa->rsa_rsaout;
03904               siglen = rsa->rsa_rsaoutlen;
03905 
03906               break;
03907          }
03908 #endif /* USE_GNUTLS */
03909 
03910          default:
03911               assert(0);
03912        }
03913 
03914        /* base64-encode the signature */
03915        dkim->dkim_b64siglen = siglen * 3 + 5;
03916        dkim->dkim_b64siglen += (dkim->dkim_b64siglen / 60);
03917        dkim->dkim_b64sig = DKIM_MALLOC(dkim, dkim->dkim_b64siglen);
03918        if (dkim->dkim_b64sig == NULL)
03919        {
03920               dkim_error(dkim, "unable to allocate %d byte(s)",
03921                          dkim->dkim_b64siglen);
03922 #ifndef USE_GNUTLS
03923               BIO_free(rsa->rsa_keydata);
03924               rsa->rsa_keydata = NULL;
03925 #endif /* ! USE_GNUTLS */
03926               return DKIM_STAT_NORESOURCE;
03927        }
03928        memset(dkim->dkim_b64sig, '\0', dkim->dkim_b64siglen);
03929 
03930        status = dkim_base64_encode(signature, siglen, dkim->dkim_b64sig,
03931                                    dkim->dkim_b64siglen);
03932 
03933 #ifndef USE_GNUTLS
03934        BIO_free(rsa->rsa_keydata);
03935        rsa->rsa_keydata = NULL;
03936 #endif /* ! USE_GNUTLS */
03937 
03938        if (status == -1)
03939        {
03940               dkim_error(dkim,
03941                          "base64 encoding error (buffer too small)");
03942               return DKIM_STAT_NORESOURCE;
03943        }
03944 
03945        dkim->dkim_signature = sig;
03946 
03947        return DKIM_STAT_OK;
03948 }
03949 
03950 /*
03951 **  DKIM_EOM_VERIFY -- declare end-of-body; complete verification
03952 **
03953 **  Parameters:
03954 **     dkim -- DKIM handle
03955 **     testkey -- TRUE iff the a matching key was found but is marked as a
03956 **                test key (returned)
03957 **
03958 **  Return value:
03959 **     A DKIM_STAT_* constant.
03960 */
03961 
03962 static DKIM_STAT
03963 dkim_eom_verify(DKIM *dkim, _Bool *testkey)
03964 {
03965        DKIM_STAT ret;
03966        int c;
03967        int status;
03968        DKIM_SIGINFO *sig = NULL;
03969        struct dkim_header *hdr;
03970        DKIM_LIB *lib;
03971 
03972        assert(dkim != NULL);
03973 
03974        if (dkim->dkim_state >= DKIM_STATE_EOM2 ||
03975            dkim->dkim_state < DKIM_STATE_EOH1)
03976               return DKIM_STAT_INVALID;
03977        if (dkim->dkim_state < DKIM_STATE_EOM1)
03978               dkim->dkim_state = DKIM_STATE_EOM1;
03979 
03980        if (dkim->dkim_chunkstate != DKIM_CHUNKSTATE_INIT &&
03981            dkim->dkim_chunkstate != DKIM_CHUNKSTATE_DONE)
03982               return DKIM_STAT_INVALID;
03983 
03984        /* finalize body canonicalizations */
03985        ret = dkim_canon_closebody(dkim);
03986        if (ret != DKIM_STAT_OK)
03987               return ret;
03988 
03989        dkim->dkim_bodydone = TRUE;
03990 
03991        if (dkim->dkim_sigcount == 0)
03992        {                                  /* unsigned */
03993               if (dkim->dkim_domain == NULL)
03994               {
03995                      u_char *domain;
03996                      u_char *user;
03997 
03998                      hdr = dkim_get_header(dkim, (u_char *) DKIM_FROMHEADER,
03999                                            DKIM_FROMHEADER_LEN, 0);
04000                      if (hdr == NULL)
04001                      {
04002                             dkim_error(dkim, "no %s header found",
04003                                        DKIM_FROMHEADER);
04004                             return DKIM_STAT_CANTVRFY;
04005                      }
04006 
04007                      if (hdr->hdr_colon == NULL)
04008                      {
04009                             dkim_error(dkim, "%s header malformed",
04010                                        DKIM_FROMHEADER);
04011                             return DKIM_STAT_CANTVRFY;
04012                      }
04013 
04014                      status = dkim_mail_parse(hdr->hdr_colon + 1,
04015                                               &user, &domain);
04016                      if (status != 0 || domain == NULL || domain[0] == '\0')
04017                      {
04018                             dkim_error(dkim, "%s header malformed",
04019                                        DKIM_FROMHEADER);
04020                             return DKIM_STAT_CANTVRFY;
04021                      }
04022 
04023                      dkim->dkim_domain = dkim_strdup(dkim, domain, 0);
04024                      if (dkim->dkim_domain == NULL)
04025                             return DKIM_STAT_NORESOURCE;
04026               }
04027 
04028               dkim->dkim_state = DKIM_STATE_EOM2;
04029 
04030               return DKIM_STAT_NOSIG;
04031        }
04032 
04033        lib = dkim->dkim_libhandle;
04034 
04035        /*
04036        **  If a signature has "l=" set but it was greater than the
04037        **  canonicalized body length, the signature is invalid.
04038        */
04039 
04040        for (c = 0; c < dkim->dkim_sigcount; c++)
04041        {
04042               sig = dkim->dkim_siglist[c];
04043 
04044               if (sig->sig_bodycanon != NULL &&
04045                   sig->sig_bodycanon->canon_length != (ssize_t) -1 &&
04046                   sig->sig_bodycanon->canon_wrote < sig->sig_bodycanon->canon_length)
04047                      sig->sig_error = DKIM_SIGERROR_TOOLARGE_L;
04048        }
04049 
04050        /* invoke the final callback if defined */
04051        if (lib->dkiml_final != NULL)
04052        {
04053               status = lib->dkiml_final(dkim, dkim->dkim_siglist,
04054                                         dkim->dkim_sigcount);
04055               switch (status)
04056               {
04057                 case DKIM_CBSTAT_CONTINUE:
04058                      break;
04059 
04060                 case DKIM_CBSTAT_REJECT:
04061                      return DKIM_STAT_CBREJECT;
04062 
04063                 case DKIM_CBSTAT_TRYAGAIN:
04064                      return DKIM_STAT_CBTRYAGAIN;
04065 
04066                 case DKIM_CBSTAT_ERROR:
04067                      return DKIM_STAT_CBERROR;
04068 
04069                 default:
04070                      return DKIM_STAT_CBINVALID;
04071               }
04072        }
04073 
04074        dkim->dkim_state = DKIM_STATE_EOM2;
04075 
04076        /* see if we have a passing signature with bh match */
04077        for (c = 0; c < dkim->dkim_sigcount; c++)
04078        {
04079               sig = dkim->dkim_siglist[c];
04080 
04081               if ((sig->sig_flags & DKIM_SIGFLAG_PASSED) != 0 &&
04082                   (sig->sig_flags & DKIM_SIGFLAG_IGNORE) == 0 &&
04083                   sig->sig_bh == DKIM_SIGBH_MATCH)
04084                      break;
04085 
04086               sig = NULL;
04087        }
04088 
04089        /* run 'em until we get one */
04090        if (sig == NULL)
04091        {
04092               DKIM_SIGINFO *firstgood = NULL;
04093 
04094               for (c = 0; c < dkim->dkim_sigcount; c++)
04095               {
04096                      sig = dkim->dkim_siglist[c];
04097 
04098                      /* if not ignoring */
04099                      if ((sig->sig_flags & DKIM_SIGFLAG_IGNORE) == 0)
04100                      {
04101                             /* run this signature */
04102                             status = dkim_sig_process(dkim, sig);
04103                             if (status != DKIM_STAT_OK)
04104                             {
04105                                    sig = NULL;
04106                                    continue;
04107                             }
04108 
04109                             /* pass and bh match? */
04110                             if ((sig->sig_flags & DKIM_SIGFLAG_PASSED) != 0 &&
04111                                 sig->sig_bh == DKIM_SIGBH_MATCH)
04112                             {
04113                                    if (firstgood == NULL)
04114                                           firstgood = sig;
04115 
04116                                    /* continue? */
04117                                    if ((lib->dkiml_flags & DKIM_LIBFLAGS_VERIFYONE) != 0)
04118                                           break;
04119                             }
04120                      }
04121 
04122                      sig = NULL;
04123               }
04124 
04125               if (sig == NULL)
04126                      sig = firstgood;
04127        }
04128 
04129        /*
04130        **  If still none, we're going to fail so just use the
04131        **  first one.
04132        */
04133 
04134        if (sig == NULL)
04135        {
04136               for (c = 0; c < dkim->dkim_sigcount; c++)
04137               {
04138                      sig = dkim->dkim_siglist[c];
04139                      if ((sig->sig_flags & DKIM_SIGFLAG_IGNORE) == 0)
04140                             break;
04141                      sig = NULL;
04142               }
04143        }
04144 
04145        /* caller marked everything with "ignore" */
04146        if (sig == NULL)
04147        {
04148               dkim_error(dkim, "all signatures ignored by caller");
04149               return DKIM_STAT_NOSIG;
04150        }
04151 
04152        dkim->dkim_signature = sig;
04153 
04154        /* things for which we return DKIM_STAT_CANTVRFY */
04155        if (sig->sig_error != DKIM_SIGERROR_OK &&
04156            sig->sig_error != DKIM_SIGERROR_UNKNOWN &&
04157            sig->sig_error != DKIM_SIGERROR_KEYFAIL &&
04158            sig->sig_error != DKIM_SIGERROR_BADSIG &&
04159            sig->sig_error != DKIM_SIGERROR_KEYREVOKED &&
04160            sig->sig_error != DKIM_SIGERROR_NOKEY)
04161        {
04162               if (dkim->dkim_error == NULL ||
04163                   dkim->dkim_error[0] == '\0')
04164               {
04165                      dkim_error(dkim, dkim_code_to_name(sigerrors,
04166                                                         sig->sig_error));
04167               }
04168 
04169               return DKIM_STAT_CANTVRFY;
04170        }
04171 
04172        /* initialize final result */
04173        ret = DKIM_STAT_OK;
04174        if (sig->sig_error == DKIM_SIGERROR_NOKEY)
04175               ret = DKIM_STAT_NOKEY;
04176        else if (sig->sig_error == DKIM_SIGERROR_KEYFAIL)
04177               ret = DKIM_STAT_KEYFAIL;
04178        else if (sig->sig_error == DKIM_SIGERROR_KEYREVOKED)
04179               ret = DKIM_STAT_REVOKED;
04180        else if ((sig->sig_flags & DKIM_SIGFLAG_PASSED) == 0)
04181               ret = DKIM_STAT_BADSIG;
04182        else if (sig->sig_bh == DKIM_SIGBH_MISMATCH)
04183               ret = DKIM_STAT_BADSIG;
04184        else if (sig->sig_error == DKIM_SIGERROR_BADSIG)
04185               ret = DKIM_STAT_BADSIG;
04186 
04187        /* set testkey based on the key flags */
04188        if (testkey != NULL &&
04189            (sig->sig_flags & DKIM_SIGFLAG_TESTKEY) != 0)
04190               *testkey = TRUE;
04191 
04192        return ret;
04193 }
04194 
04195 /*
04196 **  DKIM_NEW -- allocate a new message context
04197 **
04198 **  Parameters:
04199 **     libhandle -- DKIM_LIB handle
04200 **     id -- transaction ID string
04201 **     memclosure -- memory closure
04202 **     hdrcanon_alg -- canonicalization algorithm to use for headers
04203 **     bodycanon_alg -- canonicalization algorithm to use for headers
04204 **     sign_alg -- signature algorithm to use
04205 **     statp -- status (returned)
04206 **
04207 **  Return value:
04208 **     A new DKIM handle, or NULL on failure.
04209 */
04210 
04211 static DKIM *
04212 dkim_new(DKIM_LIB *libhandle, const unsigned char *id, void *memclosure,
04213          dkim_canon_t hdrcanon_alg, dkim_canon_t bodycanon_alg,
04214          dkim_alg_t sign_alg, DKIM_STAT *statp)
04215 {
04216        DKIM *new;
04217 
04218        assert(libhandle != NULL);
04219 
04220        /* allocate the handle */
04221        new = (DKIM *) dkim_malloc(libhandle, memclosure,
04222                                   sizeof(struct dkim));
04223        if (new == NULL)
04224        {
04225               *statp = DKIM_STAT_NORESOURCE;
04226               return NULL;
04227        }
04228 
04229        /* populate defaults */
04230        memset(new, '\0', sizeof(struct dkim));
04231        new->dkim_id = id;
04232        new->dkim_signalg = (sign_alg == -1 ? DKIM_SIGN_DEFAULT
04233                                            : sign_alg);
04234        new->dkim_hdrcanonalg = (hdrcanon_alg == -1 ? DKIM_CANON_DEFAULT
04235                                                    : hdrcanon_alg);
04236        new->dkim_bodycanonalg = (bodycanon_alg == -1 ? DKIM_CANON_DEFAULT
04237                                                      : bodycanon_alg);
04238        new->dkim_querymethod = DKIM_QUERY_DEFAULT;
04239        new->dkim_mode = DKIM_MODE_UNKNOWN;
04240        new->dkim_chunkcrlf = DKIM_CRLF_UNKNOWN;
04241        new->dkim_state = DKIM_STATE_INIT;
04242        new->dkim_presult = DKIM_PRESULT_NONE;
04243        new->dkim_dnssec_policy = DKIM_DNSSEC_UNKNOWN;
04244        new->dkim_margin = (size_t) DKIM_HDRMARGIN;
04245        new->dkim_closure = memclosure;
04246        new->dkim_libhandle = libhandle;
04247        new->dkim_tmpdir = libhandle->dkiml_tmpdir;
04248        new->dkim_timeout = libhandle->dkiml_timeout;
04249 
04250        *statp = DKIM_STAT_OK;
04251 
04252 #ifdef QUERY_CACHE
04253        if ((libhandle->dkiml_flags & DKIM_LIBFLAGS_CACHE) != 0 &&
04254            libhandle->dkiml_cache == NULL)
04255        {
04256               int err = 0;
04257 
04258               libhandle->dkiml_cache = dkim_cache_init(&err,
04259                                                        libhandle->dkiml_tmpdir);
04260        }
04261 #endif /* QUERY_CACHE */
04262 
04263        return new;
04264 }
04265 
04266 #ifndef USE_GNUTLS
04267 /*
04268 **  DKIM_INIT_OPENSSL -- initialize OpenSSL algorithms if needed
04269 **
04270 **  Parameters:
04271 **     None.
04272 **
04273 **  Return value:
04274 **     None.
04275 */
04276 
04277 static pthread_mutex_t openssl_lock = PTHREAD_MUTEX_INITIALIZER;
04278 static unsigned openssl_refcount = 0;
04279 
04280 static void
04281 dkim_init_openssl(void)
04282 {
04283        pthread_mutex_lock(&openssl_lock);
04284 
04285        if (openssl_refcount == 0)
04286               OpenSSL_add_all_algorithms();
04287        openssl_refcount++;
04288 
04289        pthread_mutex_unlock(&openssl_lock);
04290 }
04291 
04292 /*
04293 **  DKIM_CLOSE_OPENSSL -- clean up OpenSSL algorithms if needed
04294 **
04295 **  Parameters:
04296 **     None.
04297 **
04298 **  Return value:
04299 **     None.
04300 */
04301 
04302 static void
04303 dkim_close_openssl(void)
04304 {
04305        assert(openssl_refcount > 0);
04306 
04307        pthread_mutex_lock(&openssl_lock);
04308 
04309        openssl_refcount--;
04310        if (openssl_refcount == 0)
04311               EVP_cleanup();
04312 
04313        pthread_mutex_unlock(&openssl_lock);
04314 }
04315 #endif /* ! USE_GNUTLS */
04316 
04317 /* ========================= PUBLIC SECTION ========================== */
04318 
04319 /*
04320 **  DKIM_INIT -- initialize a DKIM library context
04321 **
04322 **  Parameters:
04323 **     caller_mallocf -- caller-provided memory allocation function
04324 **     caller_freef -- caller-provided memory release function
04325 **
04326 **  Return value:
04327 **     A new DKIM_LIB handle suitable for use with other DKIM functions, or
04328 **     NULL on failure.
04329 **
04330 **  Side effects:
04331 **     Crop circles near Birmingham.
04332 */
04333 
04334 DKIM_LIB *
04335 dkim_init(void *(*caller_mallocf)(void *closure, size_t nbytes),
04336           void (*caller_freef)(void *closure, void *p))
04337 {
04338        u_char *td;
04339        DKIM_LIB *libhandle;
04340 
04341 #ifndef USE_GNUTLS
04342        /* initialize OpenSSL algorithms */
04343        dkim_init_openssl();
04344 #endif /* USE_GNUTLS */
04345 
04346        /* copy the parameters */
04347        libhandle = (DKIM_LIB *) malloc(sizeof(struct dkim_lib));
04348        if (libhandle == NULL)
04349               return NULL;
04350 
04351        td = (u_char *) getenv("DKIM_TMPDIR");
04352        if (td == NULL || td[0] == '\0')
04353               td = (u_char *) DEFTMPDIR;
04354 
04355        libhandle->dkiml_signre = FALSE;
04356        libhandle->dkiml_skipre = FALSE;
04357        libhandle->dkiml_malloc = caller_mallocf;
04358        libhandle->dkiml_free = caller_freef;
04359        strlcpy((char *) libhandle->dkiml_tmpdir, (char *) td, 
04360                sizeof libhandle->dkiml_tmpdir);
04361        libhandle->dkiml_flags = DKIM_LIBFLAGS_DEFAULT;
04362        libhandle->dkiml_timeout = DEFTIMEOUT;
04363        libhandle->dkiml_senderhdrs = (u_char **) dkim_default_senderhdrs;
04364        libhandle->dkiml_alwayshdrs = NULL;
04365 #ifdef _FFR_OVERSIGN
04366        libhandle->dkiml_oversignhdrs = NULL;
04367 #endif /* _FFR_OVERSIGN */
04368        libhandle->dkiml_nalwayshdrs = 0;
04369        libhandle->dkiml_mbs = NULL;
04370        libhandle->dkiml_querymethod = DKIM_QUERY_UNKNOWN;
04371        memset(libhandle->dkiml_queryinfo, '\0',
04372               sizeof libhandle->dkiml_queryinfo);
04373 #ifdef QUERY_CACHE
04374        libhandle->dkiml_cache = NULL;
04375 #endif /* QUERY_CACHE */
04376        libhandle->dkiml_fixedtime = 0;
04377        libhandle->dkiml_sigttl = 0;
04378        libhandle->dkiml_clockdrift = DEFCLOCKDRIFT;
04379 
04380        libhandle->dkiml_key_lookup = NULL;
04381        libhandle->dkiml_policy_lookup = NULL;
04382        libhandle->dkiml_sig_handle = NULL;
04383        libhandle->dkiml_sig_handle_free = NULL;
04384        libhandle->dkiml_sig_tagvalues = NULL;
04385        libhandle->dkiml_prescreen = NULL;
04386        libhandle->dkiml_final = NULL;
04387        libhandle->dkiml_dns_callback = NULL;
04388        libhandle->dkiml_dns_start = dkim_res_query;
04389        libhandle->dkiml_dns_cancel = dkim_res_cancel;
04390        libhandle->dkiml_dns_waitreply = dkim_res_waitreply;
04391        
04392 #define FEATURE_INDEX(x)    ((x) / (8 * sizeof(u_int)))
04393 #define FEATURE_OFFSET(x)   ((x) % (8 * sizeof(u_int)))
04394 #define FEATURE_ADD(lib,x)  (lib)->dkiml_flist[FEATURE_INDEX((x))] |= (1 << FEATURE_OFFSET(x))
04395 
04396        libhandle->dkiml_flsize = (FEATURE_INDEX(DKIM_FEATURE_MAX)) + 1;
04397        libhandle->dkiml_flist = (u_int *) malloc(sizeof(u_int) * libhandle->dkiml_flsize);
04398        if (libhandle->dkiml_flist == NULL)
04399        {
04400               free(libhandle);
04401               return NULL;
04402        }
04403        memset(libhandle->dkiml_flist, '\0',
04404               sizeof(u_int) * libhandle->dkiml_flsize);
04405 
04406 #ifdef _FFR_DIFFHEADERS
04407        FEATURE_ADD(libhandle, DKIM_FEATURE_DIFFHEADERS);
04408 #endif /* _FFR_DIFFHEADERS */
04409 #ifdef QUERY_CACHE
04410        FEATURE_ADD(libhandle, DKIM_FEATURE_QUERY_CACHE);
04411 #endif /* QUERY_CACHE */
04412 #ifdef HAVE_SHA256
04413        FEATURE_ADD(libhandle, DKIM_FEATURE_SHA256);
04414 #endif /* HAVE_SHA256 */
04415 #ifdef _FFR_DNSSEC
04416        FEATURE_ADD(libhandle, DKIM_FEATURE_DNSSEC);
04417 #endif /* _FFR_DNSSEC */
04418 #ifdef _FFR_RESIGN
04419        FEATURE_ADD(libhandle, DKIM_FEATURE_RESIGN);
04420 #endif /* _FFR_RESIGN */
04421 #ifdef _FFR_ATPS
04422        FEATURE_ADD(libhandle, DKIM_FEATURE_ATPS);
04423 #endif /* _FFR_ATPS */
04424 #ifdef _FFR_OVERSIGN
04425        FEATURE_ADD(libhandle, DKIM_FEATURE_OVERSIGN);
04426 #endif /* _FFR_OVERSIGN */
04427        FEATURE_ADD(libhandle, DKIM_FEATURE_XTAGS);
04428 #ifdef _FFR_DKIM_REPUTATION
04429        FEATURE_ADD(libhandle, DKIM_FEATURE_DKIM_REPUTATION);
04430 #endif /* _FFR_DKIM_REPUTATION */
04431 
04432        /* initialize the resolver */
04433        (void) res_init();
04434 
04435        return libhandle;
04436 }
04437 
04438 /*
04439 **  DKIM_CLOSE -- shut down a DKIM library package
04440 **
04441 **  Parameters:
04442 **     lib -- library handle to shut down
04443 **
04444 **  Return value:
04445 **     None.
04446 */
04447 
04448 void
04449 dkim_close(DKIM_LIB *lib)
04450 {
04451        assert(lib != NULL);
04452 
04453 #ifdef QUERY_CACHE
04454        if (lib->dkiml_cache != NULL)
04455               (void) dkim_cache_close(lib->dkiml_cache);
04456 #endif /* QUERY_CACHE */
04457 
04458        if (lib->dkiml_skipre)
04459               (void) regfree(&lib->dkiml_skiphdrre);
04460        
04461        if (lib->dkiml_signre)
04462               (void) regfree(&lib->dkiml_hdrre);
04463 
04464 
04465 #ifdef _FFR_OVERSIGN
04466        if (lib->dkiml_oversignhdrs != NULL)
04467               dkim_clobber_array((char **) lib->dkiml_oversignhdrs);
04468 #endif /* _FFR_OVERSIGN */
04469 
04470        if (lib->dkiml_senderhdrs != (u_char **) dkim_default_senderhdrs)
04471               dkim_clobber_array((char **) lib->dkiml_senderhdrs);
04472 
04473        if (lib->dkiml_alwayshdrs != NULL)
04474               dkim_clobber_array((char **) lib->dkiml_alwayshdrs);
04475 
04476        if (lib->dkiml_mbs != NULL)
04477               dkim_clobber_array((char **) lib->dkiml_mbs);
04478 
04479        free(lib->dkiml_flist);
04480        
04481        free((void *) lib);
04482 
04483 #ifndef USE_GNUTLS
04484        dkim_close_openssl();
04485 #endif /* ! USE_GNUTLS */
04486 }
04487 
04488 /*
04489 **  DKIM_ERROR -- log an error into a DKIM handle
04490 **
04491 **  Parameters:
04492 **     dkim -- DKIM context in which this is performed
04493 **     format -- format to apply
04494 **     ... -- arguments
04495 **
04496 **  Return value:
04497 **     None.
04498 */
04499 
04500 void
04501 dkim_error(DKIM *dkim, const char *format, ...)
04502 {
04503        int flen;
04504        int saverr;
04505        u_char *new;
04506        va_list va;
04507 
04508        assert(dkim != NULL);
04509        assert(format != NULL);
04510 
04511        saverr = errno;
04512 
04513        if (dkim->dkim_error == NULL)
04514        {
04515               dkim->dkim_error = DKIM_MALLOC(dkim, DEFERRLEN);
04516               if (dkim->dkim_error == NULL)
04517               {
04518                      errno = saverr;
04519                      return;
04520               }
04521               dkim->dkim_errlen = DEFERRLEN;
04522        }
04523 
04524        for (;;)
04525        {
04526               va_start(va, format);
04527               flen = vsnprintf((char *) dkim->dkim_error, dkim->dkim_errlen,
04528                                format, va);
04529               va_end(va);
04530 
04531               /* compensate for broken vsnprintf() implementations */
04532               if (flen == -1)
04533                      flen = dkim->dkim_errlen * 2;
04534 
04535               if (flen >= dkim->dkim_errlen)
04536               {
04537                      new = DKIM_MALLOC(dkim, flen + 1);
04538                      if (new == NULL)
04539                      {
04540                             errno = saverr;
04541                             return;
04542                      }
04543 
04544                      DKIM_FREE(dkim, dkim->dkim_error);
04545                      dkim->dkim_error = new;
04546                      dkim->dkim_errlen = flen + 1;
04547               }
04548               else
04549               {
04550                      break;
04551               }
04552        }
04553 
04554        errno = saverr;
04555 }
04556 
04557 /*
04558 **  DKIM_OPTIONS -- get or set a library option
04559 **
04560 **  Parameters:
04561 **     lib -- DKIM library handle
04562 **     op -- operation to perform
04563 **     opt -- option to get/set
04564 **     ptr -- pointer to its old/new value
04565 **     len -- memory available at "ptr"
04566 **
04567 **  Return value:
04568 **     A DKIM_STAT constant.
04569 */
04570 
04571 DKIM_STAT
04572 dkim_options(DKIM_LIB *lib, int op, dkim_opts_t opt, void *ptr, size_t len)
04573 {
04574        assert(lib != NULL);
04575        assert(op == DKIM_OP_SETOPT || op == DKIM_OP_GETOPT);
04576        assert(len != 0);
04577 
04578        switch (opt)
04579        {
04580          case DKIM_OPTS_TMPDIR:
04581               if (op == DKIM_OP_GETOPT)
04582               {
04583                      strlcpy((char *) ptr, (char *) lib->dkiml_tmpdir, len);
04584               }
04585               else if (ptr == NULL)
04586               {
04587                      strlcpy((char *) lib->dkiml_tmpdir, DEFTMPDIR,
04588                              sizeof lib->dkiml_tmpdir);
04589               }
04590               else
04591               {
04592                      strlcpy((char *) lib->dkiml_tmpdir, (char *) ptr,
04593                              sizeof lib->dkiml_tmpdir);
04594               }
04595               return DKIM_STAT_OK;
04596 
04597          case DKIM_OPTS_FIXEDTIME:
04598               if (ptr == NULL)
04599                      return DKIM_STAT_INVALID;
04600 
04601               if (len != sizeof lib->dkiml_fixedtime)
04602                      return DKIM_STAT_INVALID;
04603 
04604               if (op == DKIM_OP_GETOPT)
04605               {
04606                      memcpy(ptr, &lib->dkiml_fixedtime, len);
04607               }
04608               else
04609               {
04610                      memcpy(&lib->dkiml_fixedtime, ptr, len);
04611               }
04612               return DKIM_STAT_OK;
04613 
04614          case DKIM_OPTS_SIGNATURETTL:
04615               if (ptr == NULL)
04616                      return DKIM_STAT_INVALID;
04617 
04618               if (len != sizeof lib->dkiml_sigttl)
04619                      return DKIM_STAT_INVALID;
04620 
04621               if (op == DKIM_OP_GETOPT)
04622               {
04623                      memcpy(ptr, &lib->dkiml_sigttl, len);
04624               }
04625               else
04626               {
04627                      memcpy(&lib->dkiml_sigttl, ptr, len);
04628               }
04629               return DKIM_STAT_OK;
04630 
04631          case DKIM_OPTS_CLOCKDRIFT:
04632               if (ptr == NULL)
04633                      return DKIM_STAT_INVALID;
04634 
04635               if (len != sizeof lib->dkiml_clockdrift)
04636                      return DKIM_STAT_INVALID;
04637 
04638               if (op == DKIM_OP_GETOPT)
04639               {
04640                      memcpy(ptr, &lib->dkiml_clockdrift, len);
04641               }
04642               else
04643               {
04644                      memcpy(&lib->dkiml_clockdrift, ptr, len);
04645               }
04646               return DKIM_STAT_OK;
04647 
04648          case DKIM_OPTS_FLAGS:
04649               if (ptr == NULL)
04650                      return DKIM_STAT_INVALID;
04651 
04652               if (len != sizeof lib->dkiml_flags)
04653                      return DKIM_STAT_INVALID;
04654 
04655               if (op == DKIM_OP_GETOPT)
04656               {
04657                      memcpy(ptr, &lib->dkiml_flags, len);
04658               }
04659               else
04660               {
04661                      memcpy(&lib->dkiml_flags, ptr, len);
04662               }
04663               return DKIM_STAT_OK;
04664 
04665          case DKIM_OPTS_TIMEOUT:
04666               if (ptr == NULL)
04667                      return DKIM_STAT_INVALID;
04668 
04669               if (len != sizeof lib->dkiml_timeout)
04670                      return DKIM_STAT_INVALID;
04671 
04672               if (op == DKIM_OP_GETOPT)
04673               {
04674                      memcpy(ptr, &lib->dkiml_timeout, len);
04675               }
04676               else
04677               {
04678                      memcpy(&lib->dkiml_timeout, ptr, len);
04679               }
04680               return DKIM_STAT_OK;
04681 
04682          case DKIM_OPTS_SENDERHDRS:
04683               if (len != sizeof lib->dkiml_senderhdrs)
04684                      return DKIM_STAT_INVALID;
04685 
04686               if (op == DKIM_OP_GETOPT)
04687               {
04688                      memcpy(ptr, &lib->dkiml_senderhdrs, len);
04689               }
04690               else if (ptr == NULL)
04691               {
04692                      if (lib->dkiml_senderhdrs != (u_char **) dkim_default_senderhdrs)
04693                             dkim_clobber_array((char **) lib->dkiml_senderhdrs);
04694 
04695                      lib->dkiml_senderhdrs = (u_char **) dkim_default_senderhdrs;
04696               }
04697               else
04698               {
04699                      const char **tmp;
04700 
04701                      tmp = dkim_copy_array(ptr);
04702                      if (tmp == NULL)
04703                             return DKIM_STAT_NORESOURCE;
04704 
04705                      if (lib->dkiml_senderhdrs != (u_char **) dkim_default_senderhdrs)
04706                             dkim_clobber_array((char **) lib->dkiml_senderhdrs);
04707 
04708                      lib->dkiml_senderhdrs = (u_char **) tmp;
04709               }
04710               return DKIM_STAT_OK;
04711 
04712 #ifdef _FFR_OVERSIGN
04713          case DKIM_OPTS_OVERSIGNHDRS:
04714               if (len != sizeof lib->dkiml_oversignhdrs)
04715                      return DKIM_STAT_INVALID;
04716 
04717               if (op == DKIM_OP_GETOPT)
04718               {
04719                      memcpy(ptr, &lib->dkiml_oversignhdrs, len);
04720               }
04721               else
04722               {
04723                      const char **tmp;
04724 
04725                      tmp = dkim_copy_array(ptr);
04726                      if (tmp == NULL)
04727                             return DKIM_STAT_NORESOURCE;
04728 
04729                      if (lib->dkiml_oversignhdrs != NULL)
04730                             dkim_clobber_array((char **) lib->dkiml_oversignhdrs);
04731 
04732                      lib->dkiml_oversignhdrs = (u_char **) tmp;
04733               }
04734               return DKIM_STAT_OK;
04735 #endif /* _FFR_OVERSIGN */
04736 
04737          case DKIM_OPTS_ALWAYSHDRS:
04738               if (len != sizeof lib->dkiml_alwayshdrs)
04739                      return DKIM_STAT_INVALID;
04740 
04741               if (op == DKIM_OP_GETOPT)
04742               {
04743                      memcpy(ptr, &lib->dkiml_alwayshdrs, len);
04744               }
04745               else if (ptr == NULL)
04746               {
04747                      if (lib->dkiml_alwayshdrs != NULL)
04748                             dkim_clobber_array((char **) lib->dkiml_alwayshdrs);
04749 
04750                      lib->dkiml_alwayshdrs = NULL;
04751                      lib->dkiml_nalwayshdrs = 0;
04752               }
04753               else
04754               {
04755                      u_int n;
04756                      const char **tmp;
04757 
04758                      tmp = dkim_copy_array(ptr);
04759                      if (tmp == NULL)
04760                             return DKIM_STAT_NORESOURCE;
04761 
04762                      if (lib->dkiml_alwayshdrs != NULL)
04763                             dkim_clobber_array((char **) lib->dkiml_alwayshdrs);
04764 
04765                      lib->dkiml_alwayshdrs = (u_char **) tmp;
04766                      for (n = 0; lib->dkiml_alwayshdrs[n] != NULL; n++)
04767                             continue;
04768                      lib->dkiml_nalwayshdrs = n;
04769               }
04770               return DKIM_STAT_OK;
04771 
04772          case DKIM_OPTS_MUSTBESIGNED:
04773               if (len != sizeof lib->dkiml_mbs)
04774                      return DKIM_STAT_INVALID;
04775 
04776               if (op == DKIM_OP_GETOPT)
04777               {
04778                      memcpy(ptr, &lib->dkiml_mbs, len);
04779               }
04780               else if (ptr == NULL)
04781               {
04782                      lib->dkiml_mbs = NULL;
04783               }
04784               else
04785               {
04786                      const char **tmp;
04787 
04788                      tmp = dkim_copy_array(ptr);
04789                      if (tmp == NULL)
04790                             return DKIM_STAT_NORESOURCE;
04791 
04792                      if (lib->dkiml_mbs != NULL)
04793                             dkim_clobber_array((char **) lib->dkiml_mbs);
04794 
04795                      lib->dkiml_mbs = (u_char **) tmp;
04796               }
04797               return DKIM_STAT_OK;
04798 
04799          case DKIM_OPTS_SIGNHDRS:
04800               if (len != sizeof(char **) || op == DKIM_OP_GETOPT)
04801               {
04802                      return DKIM_STAT_INVALID;
04803               }
04804               else if (ptr == NULL)
04805               {
04806                      if (lib->dkiml_signre)
04807                      {
04808                             (void) regfree(&lib->dkiml_hdrre);
04809                             lib->dkiml_signre = FALSE;
04810                      }
04811               }
04812               else
04813               {
04814                      int status;
04815                      u_char **hdrs;
04816                      char buf[BUFRSZ + 1];
04817 
04818                      if (lib->dkiml_signre)
04819                      {
04820                             (void) regfree(&lib->dkiml_hdrre);
04821                             lib->dkiml_signre = FALSE;
04822                      }
04823 
04824                      memset(buf, '\0', sizeof buf);
04825 
04826                      hdrs = (u_char **) ptr;
04827 
04828                      (void) strlcpy(buf, "^(", sizeof buf);
04829 
04830                      if (!dkim_hdrlist((u_char *) buf, sizeof buf,
04831                                        (u_char **) required_signhdrs, TRUE))
04832                             return DKIM_STAT_INVALID;
04833                      if (!dkim_hdrlist((u_char *) buf, sizeof buf,
04834                                        hdrs, FALSE))
04835                             return DKIM_STAT_INVALID;
04836 
04837                      if (strlcat(buf, ")$", sizeof buf) >= sizeof buf)
04838                             return DKIM_STAT_INVALID;
04839 
04840                      status = regcomp(&lib->dkiml_hdrre, buf,
04841                                       (REG_EXTENDED|REG_ICASE));
04842                      if (status != 0)
04843                             return DKIM_STAT_INTERNAL;
04844 
04845                      lib->dkiml_signre = TRUE;
04846               }
04847               return DKIM_STAT_OK;
04848 
04849          case DKIM_OPTS_SKIPHDRS:
04850               if (len != sizeof(char **) || op == DKIM_OP_GETOPT)
04851               {
04852                      return DKIM_STAT_INVALID;
04853               }
04854               else if (ptr == NULL)
04855               {
04856                      if (lib->dkiml_skipre)
04857                      {
04858                             (void) regfree(&lib->dkiml_skiphdrre);
04859                             lib->dkiml_skipre = FALSE;
04860                      }
04861               }
04862               else
04863               {
04864                      int status;
04865                      u_char **hdrs;
04866                      char buf[BUFRSZ + 1];
04867 
04868                      if (lib->dkiml_skipre)
04869                      {
04870                             (void) regfree(&lib->dkiml_skiphdrre);
04871                             lib->dkiml_skipre = FALSE;
04872                      }
04873 
04874                      memset(buf, '\0', sizeof buf);
04875 
04876                      hdrs = (u_char **) ptr;
04877 
04878                      (void) strlcpy(buf, "^(", sizeof buf);
04879 
04880                      if (!dkim_hdrlist((u_char *) buf, sizeof buf,
04881                                        hdrs, TRUE))
04882                             return DKIM_STAT_INVALID;
04883 
04884                      if (strlcat(buf, ")$", sizeof buf) >= sizeof buf)
04885                             return DKIM_STAT_INVALID;
04886 
04887                      status = regcomp(&lib->dkiml_skiphdrre, buf,
04888                                       (REG_EXTENDED|REG_ICASE));
04889                      if (status != 0)
04890                             return DKIM_STAT_INTERNAL;
04891 
04892                      lib->dkiml_skipre = TRUE;
04893               }
04894               return DKIM_STAT_OK;
04895 
04896          case DKIM_OPTS_QUERYMETHOD:
04897               if (ptr == NULL)
04898                      return DKIM_STAT_INVALID;
04899 
04900               if (len != sizeof lib->dkiml_querymethod)
04901                      return DKIM_STAT_INVALID;
04902 
04903               if (op == DKIM_OP_GETOPT)
04904               {
04905                      memcpy(ptr, &lib->dkiml_querymethod, len);
04906               }
04907               else
04908               {
04909                      memcpy(&lib->dkiml_querymethod, ptr, len);
04910               }
04911               return DKIM_STAT_OK;
04912 
04913          case DKIM_OPTS_QUERYINFO:
04914               if (ptr == NULL)
04915                      return DKIM_STAT_INVALID;
04916 
04917               if (op == DKIM_OP_GETOPT)
04918               {
04919                      strlcpy(ptr, (char *) lib->dkiml_queryinfo, len);
04920               }
04921               else
04922               {
04923                      strlcpy((char *) lib->dkiml_queryinfo, ptr,
04924                              sizeof lib->dkiml_queryinfo);
04925               }
04926               return DKIM_STAT_OK;
04927 
04928          default:
04929               return DKIM_STAT_INVALID;
04930        }
04931 }
04932 
04933 /*
04934 **  DKIM_FREE -- destroy a DKIM handle
04935 **
04936 **  Parameters:
04937 **     dkim -- DKIM handle to destroy
04938 **
04939 **  Return value:
04940 **     A DKIM_STAT constant.
04941 */
04942 
04943 DKIM_STAT
04944 dkim_free(DKIM *dkim)
04945 {
04946        assert(dkim != NULL);
04947 
04948 #ifdef _FFR_RESIGN
04949        /* XXX -- this should be mutex-protected */
04950        if (dkim->dkim_resign != NULL)
04951        {
04952               if (dkim->dkim_resign->dkim_refcnt == 0)
04953                      dkim_free(dkim->dkim_resign);
04954               else
04955                      dkim->dkim_resign->dkim_refcnt--;
04956        }
04957        else if (dkim->dkim_refcnt != 0)
04958        {
04959               return DKIM_STAT_INVALID;
04960        }
04961 #endif /* _FFR_RESIGN */
04962 
04963        /* blast the headers */
04964 #ifdef _FFR_RESIGN
04965        if (dkim->dkim_resign == NULL && dkim->dkim_hhead != NULL)
04966 #else /* _FFR_RESIGN */
04967        if (dkim->dkim_hhead != NULL)
04968 #endif /* _FFR_RESIGN */
04969        {
04970               struct dkim_header *next;
04971               struct dkim_header *hdr;
04972 
04973               for (hdr = dkim->dkim_hhead; hdr != NULL; )
04974               {
04975                      next = hdr->hdr_next;
04976 
04977                      CLOBBER(hdr->hdr_text);
04978                      CLOBBER(hdr);
04979 
04980                      hdr = next;
04981               }
04982        }
04983 
04984        /* blast the data sets */
04985 #ifdef _FFR_RESIGN
04986        if (dkim->dkim_resign == NULL && dkim->dkim_sethead != NULL)
04987 #else /* _FFR_RESIGN */
04988        if (dkim->dkim_sethead != NULL)
04989 #endif /* _FFR_RESIGN */
04990        {
04991               DKIM_SET *set;
04992               DKIM_SET *next;
04993 
04994               for (set = dkim->dkim_sethead; set != NULL; )
04995               {
04996                      next = set->set_next;
04997 
04998                      dkim_set_free(dkim, set);
04999 
05000                      set = next;
05001               }
05002        }
05003 
05004        /* trash the signature list */
05005        if (dkim->dkim_siglist != NULL)
05006        {
05007               int c;
05008 
05009               for (c = 0; c < dkim->dkim_sigcount; c++)
05010               {
05011                      if (dkim->dkim_siglist[c]->sig_context != NULL &&
05012                          dkim->dkim_libhandle->dkiml_sig_handle_free != NULL)
05013                      {
05014                             dkim->dkim_libhandle->dkiml_sig_handle_free(dkim->dkim_closure,
05015                                                                         dkim->dkim_siglist[c]->sig_context);
05016                      }
05017 
05018                      CLOBBER(dkim->dkim_siglist[c]->sig_key);
05019                      CLOBBER(dkim->dkim_siglist[c]->sig_sig);
05020                      if (dkim->dkim_siglist[c]->sig_keytype == DKIM_KEYTYPE_RSA)
05021                      {
05022                             struct dkim_rsa *rsa;
05023 
05024                             rsa = dkim->dkim_siglist[c]->sig_signature;
05025                             if (rsa != NULL)
05026                             {
05027 #ifdef USE_GNUTLS
05028                                    KEY_CLOBBER(rsa->rsa_key);
05029                                    PUBKEY_CLOBBER(rsa->rsa_pubkey);
05030                                    PRIVKEY_CLOBBER(rsa->rsa_privkey);
05031                                    HCLOBBER(rsa->rsa_rsaout.data);
05032 #else /* USE_GNUTLS */
05033                                    BIO_CLOBBER(rsa->rsa_keydata);
05034                                    EVP_CLOBBER(rsa->rsa_pkey);
05035                                    RSA_CLOBBER(rsa->rsa_rsa);
05036                                    CLOBBER(rsa->rsa_rsaout);
05037 #endif /* USE_GNUTLS */
05038                             }
05039                      }
05040                      CLOBBER(dkim->dkim_siglist[c]->sig_signature);
05041                      CLOBBER(dkim->dkim_siglist[c]);
05042               }
05043 
05044               CLOBBER(dkim->dkim_siglist);
05045        }
05046 
05047        if (dkim->dkim_xtags != NULL)
05048        {
05049               struct dkim_xtag *cur;
05050               struct dkim_xtag *next;
05051 
05052               cur = dkim->dkim_xtags;
05053               while (cur != NULL)
05054               {
05055                      next = cur->xt_next;
05056                      free(cur);
05057                      cur = next;
05058               }
05059        }
05060 
05061        /* destroy canonicalizations */
05062        dkim_canon_cleanup(dkim);
05063 
05064        CLOBBER(dkim->dkim_b64sig);
05065        CLOBBER(dkim->dkim_selector);
05066        CLOBBER(dkim->dkim_domain);
05067        CLOBBER(dkim->dkim_user);
05068        CLOBBER(dkim->dkim_key);
05069        CLOBBER(dkim->dkim_sender);
05070        CLOBBER(dkim->dkim_signer);
05071        CLOBBER(dkim->dkim_error);
05072        CLOBBER(dkim->dkim_zdecode);
05073        CLOBBER(dkim->dkim_hdrlist);
05074 
05075        DSTRING_CLOBBER(dkim->dkim_hdrbuf);
05076        DSTRING_CLOBBER(dkim->dkim_canonbuf);
05077 
05078        dkim_mfree(dkim->dkim_libhandle, dkim->dkim_closure, dkim);
05079 
05080        return DKIM_STAT_OK;
05081 }
05082 
05083 /*
05084 **  DKIM_SIGN -- allocate a handle for use in a signature operation
05085 **
05086 **  Parameters:
05087 **     libhandle -- DKIM_LIB handle
05088 **     id -- identification string (e.g. job ID) for logging
05089 **     memclosure -- memory closure for allocations (or NULL)
05090 **     secretkey -- secret key (PEM format)
05091 **     selector -- selector to be used when generating the signature header
05092 **     domain -- domain for which this message is being signed
05093 **     hdrcanonalg -- canonicalization algorithm to use for headers
05094 **     bodycanonalg -- canonicalization algorithm to use for body
05095 **     signalg -- signing algorithm to use
05096 **     length -- how many bytes of the body to sign (-1 for all)
05097 **     statp -- status (returned)
05098 **
05099 **  Return value:
05100 **     A new signing handle, or NULL.
05101 */
05102 
05103 DKIM *
05104 dkim_sign(DKIM_LIB *libhandle, const unsigned char *id, void *memclosure,
05105           const dkim_sigkey_t secretkey, const unsigned char *selector,
05106           const unsigned char *domain, dkim_canon_t hdrcanonalg,
05107          dkim_canon_t bodycanonalg, dkim_alg_t signalg,
05108           ssize_t length, DKIM_STAT *statp)
05109 {
05110        DKIM *new;
05111 
05112        assert(libhandle != NULL);
05113        assert(secretkey != NULL);
05114        assert(selector != NULL);
05115        assert(domain != NULL);
05116        assert(hdrcanonalg == DKIM_CANON_SIMPLE ||
05117               hdrcanonalg == DKIM_CANON_RELAXED);
05118        assert(bodycanonalg == DKIM_CANON_SIMPLE ||
05119               bodycanonalg == DKIM_CANON_RELAXED);
05120        assert(signalg == DKIM_SIGN_DEFAULT ||
05121               signalg == DKIM_SIGN_RSASHA1 || signalg == DKIM_SIGN_RSASHA256);
05122        assert(statp != NULL);
05123 
05124        if (dkim_libfeature(libhandle, DKIM_FEATURE_SHA256))
05125        {
05126               if (signalg == DKIM_SIGN_DEFAULT)
05127                      signalg = DKIM_SIGN_RSASHA256;
05128        }
05129        else
05130        {
05131               if (signalg == DKIM_SIGN_RSASHA256)
05132               {
05133                      *statp = DKIM_STAT_INVALID;
05134                      return NULL;
05135               }
05136 
05137               if (signalg == DKIM_SIGN_DEFAULT)
05138                      signalg = DKIM_SIGN_RSASHA1;
05139        }
05140 
05141        new = dkim_new(libhandle, id, memclosure, hdrcanonalg, bodycanonalg,
05142                       signalg, statp);
05143 
05144        if (new != NULL)
05145        {
05146               new->dkim_mode = DKIM_MODE_SIGN;
05147 
05148               /* do DER decoding here if needed */
05149               if (strncmp((char *) secretkey, "MII", 3) == 0)
05150               {
05151                      size_t b64len;
05152 
05153                      b64len = strlen((char *) secretkey);
05154 
05155                      new->dkim_key = (unsigned char *) DKIM_MALLOC(new,
05156                                                                    b64len);
05157                      if (new->dkim_key == NULL)
05158                      {
05159                             *statp = DKIM_STAT_NORESOURCE;
05160                             dkim_free(new);
05161                             return NULL;
05162                      }
05163 
05164                      new->dkim_keylen = dkim_base64_decode(secretkey,
05165                                                            new->dkim_key,
05166                                                            b64len);
05167                      if (new->dkim_keylen <= 0)
05168                      {
05169                             *statp = DKIM_STAT_NORESOURCE;
05170                             dkim_free(new);
05171                             return NULL;
05172                      }
05173               }
05174               else
05175               {
05176                      new->dkim_keylen = strlen((const char *) secretkey);
05177                      new->dkim_key = dkim_strdup(new, secretkey, 0);
05178 
05179                      if (new->dkim_key == NULL)
05180                      {
05181                             *statp = DKIM_STAT_NORESOURCE;
05182                             dkim_free(new);
05183                             return NULL;
05184                      }
05185               }
05186 
05187               new->dkim_selector = dkim_strdup(new, selector, 0);
05188               new->dkim_domain = dkim_strdup(new, domain, 0);
05189               if (length == (ssize_t) -1)
05190                      new->dkim_signlen = ULONG_MAX;
05191               else
05192                      new->dkim_signlen = length;
05193        }
05194 
05195        return new;
05196 }
05197 
05198 /*
05199 **  DKIM_VERIFY -- allocate a handle for use in a verify operation
05200 **
05201 **  Parameters:
05202 **     libhandle -- DKIM_LIB handle
05203 **     id -- identification string (e.g. job ID) for logging
05204 **     memclosure -- memory closure for allocations (or NULL)
05205 **     statp -- status (returned)
05206 **
05207 **  Return value:
05208 **     A new signing handle, or NULL.
05209 */
05210 
05211 DKIM *
05212 dkim_verify(DKIM_LIB *libhandle, const unsigned char *id, void *memclosure,
05213             DKIM_STAT *statp)
05214 {
05215        DKIM *new;
05216 
05217        assert(libhandle != NULL);
05218        assert(statp != NULL);
05219 
05220        new = dkim_new(libhandle, id, memclosure, DKIM_CANON_UNKNOWN,
05221                       DKIM_CANON_UNKNOWN, DKIM_SIGN_UNKNOWN, statp);
05222 
05223        if (new != NULL)
05224               new->dkim_mode = DKIM_MODE_VERIFY;
05225 
05226        return new;
05227 }
05228 
05229 /*
05230 **  DKIM_RESIGN -- bind a new signing handle to a completed handle
05231 **
05232 **  Parameters:
05233 **     new -- new signing handle
05234 **     old -- old signing/verifying handle
05235 **     hdrbind -- bind "new"'s header canonicalization to "old" as well
05236 **                as the body
05237 **
05238 **  Return value:
05239 **     DKIM_STAT_OK -- success
05240 **     DKIM_STAT_INVALID -- invalid state of one or both handles
05241 **
05242 **  Side effects:
05243 **     Sets up flags such that the two are bound; dkim_free() on "old"
05244 **     is now an invalid operation until "new" has been free'd.
05245 */
05246 
05247 DKIM_STAT
05248 dkim_resign(DKIM *new, DKIM *old, _Bool hdrbind)
05249 {
05250 #ifdef _FFR_RESIGN
05251        _Bool keep;
05252        _Bool tmp;
05253        DKIM_STAT status;
05254        int hashtype = DKIM_HASHTYPE_UNKNOWN;
05255        DKIM_CANON *bc;
05256        DKIM_CANON *hc;
05257        DKIM_LIB *lib;
05258 
05259        assert(new != NULL);
05260        assert(old != NULL);
05261 
05262        if (new->dkim_mode != DKIM_MODE_SIGN ||
05263            new->dkim_state != DKIM_STATE_INIT)
05264               return DKIM_STAT_INVALID;
05265 
05266        if (old->dkim_mode != DKIM_MODE_VERIFY ||
05267            old->dkim_state >= DKIM_STATE_EOH1 ||
05268            old->dkim_resign != NULL)
05269               return DKIM_STAT_INVALID;
05270 
05271        new->dkim_resign = old;
05272        new->dkim_hdrbind = hdrbind;
05273        /* XXX -- should be mutex-protected? */
05274        old->dkim_refcnt++;
05275 
05276        lib = old->dkim_libhandle;
05277        assert(lib != NULL);
05278 
05279        tmp = ((lib->dkiml_flags & DKIM_LIBFLAGS_TMPFILES) != 0);
05280        keep = ((lib->dkiml_flags & DKIM_LIBFLAGS_KEEPFILES) != 0);
05281 
05282        new->dkim_version = lib->dkiml_version;
05283 
05284        /* determine hash type */
05285        switch (new->dkim_signalg)
05286        {
05287          case DKIM_SIGN_RSASHA1:
05288               hashtype = DKIM_HASHTYPE_SHA1;
05289               break;
05290 
05291          case DKIM_SIGN_RSASHA256:
05292               hashtype = DKIM_HASHTYPE_SHA256;
05293               break;
05294 
05295          default:
05296               assert(0);
05297               /* NOTREACHED */
05298        }
05299 
05300        /* initialize signature and canonicalization for signing */
05301        new->dkim_siglist = DKIM_MALLOC(new, sizeof(DKIM_SIGINFO *));
05302        if (new->dkim_siglist == NULL)
05303        {
05304               dkim_error(new, "failed to allocate %d byte(s)",
05305                          sizeof(DKIM_SIGINFO *));
05306               return DKIM_STAT_NORESOURCE;
05307        }
05308 
05309        new->dkim_siglist[0] = DKIM_MALLOC(new, sizeof(struct dkim_siginfo));
05310        if (new->dkim_siglist[0] == NULL)
05311        {
05312               dkim_error(new, "failed to allocate %d byte(s)",
05313                          sizeof(struct dkim_siginfo));
05314               return DKIM_STAT_NORESOURCE;
05315        }
05316 
05317        new->dkim_sigcount = 1;
05318        memset(new->dkim_siglist[0], '\0', sizeof(struct dkim_siginfo));
05319        new->dkim_siglist[0]->sig_domain = new->dkim_domain;
05320        new->dkim_siglist[0]->sig_selector = new->dkim_selector;
05321        new->dkim_siglist[0]->sig_hashtype = hashtype;
05322        new->dkim_siglist[0]->sig_signalg = new->dkim_signalg;
05323 
05324        status = dkim_add_canon(hdrbind ? old : new, TRUE,
05325                                new->dkim_hdrcanonalg, hashtype,
05326                                NULL, NULL, 0, &hc);
05327        if (status != DKIM_STAT_OK)
05328               return status;
05329 
05330        status = dkim_add_canon(old, FALSE, new->dkim_bodycanonalg,
05331                                hashtype, NULL, NULL, new->dkim_signlen, &bc);
05332        if (status != DKIM_STAT_OK)
05333               return status;
05334 
05335        new->dkim_siglist[0]->sig_hdrcanon = hc;
05336        new->dkim_siglist[0]->sig_hdrcanonalg = new->dkim_hdrcanonalg;
05337        new->dkim_siglist[0]->sig_bodycanon = bc;
05338        new->dkim_siglist[0]->sig_bodycanonalg = new->dkim_bodycanonalg;
05339 
05340        if (new->dkim_libhandle->dkiml_fixedtime != 0)
05341        {
05342               new->dkim_siglist[0]->sig_timestamp = new->dkim_libhandle->dkiml_fixedtime;
05343        }
05344        else
05345        {
05346               time_t now;
05347 
05348               (void) time(&now);
05349 
05350               new->dkim_siglist[0]->sig_timestamp = (uint64_t) now;
05351        }
05352 
05353        return DKIM_STAT_OK;
05354 #else /* _FFR_RESIGN */
05355        return DKIM_STAT_NOTIMPLEMENT;
05356 #endif /* _FFR_RESIGN */
05357 }
05358 
05359 /*
05360 **  DKIM_POLICY_STATE_NEW -- initialize and return a DKIM policy state handle
05361 **
05362 **  Parameters:
05363 **     dkim -- DKIM handle from which to do an allocation
05364 **
05365 **  Return value:
05366 **     A DKIM_PSTATE handle, or NULL on failure.
05367 */
05368 
05369 DKIM_PSTATE *
05370 dkim_policy_state_new(DKIM *dkim)
05371 {
05372        DKIM_PSTATE *ret;
05373 
05374        assert(dkim != NULL);
05375 
05376        ret = DKIM_MALLOC(dkim, sizeof(DKIM_PSTATE));
05377 
05378        if (ret != NULL)
05379        {
05380               memset(ret, '\0', sizeof(DKIM_PSTATE));
05381               ret->ps_dkim = dkim;
05382        }
05383 
05384        return ret;
05385 }
05386 
05387 /*
05388 **  DKIM_POLICY_STATE_FREE -- destroy a DKIM policy state handle
05389 **
05390 **  Parameters:
05391 **     pstate -- previously allocated policy state handle
05392 **
05393 **  Return value:
05394 **     None.
05395 */
05396 
05397 void
05398 dkim_policy_state_free(DKIM_PSTATE *pstate)
05399 {
05400        assert(pstate != NULL);
05401 
05402        DKIM_FREE(pstate->ps_dkim, pstate);
05403 }
05404 
05405 /*
05406 **  DKIM_POLICY -- parse policy associated with the sender's domain
05407 **
05408 **  Parameters:
05409 **     dkim -- DKIM handle
05410 **     pcode -- discovered policy (returned)
05411 **     pflags -- discovered policy flags (returned)
05412 **     pstate -- state, for re-entrancy (updated; can be NULL)
05413 **
05414 **  Return value:
05415 **     A DKIM_STAT_* constant.
05416 */
05417 
05418 DKIM_STAT
05419 dkim_policy(DKIM *dkim, dkim_policy_t *pcode, u_int *pflags,
05420             DKIM_PSTATE *pstate)
05421 {
05422        int wlen;
05423        int qstatus = NOERROR;
05424        unsigned int lpflags;
05425        DKIM_STAT status;
05426        dkim_policy_t policy = DKIM_POLICY_NONE;
05427        unsigned char query[DKIM_MAXHOSTNAMELEN + 1];
05428 
05429        assert(dkim != NULL);
05430 
05431        /* fail for signing handles */
05432        if (dkim->dkim_mode == DKIM_MODE_SIGN)
05433               return DKIM_STAT_INVALID;
05434 
05435        /* fail if no domain could be determined */
05436        if (dkim->dkim_domain == NULL)
05437               return DKIM_STAT_SYNTAX;
05438 
05439        /* initialize */
05440        dkim->dkim_presult = DKIM_PRESULT_NONE;
05441        if (pstate != NULL)
05442        {
05443               qstatus = pstate->ps_qstatus;
05444               policy = pstate->ps_policy;
05445               lpflags = pstate->ps_pflags;
05446        }
05447 
05448        /*
05449        **  Apply RFC5617: Verify domain existence.
05450        */
05451 
05452        if (pstate == NULL || pstate->ps_state < 1)
05453        {
05454               status = dkim_get_policy(dkim, dkim->dkim_domain, TRUE,
05455                                        &qstatus, &policy, &lpflags);
05456               if (status != DKIM_STAT_OK)
05457               {
05458                      if (status == DKIM_STAT_CBTRYAGAIN && pstate != NULL)
05459                      {
05460                             pstate->ps_qstatus = qstatus;
05461                             pstate->ps_policy = policy;
05462                             pstate->ps_pflags = lpflags;
05463                      }
05464 
05465                      return status;
05466               }
05467 
05468               if (pstate != NULL)
05469                      pstate->ps_state = 1;
05470        }
05471 
05472        if (qstatus == NXDOMAIN)
05473        {
05474               dkim->dkim_presult = DKIM_PRESULT_NXDOMAIN;
05475               if (pcode != NULL)
05476                      *pcode = policy;
05477               return DKIM_STAT_OK;
05478        }
05479 
05480        /*
05481        **  Apply RFC5617: Retrieve policy.
05482        */
05483 
05484        if (pstate == NULL || pstate->ps_state < 2)
05485        {
05486               wlen = snprintf((char *) query, sizeof query, "%s.%s.%s",
05487                               DKIM_DNSPOLICYNAME, DKIM_DNSKEYNAME,
05488                               dkim->dkim_domain);
05489               if (wlen >= sizeof query)
05490               {
05491                      dkim_error(dkim, "policy query name overflow");
05492                      return DKIM_STAT_NORESOURCE;
05493               }
05494 
05495               status = dkim_get_policy(dkim, query, FALSE,
05496                                        &qstatus, &policy, &lpflags);
05497               if (status != DKIM_STAT_OK)
05498               {
05499                      if (status == DKIM_STAT_CBTRYAGAIN && pstate != NULL)
05500                      {
05501                             pstate->ps_qstatus = qstatus;
05502                             pstate->ps_policy = policy;
05503                             pstate->ps_pflags = lpflags;
05504                      }
05505 
05506                      return status;
05507               }
05508 
05509               if (pstate != NULL)
05510                      pstate->ps_state = 2;
05511        }
05512 
05513        if (qstatus == NOERROR)
05514               dkim->dkim_presult = DKIM_PRESULT_FOUND;
05515        if (pcode != NULL)
05516               *pcode = policy;
05517        if (pflags != NULL)
05518               *pflags = lpflags;
05519 
05520        return DKIM_STAT_OK;
05521 }
05522 
05523 /*
05524 **  DKIM_POLICY_GETDNSSEC -- retrieve DNSSEC results for a policy
05525 **
05526 **  Parameters:
05527 **     dkim -- DKIM handle
05528 **
05529 **  Return value:
05530 **     A DKIM_DNSSEC_* constant.
05531 */
05532 
05533 int
05534 dkim_policy_getdnssec(DKIM *dkim)
05535 {
05536        assert(dkim != NULL);
05537 
05538        return dkim->dkim_dnssec_policy;
05539 }
05540 
05541 /*
05542 **  DKIM_POLICY_GETREPORTINFO -- retrieve reporting information from policy
05543 **
05544 **  Parameters:
05545 **     dkim -- DKIM handle
05546 **     addr -- address buffer (or NULL)
05547 **     addrlen -- size of addr
05548 **     opts -- options buffer (or NULL)
05549 **     optslen -- size of opts
05550 **     smtp -- SMTP prefix buffer (or NULL)
05551 **     smtplen -- size of smtp
05552 **     pct -- requested report percentage (or NULL)
05553 **
05554 **  Return value:
05555 **     A DKIM_STAT_* constant.
05556 */
05557 
05558 DKIM_STAT
05559 dkim_policy_getreportinfo(DKIM *dkim,
05560                           u_char *addr, size_t addrlen,
05561                           u_char *opts, size_t optslen,
05562                           u_char *smtp, size_t smtplen,
05563                           u_int *pct)
05564 {
05565        u_char *p;
05566        DKIM_SET *set;
05567 
05568        assert(dkim != NULL);
05569 
05570        if (dkim->dkim_state != DKIM_STATE_EOM2 ||
05571            dkim->dkim_mode != DKIM_MODE_VERIFY)
05572               return DKIM_STAT_INVALID;
05573 
05574        set = dkim_set_first(dkim, DKIM_SETTYPE_POLICY);
05575        if (set == NULL)
05576               return DKIM_STAT_CANTVRFY;
05577 
05578        if (addr != NULL)
05579        {
05580               p = dkim_param_get(set, (u_char *) "ra");
05581               if (p != NULL)
05582               {
05583                      memset(addr, '\0', addrlen);
05584                      (void) dkim_qp_decode(p, addr, addrlen - 1);
05585                      p = (u_char *) strchr((char *) addr, '@');
05586                      if (p != NULL)
05587                             *p = '\0';
05588               }
05589        }
05590 
05591        if (opts != NULL)
05592        {
05593               p = dkim_param_get(set, (u_char *) "ro");
05594               if (p != NULL)
05595                      strlcpy((char *) opts, (char *) p, optslen);
05596        }
05597 
05598        if (smtp != NULL)
05599        {
05600               p = dkim_param_get(set, (u_char *) "rs");
05601               if (p != NULL)
05602               {
05603                      memset(smtp, '\0', smtplen);
05604                      (void) dkim_qp_decode(p, smtp, smtplen - 1);
05605               }
05606        }
05607 
05608        if (pct != NULL)
05609        {
05610               p = dkim_param_get(set, (u_char *) "rp");
05611               if (p != NULL)
05612               {
05613                      u_int out;
05614                      char *q;
05615 
05616                      out = strtoul((char *) p, &q, 10);
05617                      if (*q == '\0')
05618                             *pct = out;
05619               }
05620        }
05621 
05622        return DKIM_STAT_OK;
05623 }
05624 
05625 /*
05626 **  DKIM_SIG_PROCESS -- process a signature
05627 **
05628 **  Parameters:
05629 **     dkim -- DKIM handle
05630 **     sig -- DKIM_SIGINFO handle
05631 **
05632 **  Return value:
05633 **     A DKIM_STAT_* constant.
05634 */
05635 
05636 DKIM_STAT
05637 dkim_sig_process(DKIM *dkim, DKIM_SIGINFO *sig)
05638 {
05639        DKIM_STAT status;
05640        int nid;
05641        int rsastat;
05642        size_t diglen = 0;
05643 #ifdef USE_GNUTLS
05644        gnutls_datum_t key;
05645 #else /* USE_GNUTLS */
05646        BIO *key;
05647 #endif /* USE_GNUTLS */
05648        u_char *digest = NULL;
05649        struct dkim_rsa *rsa;
05650 
05651        assert(dkim != NULL);
05652        assert(sig != NULL);
05653 
05654        /* skip it if we're supposed to ignore it */
05655        if ((sig->sig_flags & DKIM_SIGFLAG_IGNORE) != 0)
05656               return DKIM_STAT_OK;
05657 
05658        /* skip it if there was a syntax or other error */
05659        if (sig->sig_error != DKIM_SIGERROR_UNKNOWN)
05660               return DKIM_STAT_OK;
05661 
05662        /* skip the DNS part if we've already done it */
05663        if ((sig->sig_flags & DKIM_SIGFLAG_PROCESSED) == 0)
05664        {
05665               /* get the digest */
05666               status = dkim_canon_getfinal(sig->sig_hdrcanon, &digest,
05667                                            &diglen);
05668               if (status != DKIM_STAT_OK)
05669               {
05670                      dkim_error(dkim, "dkim_canon_getfinal() failed");
05671                      return DKIM_STAT_INTERNAL;
05672               }
05673               assert(digest != NULL && diglen != 0);
05674 
05675               /* retrieve the key */
05676               status = dkim_get_key(dkim, sig, FALSE);
05677               if (status == DKIM_STAT_NOKEY)
05678               {
05679                      sig->sig_flags |= DKIM_SIGFLAG_PROCESSED;
05680                      sig->sig_error = DKIM_SIGERROR_NOKEY;
05681                      return DKIM_STAT_OK;
05682               }
05683               else if (status == DKIM_STAT_KEYFAIL)
05684               {
05685                      sig->sig_flags |= DKIM_SIGFLAG_PROCESSED;
05686                      sig->sig_error = DKIM_SIGERROR_KEYFAIL;
05687                      return DKIM_STAT_OK;
05688               }
05689               else if (status == DKIM_STAT_CANTVRFY ||
05690                        status == DKIM_STAT_SYNTAX)
05691               {
05692                      sig->sig_flags |= DKIM_SIGFLAG_PROCESSED;
05693                      if (sig->sig_error == DKIM_SIGERROR_UNKNOWN)
05694                             sig->sig_error = DKIM_SIGERROR_DNSSYNTAX;
05695                      return DKIM_STAT_OK;
05696               }
05697               else if (status == DKIM_STAT_MULTIDNSREPLY)
05698               {
05699                      sig->sig_flags |= DKIM_SIGFLAG_PROCESSED;
05700                      sig->sig_error = DKIM_SIGERROR_MULTIREPLY;
05701                      return DKIM_STAT_OK;
05702               }
05703               else if (status == DKIM_STAT_REVOKED)
05704               {
05705                      sig->sig_flags |= DKIM_SIGFLAG_PROCESSED;
05706                      sig->sig_error = DKIM_SIGERROR_KEYREVOKED;
05707                      return DKIM_STAT_OK;
05708               }
05709               else if (status != DKIM_STAT_OK)
05710               {
05711                      return status;
05712               }
05713 
05714 #ifdef USE_GNUTLS
05715               key.data = sig->sig_key;
05716               key.size = sig->sig_keylen;
05717 #else /* USE_GNUTLS */
05718               /* load the public key */
05719               key = BIO_new_mem_buf(sig->sig_key, sig->sig_keylen);
05720               if (key == NULL)
05721               {
05722                      dkim_error(dkim, "BIO_new_mem_buf() failed");
05723                      return DKIM_STAT_NORESOURCE;
05724               }
05725 #endif /* USE_GNUTLS */
05726 
05727               /* set up to verify */
05728               if (sig->sig_signature == NULL)
05729               {
05730                      rsa = DKIM_MALLOC(dkim, sizeof(struct dkim_rsa));
05731                      if (rsa == NULL)
05732                      {
05733                             dkim_error(dkim,
05734                                        "unable to allocate %d byte(s)",
05735                                        sizeof(struct dkim_rsa));
05736 #ifndef USE_GNUTLS
05737                             BIO_free(key);
05738 #endif /* ! USE_GNUTLS */
05739                             return DKIM_STAT_NORESOURCE;
05740                      }
05741 
05742                      sig->sig_signature = rsa;
05743               }
05744               else
05745               {
05746                      rsa = sig->sig_signature;
05747               }
05748               memset(rsa, '\0', sizeof(struct dkim_rsa));
05749 
05750 #ifdef USE_GNUTLS
05751               rsa->rsa_sig.data = sig->sig_sig;
05752               rsa->rsa_sig.size = sig->sig_siglen;
05753 
05754               rsa->rsa_digest.data = digest;
05755               rsa->rsa_digest.size = diglen;
05756 
05757               if (gnutls_pubkey_init(&rsa->rsa_pubkey) != GNUTLS_E_SUCCESS)
05758               {
05759                      dkim_error(dkim,
05760                                 "s=%s d=%s: gnutls_pubkey_init() failed",
05761                                 dkim_sig_getselector(sig),
05762                                 dkim_sig_getdomain(sig));
05763 
05764                      sig->sig_error = DKIM_SIGERROR_KEYDECODE;
05765 
05766                      return DKIM_STAT_OK;
05767               }
05768 
05769               status = gnutls_pubkey_import(rsa->rsa_pubkey, &key,
05770                                             GNUTLS_X509_FMT_DER);
05771               if (status != GNUTLS_E_SUCCESS)
05772               {
05773                      dkim_error(dkim,
05774                                 "s=%s d=%s: gnutls_pubkey_import() failed",
05775                                 dkim_sig_getselector(sig),
05776                                 dkim_sig_getdomain(sig));
05777 
05778                      sig->sig_error = DKIM_SIGERROR_KEYDECODE;
05779 
05780                      return DKIM_STAT_OK;
05781               }
05782 
05783               rsastat = gnutls_pubkey_verify_hash(rsa->rsa_pubkey, 0,
05784                                                   &rsa->rsa_digest,
05785                                                   &rsa->rsa_sig);
05786 
05787               (void) gnutls_pubkey_get_pk_algorithm(rsa->rsa_pubkey,
05788                                                     &rsa->rsa_keysize);
05789 
05790               sig->sig_keybits = rsa->rsa_keysize;
05791 #else /* USE_GNUTLS */
05792               rsa->rsa_pkey = d2i_PUBKEY_bio(key, NULL);
05793               if (rsa->rsa_pkey == NULL)
05794               {
05795                      dkim_error(dkim, "s=%s d=%s: d2i_PUBKEY_bio() failed",
05796                                 dkim_sig_getselector(sig),
05797                                 dkim_sig_getdomain(sig));
05798                      BIO_free(key);
05799 
05800                      sig->sig_error = DKIM_SIGERROR_KEYDECODE;
05801 
05802                      return DKIM_STAT_OK;
05803               }
05804 
05805               /* set up the RSA object */
05806               rsa->rsa_rsa = EVP_PKEY_get1_RSA(rsa->rsa_pkey);
05807               if (rsa->rsa_rsa == NULL)
05808               {
05809                      dkim_error(dkim,
05810                                 "s=%s d=%s: EVP_PKEY_get1_RSA() failed",
05811                                 dkim_sig_getselector(sig),
05812                                 dkim_sig_getdomain(sig));
05813                      BIO_free(key);
05814 
05815                      sig->sig_error = DKIM_SIGERROR_KEYDECODE;
05816 
05817                      return DKIM_STAT_OK;
05818               }
05819 
05820               rsa->rsa_keysize = RSA_size(rsa->rsa_rsa);
05821               rsa->rsa_pad = RSA_PKCS1_PADDING;
05822 
05823               rsa->rsa_rsain = sig->sig_sig;
05824               rsa->rsa_rsainlen = sig->sig_siglen;
05825 
05826               sig->sig_keybits = 8 * rsa->rsa_keysize;
05827 
05828               nid = NID_sha1;
05829 
05830               if (dkim_libfeature(dkim->dkim_libhandle,
05831                                   DKIM_FEATURE_SHA256) &&
05832                   sig->sig_hashtype == DKIM_HASHTYPE_SHA256)
05833                      nid = NID_sha256;
05834 
05835               rsastat = RSA_verify(nid, digest, diglen, rsa->rsa_rsain,
05836                             rsa->rsa_rsainlen, rsa->rsa_rsa);
05837 
05838               BIO_free(key);
05839               RSA_free(rsa->rsa_rsa);
05840               rsa->rsa_rsa = NULL;
05841 #endif /* USE_GNUTLS */
05842 
05843               if (rsastat == 1)
05844                      sig->sig_flags |= DKIM_SIGFLAG_PASSED;
05845               else
05846                      sig->sig_error = DKIM_SIGERROR_BADSIG;
05847 
05848               sig->sig_flags |= DKIM_SIGFLAG_PROCESSED;
05849        }
05850 
05851        /* do the body hash check if possible */
05852        if (dkim->dkim_bodydone && sig->sig_bh == DKIM_SIGBH_UNTESTED &&
05853            (sig->sig_flags & DKIM_SIGFLAG_PASSED) != 0)
05854        {
05855               u_char *bhash;
05856               u_char b64buf[BUFRSZ];
05857 
05858               memset(b64buf, '\0', sizeof b64buf);
05859 
05860               dkim_canon_getfinal(sig->sig_bodycanon, &digest, &diglen);
05861 
05862               bhash = dkim_param_get(sig->sig_taglist, (u_char *) "bh");
05863 
05864               dkim_base64_encode(digest, diglen, b64buf, sizeof b64buf);
05865 
05866               if (strcmp((char *) bhash, (char *) b64buf) == 0)
05867                      sig->sig_bh = DKIM_SIGBH_MATCH;
05868               else
05869                      sig->sig_bh = DKIM_SIGBH_MISMATCH;
05870        }
05871 
05872        /*
05873        **  Fail if t=s was present in the key and the i= and d= domains
05874        **  don't match.
05875        */
05876 
05877        if ((sig->sig_flags & DKIM_SIGFLAG_NOSUBDOMAIN) != 0)
05878        {
05879               char *d;
05880               char *i;
05881 
05882               d = (char *) dkim_param_get(sig->sig_taglist, (u_char *) "d");
05883               i = (char *) dkim_param_get(sig->sig_taglist, (u_char *) "i");
05884 
05885               if (i != NULL && d != NULL)
05886               {
05887                      char *at;
05888 
05889                      at = strchr(i, '@');
05890                      if (at == NULL)
05891                             at = i;
05892                      else
05893                             at++;
05894 
05895                      if (strcasecmp(at, d) != 0)
05896                             sig->sig_error = DKIM_SIGERROR_SUBDOMAIN;
05897               }
05898        }
05899 
05900        /*
05901        **  Fail if the "must be signed" list was set and this signature didn't
05902        **  cover a must-be-signed header which was present.
05903        */
05904 
05905        if (dkim->dkim_libhandle->dkiml_mbs != NULL)
05906        {
05907               int c;
05908 
05909               for (c = 0; dkim->dkim_libhandle->dkiml_mbs[c] != NULL; c++)
05910               {
05911                      if (dkim_get_header(dkim,
05912                                          dkim->dkim_libhandle->dkiml_mbs[c],
05913                                          0, 0) != NULL &&
05914                          !dkim_sig_hdrsigned(sig,
05915                                              dkim->dkim_libhandle->dkiml_mbs[c]))
05916                      {
05917                             sig->sig_error = DKIM_SIGERROR_MBSFAILED;
05918                             break;
05919                      }
05920               }
05921        }
05922 
05923        if (sig->sig_error == DKIM_SIGERROR_UNKNOWN &&
05924            sig->sig_bh != DKIM_SIGBH_UNTESTED)
05925               sig->sig_error = DKIM_SIGERROR_OK;
05926 
05927        return DKIM_STAT_OK;
05928 }
05929 
05930 /*
05931 **  DKIM_OHDRS -- extract and decode original headers
05932 **
05933 **  Parameters:
05934 **     dkim -- DKIM handle
05935 **     sig -- DKIM_SIGINFO handle
05936 **     ptrs -- user-provided array of pointers to header strings (updated)
05937 **     pcnt -- number of pointers available (updated)
05938 **
05939 **  Return value:
05940 **     A DKIM_STAT_* constant.
05941 **
05942 **  Notes:
05943 **     If the returned value of pcnt is greater that what it was originally,
05944 **     then there were more headers than there were pointers.
05945 */
05946 
05947 DKIM_STAT
05948 dkim_ohdrs(DKIM *dkim, DKIM_SIGINFO *sig, u_char **ptrs, int *pcnt)
05949 {
05950        int n = 0;
05951        char *z;
05952        u_char *ch;
05953        u_char *p;
05954        u_char *q;
05955        char *last;
05956 
05957        assert(dkim != NULL);
05958        assert(ptrs != NULL);
05959        assert(pcnt != NULL);
05960 
05961        if (dkim->dkim_mode != DKIM_MODE_VERIFY)
05962               return DKIM_STAT_INVALID;
05963 
05964        /* pick the one we're going to use */
05965        if (sig == NULL)
05966        {
05967               int c;
05968 
05969               for (c = 0; c < dkim->dkim_sigcount; c++)
05970               {
05971                      sig = dkim->dkim_siglist[c];
05972                      if ((sig->sig_flags & DKIM_SIGFLAG_PROCESSED) != 0 &&
05973                          (sig->sig_flags & DKIM_SIGFLAG_IGNORE) == 0)
05974                             break;
05975 
05976                      sig = NULL;
05977               }
05978        }
05979 
05980        /* none useable; return error */
05981        if (sig == NULL)
05982               return DKIM_STAT_INVALID;
05983 
05984        /* find the tag */
05985        z = (char *) dkim_param_get(sig->sig_taglist, (u_char *) "z");
05986        if (z == NULL || *z == '\0')
05987        {
05988               *pcnt = 0;
05989               return DKIM_STAT_OK;
05990        }
05991 
05992        /* get memory for the decode */
05993        if (dkim->dkim_zdecode == NULL)
05994        {
05995               dkim->dkim_zdecode = DKIM_MALLOC(dkim, MAXHEADERS);
05996               if (dkim->dkim_zdecode == NULL)
05997               {
05998                      dkim_error(dkim, "unable to allocate %d byte(s)",
05999                                 strlen(z));
06000                      return DKIM_STAT_NORESOURCE;
06001               }
06002        }
06003 
06004        /* copy it */
06005        strlcpy((char *) dkim->dkim_zdecode, z, strlen(z));
06006 
06007        /* decode */
06008        for (ch = (u_char *) strtok_r(z, "|", &last);
06009             ch != NULL;
06010             ch = (u_char *) strtok_r(NULL, "|", &last))
06011        {
06012               for (p = ch, q = ch; *p != '\0'; p++)
06013               {
06014                      if (*p == '=')
06015                      {
06016                             char c;
06017 
06018                             if (!isxdigit(*(p + 1)) || !isxdigit(*(p + 2)))
06019                             {
06020                                    dkim_error(dkim,
06021                                               "invalid trailing character (0x%02x 0x%02x) in z= tag value",
06022                                               *(p + 1), *(p + 2));
06023 
06024                                    return DKIM_STAT_INVALID;
06025                             }
06026 
06027                             c = 16 * dkim_hexchar(*(p + 1)) + dkim_hexchar(*(p + 2));
06028 
06029                             p += 2;
06030 
06031                             *q = c;
06032                             q++;
06033                      }
06034                      else
06035                      {
06036                             if (q != p)
06037                                    *q = *p;
06038                             q++;
06039                      }
06040               }
06041 
06042               *q = '\0';
06043 
06044               if (n < *pcnt)
06045                      ptrs[n] = ch;
06046               n++;
06047        }
06048 
06049        *pcnt = n;
06050 
06051        return DKIM_STAT_OK;
06052 }
06053 
06054 /*
06055 **  DKIM_DIFFHEADERS -- compare original headers with received headers
06056 **
06057 **  Parameters:
06058 **     dkim -- DKIM handle
06059 **     canon -- header canonicalization mode in use
06060 **     maxcost -- maximum "cost" of changes to be reported
06061 **     ohdrs -- original headers, presumably extracted from a "z" tag
06062 **     nohdrs -- number of headers at "ohdrs" available
06063 **     out -- pointer to an array of struct dkim_hdrdiff objects (updated)
06064 **     nout -- counter of handles returned (updated)
06065 **
06066 **  Return value:
06067 **     A DKIM_STAT_* constant.
06068 **
06069 **  Side effects:
06070 **     A series of DKIM_HDRDIFF handles is allocated and must later be
06071 **     destroyed.
06072 */
06073 
06074 DKIM_STAT
06075 dkim_diffheaders(DKIM *dkim, dkim_canon_t canon, int maxcost,
06076                  char **ohdrs, int nohdrs,
06077                  struct dkim_hdrdiff **out, int *nout)
06078 {
06079 #ifdef _FFR_DIFFHEADERS
06080        int n = 0;
06081        int a = 0;
06082        int c;
06083        int status;
06084        u_char *p;
06085        u_char *q;
06086        u_char *end;
06087        void *cls;
06088        struct dkim_header *hdr;
06089        struct dkim_hdrdiff *diffs = NULL;
06090        struct dkim_dstring *tmphdr;
06091        struct dkim_dstring **cohdrs;
06092        DKIM_LIB *lib;
06093        regaparams_t params;
06094        regamatch_t matches;
06095        regex_t re;
06096        u_char restr[BUFRSZ + 1];
06097 
06098        assert(dkim != NULL);
06099        assert(out != NULL);
06100        assert(nout != NULL);
06101 
06102        if (dkim->dkim_mode != DKIM_MODE_VERIFY)
06103               return DKIM_STAT_INVALID;
06104        if (maxcost == 0)
06105               return DKIM_STAT_INVALID;
06106 
06107        tmphdr = dkim_dstring_new(dkim, BUFRSZ, MAXBUFRSZ);
06108        if (tmphdr == NULL)
06109        {
06110               dkim_error(dkim, "failed to allocate dynamic string");
06111               return DKIM_STAT_NORESOURCE;
06112        }
06113 
06114        lib = dkim->dkim_libhandle;
06115        cls = dkim->dkim_closure;
06116 
06117        memset(&params, '\0', sizeof params);
06118 
06119        params.cost_ins = COST_INSERT;
06120        params.cost_del = COST_DELETE;
06121        params.cost_subst = COST_SUBST;
06122 
06123        params.max_cost = maxcost;
06124        params.max_ins = DKIM_MAXHEADER;
06125        params.max_del = DKIM_MAXHEADER;
06126        params.max_subst = DKIM_MAXHEADER;
06127        params.max_err = maxcost;
06128 
06129        matches.nmatch = 0;
06130        matches.pmatch = NULL;
06131 
06132        /* canonicalize all the original header fields */
06133        cohdrs = DKIM_MALLOC(dkim, sizeof(struct dkim_dstring *) * nohdrs);
06134        if (cohdrs == NULL)
06135        {
06136               dkim_error(dkim, strerror(errno));
06137               return DKIM_STAT_NORESOURCE;
06138        }
06139 
06140        for (c = 0; c < nohdrs; c++)
06141        {
06142               cohdrs[c] = dkim_dstring_new(dkim, DKIM_MAXHEADER, 0);
06143               if (cohdrs[c] == NULL)
06144               {
06145                      for (n = 0; n < c; n++)
06146                             dkim_dstring_free(cohdrs[n]);
06147 
06148                      DKIM_FREE(dkim, cohdrs);
06149 
06150                      dkim_error(dkim, strerror(errno));
06151 
06152                      return DKIM_STAT_NORESOURCE;
06153               }
06154 
06155               status = dkim_canon_header_string(cohdrs[c], canon,
06156                                                 ohdrs[c], strlen(ohdrs[c]),
06157                                                 FALSE);
06158               if (status != DKIM_STAT_OK)
06159               {
06160                      for (n = 0; n < c; n++)
06161                             dkim_dstring_free(cohdrs[n]);
06162 
06163                      DKIM_FREE(dkim, cohdrs);
06164 
06165                      dkim_error(dkim, strerror(errno));
06166 
06167                      return status;
06168               }
06169        }
06170 
06171        for (hdr = dkim->dkim_hhead; hdr != NULL; hdr = hdr->hdr_next)
06172        {
06173               dkim_dstring_blank(tmphdr);
06174 
06175               status = dkim_canon_header_string(tmphdr, canon,
06176                                                 hdr->hdr_text,
06177                                                 hdr->hdr_textlen, FALSE);
06178               if (status != DKIM_STAT_OK)
06179               {
06180                      dkim_dstring_free(tmphdr);
06181                      for (c = 0; c < nohdrs; c++)
06182                             dkim_dstring_free(cohdrs[c]);
06183                      DKIM_FREE(dkim, cohdrs);
06184                      return status;
06185               }
06186 
06187               memset(restr, '\0', sizeof restr);
06188 
06189               end = restr + sizeof restr;
06190 
06191               for (p = dkim_dstring_get(tmphdr), q = restr;
06192                    *p != '\0' && q < end - 3;
06193                    p++)
06194               {
06195                      if (q == restr)
06196                             *q++ = '^';
06197 
06198                      if (*p == '*' ||
06199                          *p == '\\' ||
06200                          *p == '$' ||
06201                          *p == '+' ||
06202                          *p == '[' ||
06203                          *p == ']' ||
06204                          *p == '(' ||
06205                          *p == ')' ||
06206                          *p == '.' ||
06207                          *p == '|')
06208                             *q++ = '\\';
06209 
06210                      *q++ = *p;
06211               }
06212 
06213               *q = '$';
06214 
06215               status = tre_regcomp(&re, restr, REG_NOSUB);
06216               if (status != 0)
06217               {
06218                      char err[BUFRSZ + 1];
06219 
06220                      memset(err, '\0', sizeof err);
06221 
06222                      (void) tre_regerror(status, &re, err, sizeof err);
06223 
06224                      dkim_error(dkim, err);
06225 
06226                      if (diffs != NULL)
06227                             dkim_mfree(lib, cls, diffs);
06228 
06229                      dkim_dstring_free(tmphdr);
06230                      for (c = 0; c < nohdrs; c++)
06231                             dkim_dstring_free(cohdrs[c]);
06232                      DKIM_FREE(dkim, cohdrs);
06233 
06234                      return DKIM_STAT_INTERNAL;
06235               }
06236 
06237               for (c = 0; c < nohdrs; c++)
06238               {
06239                      /* not even the same header field */
06240                      if (hdr->hdr_namelen != hdr->hdr_textlen &&
06241                          strncmp(dkim_dstring_get(cohdrs[c]),
06242                                  dkim_dstring_get(tmphdr),
06243                                  hdr->hdr_namelen + 1) != 0)
06244                             continue;
06245 
06246                      /* same, no changes at all */
06247                      if (strcmp(dkim_dstring_get(cohdrs[c]),
06248                                 dkim_dstring_get(tmphdr)) == 0)
06249                             continue;
06250 
06251                      /* check for approximate match */
06252                      status = tre_regaexec(&re, dkim_dstring_get(cohdrs[c]),
06253                                            &matches, params, 0);
06254 
06255                      if (status == 0)
06256                      {
06257                             if (n + 1 > a)
06258                             {
06259                                    int sz;
06260                                    struct dkim_hdrdiff *new;
06261 
06262                                    if (a == 0)
06263                                           a = 16;
06264                                    else
06265                                           a *= 2;
06266 
06267                                    sz = a * sizeof(struct dkim_hdrdiff);
06268 
06269                                    new = (struct dkim_hdrdiff *) dkim_malloc(lib,
06270                                                                              cls,
06271                                                                              sz);
06272 
06273                                    if (new == NULL)
06274                                    {
06275                                           dkim_error(dkim,
06276                                                      "unable to allocate %d byte(s)",
06277                                                      sz);
06278 
06279                                           if (diffs != NULL)
06280                                           {
06281                                                  dkim_mfree(lib, cls,
06282                                                             diffs);
06283                                           }
06284 
06285                                           dkim_dstring_free(tmphdr);
06286                                           for (c = 0; c < nohdrs; c++)
06287                                                  dkim_dstring_free(cohdrs[c]);
06288                                           DKIM_FREE(dkim, cohdrs);
06289 
06290                                           return DKIM_STAT_NORESOURCE;
06291                                    }
06292 
06293                                    dkim_mfree(lib, cls, diffs);
06294 
06295                                    diffs = new;
06296 
06297                                    sz = (a - n) & sizeof(struct dkim_hdrdiff);
06298                                    memset(&diffs[n], '\0', sz);
06299                             }
06300 
06301                             diffs[n].hd_old = ohdrs[c];
06302                             diffs[n].hd_new = hdr->hdr_text;
06303 
06304                             n++;
06305                      }
06306               }
06307 
06308               tre_regfree(&re);
06309        }
06310 
06311        *out = diffs;
06312        *nout = n;
06313 
06314        dkim_dstring_free(tmphdr);
06315        for (c = 0; c < nohdrs; c++)
06316               dkim_dstring_free(cohdrs[c]);
06317        DKIM_FREE(dkim, cohdrs);
06318 
06319        return DKIM_STAT_OK;
06320 #else /* _FFR_DIFFHEADERS */
06321        return DKIM_STAT_NOTIMPLEMENT;
06322 #endif /* _FFR_DIFFHEADERS */
06323 }
06324 
06325 /*
06326 **  DKIM_HEADER -- process a header
06327 **
06328 **  Parameters:
06329 **     dkim -- DKIM handle
06330 **     hdr -- header text
06331 **     len -- bytes available at "hdr"
06332 **
06333 **  Return value:
06334 **     A DKIM_STAT_* constant.
06335 */
06336 
06337 DKIM_STAT
06338 dkim_header(DKIM *dkim, u_char *hdr, size_t len)
06339 {
06340        u_char *colon;
06341        u_char *semicolon;
06342        u_char *end = NULL;
06343        struct dkim_header *h;
06344 
06345        assert(dkim != NULL);
06346        assert(hdr != NULL);
06347        assert(len != 0);
06348 
06349 #ifdef _FFR_RESIGN
06350        if (dkim->dkim_hdrbind)
06351               return DKIM_STAT_INVALID;
06352 #endif /* _FFR_RESIGN */
06353 
06354        if (dkim->dkim_state > DKIM_STATE_HEADER)
06355               return DKIM_STAT_INVALID;
06356        dkim->dkim_state = DKIM_STATE_HEADER;
06357 
06358        colon = memchr(hdr, ':', len);
06359        if (colon != NULL)
06360        {
06361               end = colon;
06362 
06363               while (end > hdr && isascii(*(end - 1)) && isspace(*(end - 1)))
06364                      end--;
06365        }
06366 
06367        /* don't allow a field name containing a semicolon */
06368        semicolon = memchr(hdr, ';', len);
06369        if (semicolon != NULL && colon != NULL && semicolon < colon)
06370               return DKIM_STAT_SYNTAX;
06371 
06372        /* see if this is one we should skip */
06373        if (dkim->dkim_mode == DKIM_MODE_SIGN &&
06374            dkim->dkim_libhandle->dkiml_skipre)
06375        {
06376               int status;
06377               unsigned char name[DKIM_MAXHEADER + 1];
06378 
06379               strlcpy((char *) name, (char *) hdr, sizeof name);
06380               if (end != NULL)
06381                      name[end - hdr] = '\0';
06382 
06383               status = regexec(&dkim->dkim_libhandle->dkiml_skiphdrre,
06384                                (char *) name, 0, NULL, 0);
06385 
06386               if (status == 0)
06387                      return DKIM_STAT_OK;
06388               else
06389                      assert(status == REG_NOMATCH);
06390        }
06391 
06392        h = DKIM_MALLOC(dkim, sizeof(struct dkim_header));
06393 
06394        if (h == NULL)
06395        {
06396               dkim_error(dkim, "unable to allocate %d byte(s)",
06397                          sizeof(struct dkim_header));
06398               return DKIM_STAT_NORESOURCE;
06399        }
06400 
06401        if ((dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_FIXCRLF) != 0)
06402        {
06403               u_char prev = '\0';
06404               u_char *p;
06405               struct dkim_dstring *tmphdr;
06406 
06407               tmphdr = dkim_dstring_new(dkim, BUFRSZ, MAXBUFRSZ);
06408               if (tmphdr == NULL)
06409               {
06410                      DKIM_FREE(dkim, h);
06411                      return DKIM_STAT_NORESOURCE;
06412               }
06413 
06414               for (p = hdr; *p != '\0'; p++)
06415               {
06416                      if (*p == '\n' && prev != '\r')           /* bare LF */
06417                      {
06418                             dkim_dstring_catn(tmphdr, CRLF, 2);
06419                      }
06420                      else if (prev == '\r' && *p != '\n')      /* bare CR */
06421                      {
06422                             dkim_dstring_cat1(tmphdr, '\n');
06423                             dkim_dstring_cat1(tmphdr, *p);
06424                      }
06425                      else                               /* other */
06426                      {
06427                             dkim_dstring_cat1(tmphdr, *p);
06428                      }
06429 
06430                      prev = *p;
06431               }
06432 
06433               if (prev == '\r')                         /* end CR */
06434                      dkim_dstring_cat1(tmphdr, '\n');
06435 
06436               h->hdr_text = dkim_strdup(dkim, dkim_dstring_get(tmphdr),
06437                                         dkim_dstring_len(tmphdr));
06438 
06439               dkim_dstring_free(tmphdr);
06440        }
06441        else
06442        {
06443               h->hdr_text = dkim_strdup(dkim, hdr, len);
06444        }
06445 
06446        if (h->hdr_text == NULL)
06447        {
06448               DKIM_FREE(dkim, h);
06449               return DKIM_STAT_NORESOURCE;
06450        }
06451 
06452        h->hdr_namelen = end != NULL ? end - hdr : len;
06453        h->hdr_textlen = len;
06454        if (colon == NULL)
06455               h->hdr_colon = NULL;
06456        else
06457               h->hdr_colon = h->hdr_text + (colon - hdr);
06458        h->hdr_flags = 0;
06459        h->hdr_next = NULL;
06460 
06461        if (dkim->dkim_hhead == NULL)
06462        {
06463               dkim->dkim_hhead = h;
06464               dkim->dkim_htail = h;
06465        }
06466        else
06467        {
06468               dkim->dkim_htail->hdr_next = h;
06469               dkim->dkim_htail = h;
06470        }
06471 
06472        dkim->dkim_hdrcnt++;
06473 
06474        if (h->hdr_colon != NULL)
06475        {
06476               if (h->hdr_namelen == DKIM_SIGNHEADER_LEN &&
06477                   strncasecmp((char *) hdr, DKIM_SIGNHEADER,
06478                               DKIM_SIGNHEADER_LEN) == 0)
06479               {
06480                      DKIM_STAT status;
06481                      size_t plen;
06482 
06483                      plen = len - (h->hdr_colon - h->hdr_text) - 1;
06484                      status = dkim_process_set(dkim, DKIM_SETTYPE_SIGNATURE,
06485                                                h->hdr_colon + 1, plen, h,
06486                                                FALSE, NULL);
06487 
06488                      if (status != DKIM_STAT_OK)
06489                             return status;
06490               }
06491        }
06492 
06493        return DKIM_STAT_OK;
06494 }
06495 
06496 /*
06497 **  DKIM_EOH -- declare end-of-headers
06498 ** 
06499 **  Parameters:
06500 **     dkim -- DKIM handle
06501 **
06502 **  Return value:
06503 **     A DKIM_STAT_* constant.
06504 */
06505 
06506 DKIM_STAT
06507 dkim_eoh(DKIM *dkim)
06508 {
06509        assert(dkim != NULL);
06510 
06511        if (dkim->dkim_mode == DKIM_MODE_VERIFY)
06512               return dkim_eoh_verify(dkim);
06513        else
06514               return dkim_eoh_sign(dkim);
06515 }
06516 
06517 /*
06518 **  DKIM_BODY -- pass a body chunk in for processing
06519 **
06520 **  Parameters:
06521 **     dkim -- DKIM handle
06522 **     buf -- body chunk
06523 **     buflen -- number of bytes at "buf"
06524 **
06525 **  Return value:
06526 **     A DKIM_STAT_* constant.
06527 */
06528 
06529 DKIM_STAT
06530 dkim_body(DKIM *dkim, u_char *buf, size_t buflen)
06531 {
06532        assert(dkim != NULL);
06533        assert(buf != NULL);
06534 
06535 #ifdef _FFR_RESIGN
06536        if (dkim->dkim_resign != NULL)
06537               return DKIM_STAT_INVALID;
06538 #endif /* _FFR_RESIGN */
06539 
06540        if (dkim->dkim_state > DKIM_STATE_BODY ||
06541            dkim->dkim_state < DKIM_STATE_EOH1)
06542               return DKIM_STAT_INVALID;
06543        dkim->dkim_state = DKIM_STATE_BODY;
06544 
06545        if (dkim->dkim_skipbody)
06546               return DKIM_STAT_OK;
06547 
06548        return dkim_canon_bodychunk(dkim, buf, buflen);
06549 }
06550 
06551 /*
06552 **  DKIM_EOM -- declare end-of-body; conduct verification or signing
06553 **
06554 **  Parameters:
06555 **     dkim -- DKIM handle
06556 **     testkey -- TRUE iff the a matching key was found but is marked as a
06557 **                test key (returned)
06558 **
06559 **  Return value:
06560 **     A DKIM_STAT_* constant.
06561 */
06562 
06563 DKIM_STAT
06564 dkim_eom(DKIM *dkim, _Bool *testkey)
06565 {
06566        assert(dkim != NULL);
06567 
06568        if (dkim->dkim_mode == DKIM_MODE_SIGN)
06569               return dkim_eom_sign(dkim);
06570        else
06571               return dkim_eom_verify(dkim, testkey);
06572 }
06573 
06574 /*
06575 **  DKIM_CHUNK -- process a message chunk
06576 **
06577 **  Parameters:
06578 **     dkim -- DKIM handle
06579 **     buf -- data to process
06580 **     buflen -- number of bytes at "buf" to process
06581 **
06582 **  Return value:
06583 **     A DKIM_STAT_* constant.
06584 */
06585 
06586 DKIM_STAT
06587 dkim_chunk(DKIM *dkim, u_char *buf, size_t buflen)
06588 {
06589        _Bool bso;
06590        DKIM_STAT status;
06591        unsigned char *p;
06592        unsigned char *end;
06593 
06594        assert(dkim != NULL);
06595 
06596        bso = ((dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_BADSIGHANDLES) != 0);
06597 
06598        if ((dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_FIXCRLF) == 0)
06599               dkim->dkim_chunkcrlf = DKIM_CRLF_CRLF;
06600 
06601        /* verify chunking state */
06602        if (dkim->dkim_chunkstate >= DKIM_CHUNKSTATE_DONE)
06603        {
06604               return DKIM_STAT_INVALID;
06605        }
06606        else if (dkim->dkim_chunkstate == DKIM_CHUNKSTATE_INIT)
06607        {
06608               if (dkim->dkim_hdrbuf == NULL)
06609               {
06610                      dkim->dkim_hdrbuf = dkim_dstring_new(dkim, BUFRSZ,
06611                                                           MAXBUFRSZ);
06612                      if (dkim->dkim_hdrbuf == NULL)
06613                             return DKIM_STAT_NORESOURCE;
06614               }
06615               else
06616               {
06617                      dkim_dstring_blank(dkim->dkim_hdrbuf);
06618               }
06619 
06620               dkim->dkim_chunkstate = DKIM_CHUNKSTATE_HEADER;
06621               dkim->dkim_chunksm = 0;
06622        }
06623 
06624        /* process an "end" call */
06625        if (buf == NULL || buflen == 0)
06626        {
06627               if (dkim->dkim_chunkstate == DKIM_CHUNKSTATE_HEADER)
06628               {
06629                      if (dkim_dstring_len(dkim->dkim_hdrbuf) > 0)
06630                      {
06631                             status = dkim_header(dkim,
06632                                                  dkim_dstring_get(dkim->dkim_hdrbuf),
06633                                                  dkim_dstring_len(dkim->dkim_hdrbuf));
06634                             if (status != DKIM_STAT_OK &&
06635                                 !(status == DKIM_STAT_SYNTAX && bso))
06636                                    return status;
06637                      }
06638 
06639                      status = dkim_eoh(dkim);
06640                      if (status != DKIM_STAT_OK)
06641                             return status;
06642               }
06643 
06644               dkim->dkim_chunkstate = DKIM_CHUNKSTATE_DONE;
06645 
06646               return DKIM_STAT_OK;
06647        }
06648 
06649        /* if we're in body state, just call dkim_body() */
06650        if (dkim->dkim_chunkstate == DKIM_CHUNKSTATE_BODY)
06651               return dkim_body(dkim, buf, buflen);
06652 
06653        assert(dkim->dkim_chunkstate == DKIM_CHUNKSTATE_HEADER);
06654 
06655        end = buf + buflen - 1;
06656 
06657        /* process headers */
06658        for (p = buf; p <= end; p++)
06659        {
06660               switch (dkim->dkim_chunksm)
06661               {
06662                 case 0:
06663                      if (*p == '\n' &&
06664                          dkim->dkim_chunkcrlf != DKIM_CRLF_CRLF)
06665                      {
06666                             dkim->dkim_chunkcrlf = DKIM_CRLF_LF;
06667 
06668                             /*
06669                             **  If this is a CRLF up front, change state
06670                             **  and write the rest as part of the body.
06671                             */
06672 
06673                             if (dkim->dkim_hhead == NULL &&
06674                                 dkim_dstring_len(dkim->dkim_hdrbuf) == 2)
06675                             {
06676                                    status = dkim_eoh(dkim);
06677                                    if (status != DKIM_STAT_OK)
06678                                           return status;
06679 
06680                                    dkim->dkim_chunkstate = DKIM_CHUNKSTATE_BODY;
06681                                    if (p < end)
06682                                    {
06683                                           return dkim_body(dkim, p + 1,
06684                                                            end - p);
06685                                    }
06686                                    else
06687                                    {
06688                                           return DKIM_STAT_OK;
06689                                    }
06690                             }
06691 
06692                             dkim_dstring_catn(dkim->dkim_hdrbuf, CRLF, 2);
06693                             dkim->dkim_chunksm = 2;
06694                      }
06695                      else
06696                      {
06697                             dkim_dstring_cat1(dkim->dkim_hdrbuf, *p);
06698                             if (*p == '\r')
06699                                    dkim->dkim_chunksm = 1;
06700                      }
06701                      break;
06702 
06703                 case 1:
06704                      dkim_dstring_cat1(dkim->dkim_hdrbuf, *p);
06705                      if (*p == '\n')
06706                      {
06707                             if (dkim->dkim_chunkcrlf == DKIM_CRLF_UNKNOWN)
06708                                    dkim->dkim_chunkcrlf = DKIM_CRLF_CRLF;
06709 
06710                             /*
06711                             **  If this is a CRLF up front, change state
06712                             **  and write the rest as part of the body.
06713                             */
06714 
06715                             if (dkim->dkim_hhead == NULL &&
06716                                 dkim_dstring_len(dkim->dkim_hdrbuf) == 2)
06717                             {
06718                                    status = dkim_eoh(dkim);
06719                                    if (status != DKIM_STAT_OK)
06720                                           return status;
06721 
06722                                    dkim->dkim_chunkstate = DKIM_CHUNKSTATE_BODY;
06723                                    if (p < end)
06724                                    {
06725                                           return dkim_body(dkim, p + 1,
06726                                                            end - p);
06727                                    }
06728                                    else
06729                                    {
06730                                           return DKIM_STAT_OK;
06731                                    }
06732                             }
06733 
06734                             dkim->dkim_chunksm = 2;
06735                      }
06736                      else if (*p != '\r')
06737                      {
06738                             dkim->dkim_chunksm = 0;
06739                      }
06740                      break;
06741                      
06742                 case 2:
06743                      if (DKIM_ISLWSP(*p))
06744                      {
06745                             dkim_dstring_cat1(dkim->dkim_hdrbuf, *p);
06746                             dkim->dkim_chunksm = 0;
06747                             break;
06748                      }
06749                      else if (*p == '\r' &&
06750                               dkim->dkim_chunkcrlf == DKIM_CRLF_CRLF)
06751                      {
06752                             dkim->dkim_chunksm = 3;
06753                             break;
06754                      }
06755                      else if (*p != '\n' ||
06756                               dkim->dkim_chunkcrlf != DKIM_CRLF_LF)
06757                      {
06758                             status = dkim_header(dkim,
06759                                                  dkim_dstring_get(dkim->dkim_hdrbuf),
06760                                                  dkim_dstring_len(dkim->dkim_hdrbuf) - 2);
06761                             if (status != DKIM_STAT_OK &&
06762                                 !(status == DKIM_STAT_SYNTAX && bso))
06763                                    return status;
06764 
06765                             dkim_dstring_blank(dkim->dkim_hdrbuf);
06766                             dkim_dstring_cat1(dkim->dkim_hdrbuf, *p);
06767                             dkim->dkim_chunksm = 0;
06768                             break;
06769                      }
06770                      /* FALLTHROUGH */
06771                             
06772                 case 3:
06773                      if (*p == '\n')
06774                      {
06775                             if (dkim_dstring_len(dkim->dkim_hdrbuf) > 0)
06776                             {
06777                                    status = dkim_header(dkim,
06778                                                         dkim_dstring_get(dkim->dkim_hdrbuf),
06779                                                         dkim_dstring_len(dkim->dkim_hdrbuf) - 2);
06780                                    if (status != DKIM_STAT_OK &&
06781                                        !(status == DKIM_STAT_SYNTAX &&
06782                                          bso))
06783                                           return status;
06784                             }
06785 
06786                             status = dkim_eoh(dkim);
06787                             if (status != DKIM_STAT_OK)
06788                                    return status;
06789 
06790                             dkim->dkim_chunkstate = DKIM_CHUNKSTATE_BODY;
06791 
06792                             if (p < end)
06793                                    return dkim_body(dkim, p + 1, end - p);
06794                             else
06795                                    return DKIM_STAT_OK;
06796                      }
06797                      else
06798                      {
06799                             status = dkim_header(dkim,
06800                                                  dkim_dstring_get(dkim->dkim_hdrbuf),
06801                                                  dkim_dstring_len(dkim->dkim_hdrbuf) - 2);
06802                             if (status != DKIM_STAT_OK &&
06803                                 !(status == DKIM_STAT_SYNTAX && bso))
06804                                    return status;
06805 
06806                             dkim_dstring_blank(dkim->dkim_hdrbuf);
06807                             dkim_dstring_cat1(dkim->dkim_hdrbuf, '\r');
06808                             dkim_dstring_cat1(dkim->dkim_hdrbuf, *p);
06809                             dkim->dkim_chunksm = 0;
06810                      }
06811                      break;
06812 
06813                 default:
06814                      assert(0);
06815                      /* NOTREACHED */
06816               }
06817        }
06818 
06819        return DKIM_STAT_OK;
06820 }
06821 
06822 /*
06823 **  DKIM_MINBODY -- return number of bytes still expected
06824 **
06825 **  Parameters:
06826 **     dkim -- DKIM handle
06827 **
06828 **  Return value:
06829 **     0 -- all canonicalizations satisfied
06830 **     ULONG_MAX -- at least one canonicalization wants the whole message
06831 **     other -- bytes required to satisfy all canonicalizations
06832 */
06833 
06834 u_long
06835 dkim_minbody(DKIM *dkim)
06836 {
06837        assert(dkim != NULL);
06838 
06839        return dkim_canon_minbody(dkim);
06840 }
06841 
06842 /*
06843 **  DKIM_KEY_SYNTAX -- process a key record parameter set for valid syntax
06844 **
06845 **  Parameters:
06846 **     dkim -- DKIM context in which this is performed
06847 **     str -- string to be scanned
06848 **     len -- number of bytes available at "str"
06849 **
06850 **  Return value:
06851 **     A DKIM_STAT constant.
06852 */
06853 
06854 DKIM_STAT
06855 dkim_key_syntax(DKIM *dkim, u_char *str, size_t len)
06856 {
06857        return dkim_process_set(dkim, DKIM_SETTYPE_KEY, str, len, NULL, TRUE,
06858                                NULL);
06859 }
06860 
06861 /*
06862 **  DKIM_POLICY_SYNTAX -- process a policy record parameter set
06863 **                        for valid syntax
06864 **
06865 **  Parameters:
06866 **     dkim -- DKIM context in which this is performed
06867 **     str -- string to be scanned
06868 **     len -- number of bytes available at "str"
06869 **
06870 **  Return value:
06871 **     A DKIM_STAT constant.
06872 */
06873 
06874 DKIM_STAT
06875 dkim_policy_syntax(DKIM *dkim, u_char *str, size_t len)
06876 {
06877        return dkim_process_set(dkim, DKIM_SETTYPE_POLICY, str, len,
06878                                NULL, TRUE, NULL);
06879 }
06880 
06881 /*
06882 **  DKIM_SIG_SYNTAX -- process a signature parameter set for valid syntax
06883 **
06884 **  Parameters:
06885 **     dkim -- DKIM context in which this is performed
06886 **     str -- string to be scanned
06887 **     len -- number of bytes available at "str"
06888 **
06889 **  Return value:
06890 **     A DKIM_STAT constant.
06891 */
06892 
06893 DKIM_STAT
06894 dkim_sig_syntax(DKIM *dkim, u_char *str, size_t len)
06895 {
06896        return dkim_process_set(dkim, DKIM_SETTYPE_SIGNATURE, str, len,
06897                                NULL, TRUE, NULL);
06898 }
06899 
06900 /*
06901 **  DKIM_GETID -- retrieve "id" pointer from a handle
06902 **
06903 **  Parameters:
06904 **     dkim -- DKIM handle
06905 **
06906 **  Return value:
06907 **     The "id" pointer from inside the handle, stored when it was created.
06908 */
06909 
06910 const char *
06911 dkim_getid(DKIM *dkim)
06912 {
06913        assert(dkim != NULL);
06914 
06915        return dkim->dkim_id;
06916 }
06917 
06918 /*
06919 **  DKIM_GETSIGLIST -- retrieve the list of signatures
06920 **
06921 **  Parameters:
06922 **     dkim -- DKIM handle
06923 **     sigs -- pointer to a vector of DKIM_SIGINFO pointers (updated)
06924 **     nsigs -- pointer to an integer to receive the pointer count (updated)
06925 **
06926 **  Return value:
06927 **     A DKIM_STAT_* constant.
06928 */
06929 
06930 DKIM_STAT
06931 dkim_getsiglist(DKIM *dkim, DKIM_SIGINFO ***sigs, int *nsigs)
06932 {
06933        assert(dkim != NULL);
06934        assert(sigs != NULL);
06935        assert(nsigs != NULL);
06936 
06937        if (dkim->dkim_state < DKIM_STATE_EOH2)
06938               return DKIM_STAT_INVALID;
06939 
06940        *sigs = dkim->dkim_siglist;
06941        *nsigs = dkim->dkim_sigcount;
06942 
06943        return DKIM_STAT_OK;
06944 }
06945 
06946 /*
06947 **  DKIM_GETSIGNATURE -- retrieve the "final" signature
06948 **
06949 **  Parameters:
06950 **     dkim -- DKIM handle
06951 **
06952 **  Return value:
06953 **     Pointer to a DKIM_SIGINFO handle which is the one libopendkim will
06954 **     use to return a "final" result; NULL if none could be determined.
06955 */
06956 
06957 DKIM_SIGINFO *
06958 dkim_getsignature(DKIM *dkim)
06959 {
06960        assert(dkim != NULL);
06961 
06962        return dkim->dkim_signature;
06963 }
06964 
06965 /*
06966 **  DKIM_GETSIGHDR_D -- for signing operations, retrieve the complete signature
06967 **                      header, doing so dynamically
06968 **
06969 **  Parameters:
06970 **     dkim -- DKIM handle
06971 **     initial -- initial line width
06972 **     buf -- pointer to buffer containing the signature (returned)
06973 **     buflen -- number of bytes at "buf" (returned)
06974 **
06975 **  Return value:
06976 **     A DKIM_STAT_* constant.
06977 **
06978 **  Notes:
06979 **     Per RFC6376 Section 3.7, the signature header returned here does
06980 **     not contain a trailing CRLF.
06981 */
06982 
06983 DKIM_STAT
06984 dkim_getsighdr_d(DKIM *dkim, size_t initial, u_char **buf, size_t *buflen)
06985 {
06986        size_t len;
06987        char *ctx;
06988        char *pv;
06989        DKIM_SIGINFO *sig;
06990        struct dkim_dstring *tmpbuf;
06991 
06992        assert(dkim != NULL);
06993        assert(buf != NULL);
06994        assert(buflen != NULL);
06995 
06996        if (dkim->dkim_state != DKIM_STATE_EOM2 ||
06997            dkim->dkim_mode != DKIM_MODE_SIGN)
06998               return DKIM_STAT_INVALID;
06999 
07000 #define       DELIMITER     "\001"
07001 
07002        sig = dkim->dkim_signature;
07003        if (sig == NULL)
07004               sig = dkim->dkim_siglist[0];
07005 
07006        if ((sig->sig_flags & DKIM_SIGFLAG_KEYLOADED) == 0)
07007        {
07008               dkim_error(dkim, "private key load failure");
07009               return DKIM_STAT_INVALID;
07010        }
07011 
07012        tmpbuf = dkim_dstring_new(dkim, BUFRSZ, MAXBUFRSZ);
07013        if (tmpbuf == NULL)
07014        {
07015               dkim_error(dkim, "failed to allocate dynamic string");
07016               return DKIM_STAT_NORESOURCE;
07017        }
07018 
07019        if (dkim->dkim_hdrbuf == NULL)
07020        {
07021               dkim->dkim_hdrbuf = dkim_dstring_new(dkim, BUFRSZ, MAXBUFRSZ);
07022               if (dkim->dkim_hdrbuf == NULL)
07023               {
07024                      dkim_dstring_free(tmpbuf);
07025                      dkim_error(dkim, "failed to allocate dynamic string");
07026                      return DKIM_STAT_NORESOURCE;
07027               }
07028        }
07029        else
07030        {
07031               dkim_dstring_blank(dkim->dkim_hdrbuf);
07032        }
07033 
07034        /* compute and extract the signature header */
07035        len = dkim_gensighdr(dkim, sig, tmpbuf, DELIMITER);
07036        if (len == 0)
07037               return DKIM_STAT_INVALID;
07038 
07039        if (dkim->dkim_b64sig != NULL)
07040               dkim_dstring_cat(tmpbuf, dkim->dkim_b64sig);
07041 
07042        if (dkim->dkim_margin == 0)
07043        {
07044               _Bool first = TRUE;
07045 
07046               for (pv = strtok_r((char *) dkim_dstring_get(tmpbuf),
07047                                  DELIMITER, &ctx);
07048                    pv != NULL;
07049                    pv = strtok_r(NULL, DELIMITER, &ctx))
07050               {
07051                      if (!first)
07052                             dkim_dstring_cat1(dkim->dkim_hdrbuf, ' ');
07053 
07054                      dkim_dstring_cat(dkim->dkim_hdrbuf, (u_char *) pv);
07055 
07056                      first = FALSE;
07057               }
07058        }
07059        else
07060        {
07061               _Bool first = TRUE;
07062               _Bool forcewrap;
07063               int pvlen;
07064               int whichlen;
07065               char *p;
07066               char *q;
07067               char *end;
07068               char which[MAXTAGNAME + 1];
07069 
07070               len = initial;
07071               end = which + MAXTAGNAME;
07072 
07073               for (pv = strtok_r((char *) dkim_dstring_get(tmpbuf),
07074                                  DELIMITER, &ctx);
07075                    pv != NULL;
07076                    pv = strtok_r(NULL, DELIMITER, &ctx))
07077               {
07078                      for (p = pv, q = which; *p != '=' && q <= end; p++, q++)
07079                      {
07080                             *q = *p;
07081                             *(q + 1) = '\0';
07082                      }
07083 
07084                      whichlen = strlen(which);
07085 
07086                      /* force wrapping of "b=" ? */
07087 
07088                      forcewrap = FALSE;
07089                      if (sig->sig_keytype == DKIM_KEYTYPE_RSA)
07090                      {
07091                             u_int siglen;
07092 
07093                             siglen = BASE64SIZE(sig->sig_keybits / 8);
07094                             if (strcmp(which, "b") == 0 &&
07095                                 len + whichlen + siglen + 1 >= dkim->dkim_margin)
07096                                    forcewrap = TRUE;
07097                      }
07098 
07099                      pvlen = strlen(pv);
07100 
07101                      if (len == 0 || first)
07102                      {
07103                             dkim_dstring_catn(dkim->dkim_hdrbuf,
07104                                               (u_char *) pv,
07105                                               pvlen);
07106                             len += pvlen;
07107                             first = FALSE;
07108                      }
07109                      else if (forcewrap || len + pvlen > dkim->dkim_margin)
07110                      {
07111                             forcewrap = FALSE;
07112                             dkim_dstring_catn(dkim->dkim_hdrbuf,
07113                                               (u_char *) "\r\n\t", 3);
07114                             len = 8;
07115 
07116                             if (strcmp(which, "h") == 0)
07117                             {                    /* break at colons */
07118                                    _Bool ifirst = TRUE;
07119                                    int tmplen;
07120                                    char *tmp;
07121                                    char *ctx2;
07122 
07123                                    for (tmp = strtok_r(pv, ":", &ctx2);
07124                                         tmp != NULL;
07125                                         tmp = strtok_r(NULL, ":", &ctx2))
07126                                    {
07127                                           tmplen = strlen(tmp);
07128 
07129                                           if (ifirst)
07130                                           {
07131                                                  dkim_dstring_catn(dkim->dkim_hdrbuf,
07132                                                                    (u_char *) tmp,
07133                                                                    tmplen);
07134                                                  len += tmplen;
07135                                                  ifirst = FALSE;
07136                                           }
07137                                           else if (len + tmplen + 1 > dkim->dkim_margin)
07138                                           {
07139                                                  dkim_dstring_cat1(dkim->dkim_hdrbuf,
07140                                                                    ':');
07141                                                  len += 1;
07142                                                  dkim_dstring_catn(dkim->dkim_hdrbuf,
07143                                                                    (u_char *) "\r\n\t ",
07144                                                                    4);
07145                                                  len = 9;
07146                                                  dkim_dstring_catn(dkim->dkim_hdrbuf,
07147                                                                    (u_char *) tmp,
07148                                                                    tmplen);
07149                                                  len += tmplen;
07150                                           }
07151                                           else
07152                                           {
07153                                                  dkim_dstring_cat1(dkim->dkim_hdrbuf,
07154                                                                    ':');
07155                                                  len += 1;
07156                                                  dkim_dstring_catn(dkim->dkim_hdrbuf,
07157                                                                    (u_char *) tmp,
07158                                                                    tmplen);
07159                                                  len += tmplen;
07160                                           }
07161                                    }
07162 
07163                             }
07164                             else if (strcmp(which, "b") == 0 ||
07165                                      strcmp(which, "bh") == 0 ||
07166                                      strcmp(which, "z") == 0)
07167                             {                    /* break at margins */
07168                                    int offset;
07169                                    int n;
07170                                    char *x;
07171                                    char *y;
07172 
07173                                    offset = whichlen + 1;
07174 
07175                                    dkim_dstring_catn(dkim->dkim_hdrbuf,
07176                                                      (u_char *) which,
07177                                                      whichlen);
07178                                    dkim_dstring_cat1(dkim->dkim_hdrbuf,
07179                                                      '=');
07180 
07181                                    len += offset;
07182 
07183                                    dkim_dstring_cat1(dkim->dkim_hdrbuf,
07184                                                      *(pv + offset));
07185                                    len++;
07186 
07187                                    x = pv + offset + 1;
07188                                    y = pv + pvlen;
07189 
07190                                    while (x < y)
07191                                    {
07192                                           if (dkim->dkim_margin - len == 0)
07193                                           {
07194                                                  dkim_dstring_catn(dkim->dkim_hdrbuf,
07195                                                                    (u_char *) "\r\n\t ",
07196                                                                    4);
07197                                                  len = 9;
07198                                           }
07199 
07200                                           n = MIN(dkim->dkim_margin - len,
07201                                                   y - x);
07202                                           dkim_dstring_catn(dkim->dkim_hdrbuf,
07203                                                             (u_char *) x,
07204                                                             n);
07205                                           x += n;
07206                                           len += n;
07207                                           
07208                                    }
07209                             }
07210                             else
07211                             {                    /* break at delimiter */
07212                                    dkim_dstring_catn(dkim->dkim_hdrbuf,
07213                                                      (u_char *) pv,
07214                                                      pvlen);
07215                                    len += pvlen;
07216                             }
07217                      }
07218                      else
07219                      {
07220                             if (!first)
07221                             {
07222                                    dkim_dstring_cat1(dkim->dkim_hdrbuf,
07223                                                      ' ');
07224                                    len += 1;
07225                             }
07226 
07227                             first = FALSE;
07228                             dkim_dstring_catn(dkim->dkim_hdrbuf,
07229                                               (u_char *) pv,
07230                                               pvlen);
07231                             len += pvlen;
07232                      }
07233               }
07234        }
07235 
07236        *buf = dkim_dstring_get(dkim->dkim_hdrbuf);
07237        *buflen = dkim_dstring_len(dkim->dkim_hdrbuf);
07238 
07239        dkim_dstring_free(tmpbuf);
07240 
07241        return DKIM_STAT_OK;
07242 }
07243 
07244 /*
07245 **  DKIM_GETSIGHDR -- retrieve signature header into a user-provided buffer
07246 **
07247 **  Parameters:
07248 **     dkim -- libopendkim handle
07249 **     buf -- buffer into which to write
07250 **     buflen -- bytes available at "buf"
07251 **     initial -- width aleady consumed for the first line
07252 **
07253 **  Return value:
07254 **     A DKIM_STAT_* constant.
07255 */
07256 
07257 DKIM_STAT
07258 dkim_getsighdr(DKIM *dkim, u_char *buf, size_t buflen, size_t initial)
07259 {
07260        u_char *p;
07261        size_t len;
07262        DKIM_STAT status;
07263 
07264        assert(dkim != NULL);
07265        assert(buf != NULL);
07266        assert(buflen > 0);
07267 
07268        status = dkim_getsighdr_d(dkim, initial, &p, &len);
07269        if (status != DKIM_STAT_OK)
07270               return status;
07271 
07272        if (len > buflen)
07273        {
07274               dkim_error(dkim, "generated signature header too large");
07275               return DKIM_STAT_NORESOURCE;
07276        }
07277 
07278        strlcpy((char *) buf, (char *) p, buflen);
07279 
07280        return DKIM_STAT_OK;
07281 }
07282 
07283 /*
07284 **  DKIM_SIG_HDRSIGNED -- retrieve the header list from a signature
07285 **
07286 **  Parameters:
07287 **     sig -- DKIM_SIGINFO handle
07288 **     hdr -- header name to find
07289 **
07290 **  Return value:
07291 **     TRUE iff "sig" had a header list in it and the header "hdr"
07292 **     appeared in that list.
07293 */
07294 
07295 _Bool
07296 dkim_sig_hdrsigned(DKIM_SIGINFO *sig, u_char *hdr)
07297 {
07298        size_t len;
07299        u_char *c1 = NULL;
07300        u_char *c2 = NULL;
07301        u_char *start;
07302        u_char *p;
07303        u_char *hdrlist;
07304 
07305        assert(sig != NULL);
07306        assert(hdr != NULL);
07307 
07308        hdrlist = dkim_param_get(sig->sig_taglist, (u_char *) "h");
07309        if (hdrlist == NULL)
07310               return FALSE;
07311 
07312        for (p = hdrlist; ; p++)
07313        {
07314               len = -1;
07315 
07316               if (*p == ':')
07317               {
07318                      c1 = c2;
07319                      c2 = p;
07320 
07321                      if (c1 == NULL)
07322                      {
07323                             start = hdrlist;
07324                             len = c2 - start; 
07325                      }
07326                      else
07327                      {
07328                             start = c1 + 1;
07329                             len = c2 - c1 - 1;
07330                      }
07331               }
07332               else if (*p == '\0')
07333               {
07334                      if (c2 != NULL)
07335                      {
07336                             start = c2 + 1;
07337                             len = p - c2 - 1;
07338 
07339                             if (strncasecmp((char *) hdr, (char *) start,
07340                                             len) == 0)
07341                                    return TRUE;
07342                      }
07343                      else
07344                      {
07345                             if (strcasecmp((char *) hdr,
07346                                            (char *) hdrlist) == 0)
07347                                    return TRUE;
07348                      }
07349 
07350                      break;
07351               }
07352 
07353               if (len != -1)
07354               {
07355                      if (strncasecmp((char *) hdr, (char *) start,
07356                                      len) == 0)
07357                             return TRUE;
07358               }
07359        }
07360 
07361        return FALSE;
07362 }
07363 
07364 /*
07365 **  DKIM_SIG_GETDNSSEC -- retrieve DNSSEC results for a signature
07366 **
07367 **  Parameters:
07368 **     sig -- DKIM_SIGINFO handle
07369 **
07370 **  Return value:
07371 **     A DKIM_DNSSEC_* constant.
07372 */
07373 
07374 int
07375 dkim_sig_getdnssec(DKIM_SIGINFO *sig)
07376 {
07377        assert(sig != NULL);
07378 
07379        return sig->sig_dnssec_key;
07380 }
07381 
07382 /*
07383 **  DKIM_SIG_GETREPORTINFO -- retrieve reporting information for a signature
07384 **
07385 **  Parameters:
07386 **     dkim -- DKIM handle
07387 **     sig -- DKIM_SIGINFO handle
07388 **     hfd -- descriptor to canonicalized header (or NULL) (returned)
07389 **     bfd -- descriptor to canonicalized body (or NULL) (returned)
07390 **     addr -- address buffer (or NULL)
07391 **     addrlen -- size of addr
07392 **     opts -- options buffer (or NULL)
07393 **     optslen -- size of opts
07394 **     smtp -- SMTP reply text buffer (or NULL)
07395 **     smtplen -- size of smtp
07396 **     pct -- requested reporting percentage (or NULL)
07397 **
07398 **  Return value:
07399 **     A DKIM_STAT_* constant.
07400 */
07401 
07402 DKIM_STAT
07403 dkim_sig_getreportinfo(DKIM *dkim, DKIM_SIGINFO *sig,
07404                        int *hfd, int *bfd,
07405                        u_char *addr, size_t addrlen,
07406                        u_char *opts, size_t optslen,
07407                        u_char *smtp, size_t smtplen,
07408                        u_int *pct)
07409 {
07410        DKIM_STAT status;
07411        u_char *p;
07412        char *sdomain;
07413        DKIM_SET *set;
07414        struct timeval timeout;
07415        unsigned char buf[BUFRSZ];
07416 
07417        assert(dkim != NULL);
07418        assert(sig != NULL);
07419 
07420        if (dkim->dkim_state != DKIM_STATE_EOM2 ||
07421            dkim->dkim_mode != DKIM_MODE_VERIFY)
07422               return DKIM_STAT_INVALID;
07423 
07424        sdomain = dkim_sig_getdomain(sig);
07425 
07426        /* see if the signature had an "r=y" tag */
07427        set = sig->sig_taglist;
07428        if (set == NULL)
07429               return DKIM_STAT_INTERNAL;
07430 
07431        p = dkim_param_get(set, (u_char *) "r");
07432        if (p == NULL || p[0] != 'y' || p[1] != '\0')
07433        {
07434               if (addr != NULL)
07435                      addr[0] = '\0';
07436               if (opts != NULL)
07437                      opts[0] = '\0';
07438               if (smtp != NULL)
07439                      smtp[0] = '\0';
07440               if (pct != NULL)
07441                      *pct = (u_int) -1;
07442 
07443               return DKIM_STAT_OK;
07444        }
07445 
07446        /* see if we've grabbed this set already */
07447        for (set = dkim_set_first(dkim, DKIM_SETTYPE_SIGREPORT);
07448             set != NULL;
07449             set = dkim_set_next(set, DKIM_SETTYPE_SIGREPORT))
07450        {
07451               if (set->set_name != NULL &&
07452                   strcasecmp(set->set_name, sdomain) == 0)
07453                      break;
07454        }
07455 
07456        /* guess not; go to the DNS to get reporting parameters */
07457        if (set == NULL)
07458        {
07459               timeout.tv_sec = dkim->dkim_timeout;
07460               timeout.tv_usec = 0;
07461 
07462               memset(buf, '\0', sizeof buf);
07463               status = dkim_repinfo(dkim, sig, &timeout, buf, sizeof buf);
07464               if (status != DKIM_STAT_OK)
07465                      return status;
07466               if (buf[0] == '\0')
07467                      return DKIM_STAT_OK;
07468 
07469               status = dkim_process_set(dkim, DKIM_SETTYPE_SIGREPORT,
07470                                         buf, strlen(buf), NULL, FALSE,
07471                                         sdomain);
07472               if (status != DKIM_STAT_OK)
07473                      return status;
07474 
07475               for (set = dkim_set_first(dkim, DKIM_SETTYPE_SIGREPORT);
07476                    set != NULL;
07477                    set = dkim_set_next(set, DKIM_SETTYPE_SIGREPORT))
07478               {
07479                      if (set->set_name != NULL &&
07480                          strcasecmp(set->set_name, sdomain) == 0)
07481                             break;
07482               }
07483 
07484               assert(set != NULL);
07485        }
07486 
07487        if (addr != NULL)
07488        {
07489               p = dkim_param_get(set, (u_char *) "ra");
07490               if (p != NULL)
07491               {
07492                      memset(addr, '\0', addrlen);
07493                      (void) dkim_qp_decode(p, addr, addrlen - 1);
07494                      p = (u_char *) strchr((char *) addr, '@');
07495                      if (p != NULL)
07496                             *p = '\0';
07497               }
07498        }
07499 
07500        if (opts != NULL)
07501        {
07502               p = dkim_param_get(set, (u_char *) "ro");
07503               if (p != NULL)
07504                      strlcpy((char *) opts, (char *) p, optslen);
07505        }
07506 
07507        if (smtp != NULL)
07508        {
07509               p = dkim_param_get(set, (u_char *) "rs");
07510               if (p != NULL)
07511               {
07512                      memset(smtp, '\0', smtplen);
07513                      (void) dkim_qp_decode(p, smtp, smtplen - 1);
07514               }
07515        }
07516 
07517        if (pct != NULL)
07518        {
07519               p = dkim_param_get(set, (u_char *) "rp");
07520               if (p != NULL)
07521               {
07522                      u_int out;
07523                      char *q;
07524 
07525                      out = strtoul((char *) p, &q, 10);
07526                      if (*q == '\0')
07527                             *pct = out;
07528               }
07529        }
07530 
07531        if (sig->sig_hdrcanon != NULL)
07532        {
07533               switch (sig->sig_hashtype)
07534               {
07535 #ifdef USE_GNUTLS
07536                 case DKIM_HASHTYPE_SHA1:
07537                 case DKIM_HASHTYPE_SHA256:
07538                 {
07539                      struct dkim_sha *sha;
07540 
07541                      sha = (struct dkim_sha *) sig->sig_hdrcanon->canon_hash;
07542                      if (hfd != NULL)
07543                             *hfd = sha->sha_tmpfd;
07544 
07545                      if (bfd != NULL)
07546                      {
07547                             sha = (struct dkim_sha *) sig->sig_bodycanon->canon_hash;
07548                             *bfd = sha->sha_tmpfd;
07549                      }
07550 
07551                      break;
07552                 }
07553 #else /* USE_GNUTLS */
07554                 case DKIM_HASHTYPE_SHA1:
07555                 {
07556                      struct dkim_sha1 *sha1;
07557 
07558                      sha1 = (struct dkim_sha1 *) sig->sig_hdrcanon->canon_hash;
07559                      if (hfd != NULL)
07560                             *hfd = sha1->sha1_tmpfd;
07561 
07562                      if (bfd != NULL)
07563                      {
07564                             sha1 = (struct dkim_sha1 *) sig->sig_bodycanon->canon_hash;
07565                             *bfd = sha1->sha1_tmpfd;
07566                      }
07567 
07568                      break;
07569                 }
07570 
07571 # ifdef HAVE_SHA256
07572                 case DKIM_HASHTYPE_SHA256:
07573                 {
07574                      struct dkim_sha256 *sha256;
07575 
07576                      sha256 = (struct dkim_sha256 *) sig->sig_hdrcanon->canon_hash;
07577                      if (hfd != NULL)
07578                             *hfd = sha256->sha256_tmpfd;
07579 
07580                      if (bfd != NULL)
07581                      {
07582                             sha256 = (struct dkim_sha256 *) sig->sig_bodycanon->canon_hash;
07583                             *bfd = sha256->sha256_tmpfd;
07584                      }
07585 
07586                      break;
07587                 }
07588 # endif /* HAVE_SHA256 */
07589 #endif /* USE_GNUTLS */
07590 
07591                 default:
07592                      assert(0);
07593               }
07594        }
07595 
07596        return DKIM_STAT_OK;
07597 }
07598 
07599 /*
07600 **  DKIM_SIG_GETIDENTITY -- retrieve identity of the signer
07601 **
07602 **  Parameters:
07603 **     dkim -- DKIM handle
07604 **     sig -- DKIM_SIGINFO handle (or NULL to choose final one)
07605 **     val -- destination buffer
07606 **     vallen -- size of destination buffer
07607 **
07608 **  Return value:
07609 **     A DKIM_STAT_* constant.
07610 */
07611 
07612 DKIM_STAT
07613 dkim_sig_getidentity(DKIM *dkim, DKIM_SIGINFO *sig, u_char *val, size_t vallen)
07614 {
07615        int len;
07616        char *param;
07617        struct dkim_set *set;
07618 
07619        assert(val != NULL);
07620        assert(vallen != 0);
07621 
07622        if (sig == NULL)
07623        {
07624               if (dkim == NULL)
07625                      return DKIM_STAT_INVALID;
07626 
07627               sig = dkim->dkim_signature;
07628               if (sig == NULL)
07629                      return DKIM_STAT_INVALID;
07630        }
07631 
07632        set = sig->sig_taglist;
07633 
07634        param = (char *) dkim_param_get(set, (u_char *) "i");
07635        if (param == NULL)
07636        {
07637               param = (char *) dkim_param_get(set, (u_char *) "d");
07638               if (param == NULL)
07639                      return DKIM_STAT_INTERNAL;
07640 
07641               len = snprintf((char *) val, vallen, "@%s", param);
07642 
07643               return (len < vallen ? DKIM_STAT_OK : DKIM_STAT_NORESOURCE);
07644        }
07645        else
07646        {
07647               len = dkim_qp_decode((u_char *) param, (u_char *) val,
07648                                    vallen - 1);
07649 
07650               if (len == -1)
07651               {
07652                      return DKIM_STAT_SYNTAX;
07653               }
07654               else if (len >= vallen)
07655               {
07656                      return DKIM_STAT_NORESOURCE;
07657               }
07658               else
07659               {
07660                      val[len] = '\0';
07661                      return DKIM_STAT_OK;
07662               }
07663        }
07664 }
07665 
07666 /*
07667 **  DKIM_SIG_GETCANONLEN -- return canonicalized and total body lengths
07668 **
07669 **  Parameters:
07670 **     dkim -- DKIM handle
07671 **     sig -- DKIM_SIGINFO handle
07672 **     msglen -- total body length (returned)
07673 **     canonlen -- total canonicalized length (returned)
07674 **     signlen -- maximum signed length (returned)
07675 **
07676 **  Return value:
07677 **     A DKIM_STAT_* constant.
07678 */
07679 
07680 DKIM_STAT
07681 dkim_sig_getcanonlen(DKIM *dkim, DKIM_SIGINFO *sig, ssize_t *msglen,
07682                      ssize_t *canonlen, ssize_t *signlen)
07683 {
07684        assert(dkim != NULL);
07685        assert(sig != NULL);
07686 
07687        if (msglen != NULL)
07688               *msglen = dkim->dkim_bodylen;
07689 
07690        if (canonlen != NULL)
07691        {
07692               if (sig->sig_bodycanon == NULL)
07693                      return DKIM_STAT_INTERNAL;
07694               *canonlen = sig->sig_bodycanon->canon_wrote;
07695        }
07696 
07697        if (signlen != NULL)
07698        {
07699               if (sig->sig_bodycanon == NULL)
07700                      return DKIM_STAT_INTERNAL;
07701               *signlen = sig->sig_bodycanon->canon_length;
07702        }
07703 
07704        return DKIM_STAT_OK;
07705 }
07706 
07707 /*
07708 **  DKIM_SIG_GETFLAGS -- retreive signature handle flags
07709 **
07710 **  Parameters:
07711 **     sig -- DKIM_SIGINFO handle
07712 **
07713 **  Return value:
07714 **     An unsigned integer which is a bitwise-OR of the DKIM_SIGFLAG_*
07715 **     constants currently set in the provided handle.
07716 */
07717 
07718 unsigned int
07719 dkim_sig_getflags(DKIM_SIGINFO *sig)
07720 {
07721        assert(sig != NULL);
07722 
07723        return sig->sig_flags;
07724 }
07725 
07726 /*
07727 **  DKIM_SIG_GETBH -- retreive signature handle "bh" test state
07728 **
07729 **  Parameters:
07730 **     sig -- DKIM_SIGINFO handle
07731 **
07732 **  Return value:
07733 **     An integer that is one of the DKIM_SIGBH_* constants
07734 **     indicating the current state of "bh" evaluation of the signature.
07735 */
07736 
07737 int
07738 dkim_sig_getbh(DKIM_SIGINFO *sig)
07739 {
07740        assert(sig != NULL);
07741 
07742        return sig->sig_bh;
07743 }
07744 
07745 /*
07746 **  DKIM_SIG_GETKEYSIZE -- retrieve key size (in bits) when verifying
07747 **
07748 **  Parameters:
07749 **     sig -- DKIM_SIGINFO handle
07750 **     bits -- number of bits in the key (returned)
07751 **
07752 **  Return value:
07753 **     A DKIM_STAT_* constant.
07754 */
07755 
07756 DKIM_STAT
07757 dkim_sig_getkeysize(DKIM_SIGINFO *sig, unsigned int *bits)
07758 {
07759        assert(sig != NULL);
07760        assert(bits != NULL);
07761 
07762        if (sig->sig_keybits == 0)
07763               return DKIM_STAT_INVALID;
07764 
07765        *bits = sig->sig_keybits;
07766 
07767        return DKIM_STAT_OK;
07768 }
07769 
07770 /*
07771 **  DKIM_SIG_GETSIGNALG -- retrieve signature algorithm when verifying
07772 **
07773 **  Parameters:
07774 **     sig -- DKIM_SIGINFO handle
07775 **     alg -- signature algorithm used (returned)
07776 **
07777 **  Return value:
07778 **     A DKIM_STAT_* constant.
07779 */
07780 
07781 DKIM_STAT
07782 dkim_sig_getsignalg(DKIM_SIGINFO *sig, dkim_alg_t *alg)
07783 {
07784        assert(sig != NULL);
07785        assert(alg != NULL);
07786 
07787        *alg = sig->sig_signalg;
07788 
07789        return DKIM_STAT_OK;
07790 }
07791 
07792 /*
07793 **  DKIM_SIG_GETSIGNTIME -- retrieve signature timestamp
07794 **
07795 **  Parameters:
07796 **     sig -- DKIM_SIGINFO handle
07797 **     when -- signature timestamp (returned)
07798 **
07799 **  Return value:
07800 **     A DKIM_STAT_* constant.
07801 */
07802 
07803 DKIM_STAT
07804 dkim_sig_getsigntime(DKIM_SIGINFO *sig, uint64_t *when)
07805 {
07806        assert(sig != NULL);
07807        assert(when != NULL);
07808 
07809        if (sig->sig_timestamp == 0)
07810               return DKIM_STAT_INVALID;
07811 
07812        *when = sig->sig_timestamp;
07813 
07814        return DKIM_STAT_OK;
07815 }
07816 
07817 /*
07818 **  DKIM_SIG_GETCANONS -- retrieve canonicalizations used when signing
07819 **
07820 **  Parameters:
07821 **     sig -- DKIM_SIGINFO handle from which to retrieve canonicalizations
07822 **     hdr -- Pointer to a dkim_canon_t where the header canonicalization
07823 **             should be stored
07824 **     body -- Pointer to a dkim_canon_t where the body canonicalization
07825 **              should be stored
07826 **
07827 **  Return value:
07828 **     A DKIM_STAT_* constant.
07829 */
07830 
07831 DKIM_STAT
07832 dkim_sig_getcanons(DKIM_SIGINFO *sig, dkim_canon_t *hdr, dkim_canon_t *body)
07833 {
07834        assert(sig != NULL);
07835 
07836        if (hdr != NULL)
07837               *hdr = sig->sig_hdrcanonalg;
07838        if (body != NULL)
07839               *body = sig->sig_bodycanonalg;
07840 
07841        return DKIM_STAT_OK;
07842 }
07843 
07844 /*
07845 **  DKIM_GET_SIGNER -- get DKIM signature's signer
07846 **
07847 **  Parameters:
07848 **     dkim -- DKIM signing handle
07849 **
07850 **  Parameters:
07851 **     Pointer to a buffer containing the signer previously requested,
07852 **     or NULL if none.
07853 */
07854 
07855 const unsigned char *
07856 dkim_get_signer(DKIM *dkim)
07857 {
07858        assert(dkim != NULL);
07859 
07860        return dkim->dkim_signer;
07861 }
07862 
07863 /*
07864 **  DKIM_SET_SIGNER -- set DKIM signature's signer
07865 **
07866 **  Parameters:
07867 **     dkim -- DKIM signing handle
07868 **     signer -- signer to store
07869 **
07870 **  Parameters:
07871 **     A DKIM_STAT_* constant.
07872 */
07873 
07874 DKIM_STAT
07875 dkim_set_signer(DKIM *dkim, const unsigned char *signer)
07876 {
07877        assert(dkim != NULL);
07878        assert(signer != NULL);
07879 
07880        if (dkim->dkim_mode != DKIM_MODE_SIGN)
07881               return DKIM_STAT_INVALID;
07882 
07883        if (dkim->dkim_signer == NULL)
07884        {
07885               dkim->dkim_signer = DKIM_MALLOC(dkim, MAXADDRESS + 1);
07886               if (dkim->dkim_signer == NULL)
07887               {
07888                      dkim_error(dkim, "unable to allocate %d byte(s)",
07889                                 MAXADDRESS + 1);
07890                      return DKIM_STAT_NORESOURCE;
07891               }
07892        }
07893 
07894        strlcpy((char *) dkim->dkim_signer, (char *) signer, MAXADDRESS + 1);
07895 
07896        return DKIM_STAT_OK;
07897 }
07898 
07899 /*
07900 **  DKIM_GETERROR -- return any stored error string from within the DKIM
07901 **                   context handle
07902 **
07903 **  Parameters:
07904 **     dkim -- DKIM handle from which to retrieve an error string
07905 **
07906 **  Return value:
07907 **     A pointer to the stored string, or NULL if none was stored.
07908 */
07909 
07910 const char *
07911 dkim_geterror(DKIM *dkim)
07912 {
07913        assert(dkim != NULL);
07914 
07915        return (const char *) dkim->dkim_error;
07916 }
07917 
07918 /*
07919 **  DKIM_GETPARTIAL -- return if the DKIM handle is to be signed using
07920 **                     the bodylength tag (l=)
07921 **
07922 **  Parameters:
07923 **      dkim -- DKIM handle
07924 **
07925 **  Return value:
07926 **      True iff the signature is to include a body length tag
07927 */
07928 
07929 _Bool
07930 dkim_getpartial(DKIM *dkim)
07931 {
07932        assert(dkim != NULL);
07933 
07934        return dkim->dkim_partial;
07935 }
07936 
07937 /*
07938 **  DKIM_SETPARTIAL -- set the DKIM handle to sign using the DKIM body length
07939 **                     tag (l=)
07940 **
07941 **  Parameters:
07942 **      dkim -- DKIM handle
07943 **      value -- new Boolean value
07944 **
07945 **  Return value:
07946 **      DKIM_STAT_INVALID -- "dkim" referenced a verification handle
07947 **      DKIM_STAT_OK -- otherwise
07948 */
07949 
07950 DKIM_STAT
07951 dkim_setpartial(DKIM *dkim, _Bool value)
07952 {
07953        assert(dkim != NULL);
07954 
07955        if (dkim->dkim_mode != DKIM_MODE_SIGN)
07956               return DKIM_STAT_INVALID;
07957 
07958        dkim->dkim_partial = value;
07959 
07960        return DKIM_STAT_OK;
07961 }
07962 
07963 /*
07964 **  DKIM_SET_MARGIN -- set the margin to use when generating signatures
07965 **
07966 **  Parameters:
07967 **      dkim -- DKIM handle
07968 **      value -- new margin value
07969 **
07970 **  Return value:
07971 **      DKIM_STAT_INVALID -- "dkim" referenced a verification handle,
07972 **                          "value" was negative, or this is being called
07973 **                          after dkim_eom() completed
07974 **      DKIM_STAT_OK -- otherwise
07975 */
07976 
07977 DKIM_STAT
07978 dkim_set_margin(DKIM *dkim, int value)
07979 {
07980        assert(dkim != NULL);
07981 
07982        if (dkim->dkim_mode != DKIM_MODE_SIGN || value < 0 ||
07983            dkim->dkim_state >= DKIM_STATE_EOM2)
07984               return DKIM_STAT_INVALID;
07985 
07986        dkim->dkim_margin = (size_t) value;
07987 
07988        return DKIM_STAT_OK;
07989 }
07990 
07991 /*
07992 **  DKIM_GETRESULTSTR -- translate a DKIM_STAT_* constant to a string
07993 **
07994 **  Parameters:
07995 **     result -- DKIM_STAT_* constant to translate
07996 **
07997 **  Return value:
07998 **     Pointer to a text describing "result", or NULL if none exists
07999 */
08000 
08001 const char *
08002 dkim_getresultstr(DKIM_STAT result)
08003 {
08004        return dkim_code_to_name(results, result);
08005 }
08006 
08007 /*
08008 **  DKIM_GETPRESULT -- retrieve policy result
08009 **
08010 **  Parameters:
08011 **     dkim -- DKIM handle from which to get policy result
08012 **
08013 **  Return value:
08014 **     DKIM policy check result.
08015 */
08016 
08017 int
08018 dkim_getpresult(DKIM *dkim)
08019 {
08020        assert(dkim != NULL);
08021 
08022        return dkim->dkim_presult;
08023 }
08024 
08025 /*
08026 **  DKIM_GETPRESULTSTR -- retrieve policy result string
08027 **
08028 **  Parameters:
08029 **     presult -- policy result code to translate
08030 **
08031 **  Return value:
08032 **     Pointer to text that describes "presult".
08033 */
08034 
08035 const char *
08036 dkim_getpresultstr(int presult)
08037 {
08038        return dkim_code_to_name(policyresults, presult);
08039 }
08040 
08041 /*
08042 **  DKIM_GETPOLICYSTR -- retrieve policy string
08043 **
08044 **  Parameters:
08045 **     policy -- policy code to translate
08046 **
08047 **  Return value:
08048 **     Pointer to text that describes "policy".
08049 */
08050 
08051 const char *
08052 dkim_getpolicystr(int policy)
08053 {
08054        return dkim_code_to_name(policies, policy);
08055 }
08056 
08057 /*
08058 **  DKIM_SET_DNS_CALLBACK -- set the DNS wait callback
08059 **
08060 **  Parameters:
08061 **     libopendkim -- DKIM library handle
08062 **     func -- function to call; should take an opaque context pointer
08063 **     interval -- how often to call back
08064 **
08065 **  Return value:
08066 **     DKIM_STAT_OK -- success
08067 **     DKIM_STAT_INVALID -- invalid use
08068 **     DKIM_STAT_NOTIMPLEMENT -- underlying resolver doesn't support callbacks
08069 */
08070 
08071 DKIM_STAT
08072 dkim_set_dns_callback(DKIM_LIB *libopendkim, void (*func)(const void *context),
08073                       unsigned int interval)
08074 {
08075        assert(libopendkim != NULL);
08076 
08077        if (func != NULL && interval == 0)
08078               return DKIM_STAT_INVALID;
08079 
08080        libopendkim->dkiml_dns_callback = func;
08081        libopendkim->dkiml_callback_int = interval;
08082 
08083        return DKIM_STAT_OK;
08084 }
08085 
08086 /*
08087 **  DKIM_SET_USER_CONTEXT -- set user context pointer
08088 **
08089 **  Parameters:
08090 **     dkim -- DKIM handle
08091 **     ctx -- opaque context pointer
08092 **
08093 **  Return value:
08094 **     DKIM_STAT_OK
08095 */
08096 
08097 DKIM_STAT
08098 dkim_set_user_context(DKIM *dkim, void *ctx)
08099 {
08100        assert(dkim != NULL);
08101 
08102        dkim->dkim_user_context = (const void *) ctx;
08103 
08104        return DKIM_STAT_OK;
08105 }
08106 
08107 /*
08108 **  DKIM_GET_USER_CONTEXT -- get user context pointer
08109 **
08110 **  Parameters:
08111 **     dkim -- DKIM handle
08112 **
08113 **  Return value:
08114 **     User context associated with a DKIM handle
08115 */
08116 
08117 void *
08118 dkim_get_user_context(DKIM *dkim)
08119 {
08120        assert(dkim != NULL);
08121 
08122        return (void *) dkim->dkim_user_context;
08123 }
08124 
08125 /*
08126 **  DKIM_GETMODE -- return the mode (signing, verifying, etc.) of a handle
08127 **
08128 **  Parameters:
08129 **     dkim -- DKIM handle
08130 **
08131 **  Return value:
08132 **     A DKIM_MODE_* constant.
08133 */
08134 
08135 int
08136 dkim_getmode(DKIM *dkim)
08137 {
08138        assert(dkim != NULL);
08139 
08140        return dkim->dkim_mode;
08141 }
08142 
08143 /*
08144 **  DKIM_GETDOMAIN -- retrieve policy domain from a DKIM context
08145 **
08146 **  Parameters:
08147 **     dkim -- DKIM handle
08148 **
08149 **  Return value:
08150 **     Pointer to the domain used for policy checking or NULL if no domain
08151 **     could be determined.
08152 */
08153 
08154 u_char *
08155 dkim_getdomain(DKIM *dkim)
08156 {
08157        assert(dkim != NULL);
08158 
08159        return dkim->dkim_domain;
08160 }
08161 
08162 /*
08163 **  DKIM_GETUSER -- retrieve sending user (local-part) from a DKIM context
08164 **
08165 **  Parameters:
08166 **     dkim -- DKIM handle
08167 **
08168 **  Return value:
08169 **     Pointer to the apparent sending user (local-part) or NULL if not known.
08170 */
08171 
08172 u_char *
08173 dkim_getuser(DKIM *dkim)
08174 {
08175        assert(dkim != NULL);
08176 
08177        return dkim->dkim_user;
08178 }
08179 
08180 /*
08181 **  DKIM_SET_KEY_LOOKUP -- set the key lookup function
08182 **
08183 **  Parameters:
08184 **     libopendkim -- DKIM library handle
08185 **     func -- function to call
08186 **
08187 **  Return value:
08188 **     DKIM_STAT_OK
08189 */
08190 
08191 DKIM_STAT
08192 dkim_set_key_lookup(DKIM_LIB *libopendkim,
08193                     DKIM_STAT (*func)(DKIM *dkim, DKIM_SIGINFO *sig,
08194                                       u_char *buf, size_t buflen))
08195 {
08196        assert(libopendkim != NULL);
08197 
08198        libopendkim->dkiml_key_lookup = func;
08199 
08200        return DKIM_STAT_OK;
08201 }
08202 
08203 /*
08204 **  DKIM_SET_POLICY_LOOKUP -- set the policy lookup function
08205 **
08206 **  Parameters:
08207 **     libopendkim -- DKIM library handle
08208 **     func -- function to call
08209 **
08210 **  Return value:
08211 **     DKIM_STAT_OK
08212 */
08213 
08214 DKIM_STAT
08215 dkim_set_policy_lookup(DKIM_LIB *libopendkim,
08216                        int (*func)(DKIM *dkim, u_char *query, _Bool excheck,
08217                                    u_char *buf, size_t buflen, int *qstat))
08218 {
08219        assert(libopendkim != NULL);
08220 
08221        libopendkim->dkiml_policy_lookup = func;
08222 
08223        return DKIM_STAT_OK;
08224 }
08225 
08226 /*
08227 **  DKIM_SET_SIGNATURE_HANDLE -- set the user handle allocation function
08228 **
08229 **  Parameters:
08230 **     libopendkim -- DKIM library handle
08231 **     func -- function to call
08232 **
08233 **  Return value:
08234 **     DKIM_STAT_OK -- success
08235 */
08236 
08237 DKIM_STAT
08238 dkim_set_signature_handle(DKIM_LIB *libopendkim, void * (*func)(void *closure))
08239 {
08240        assert(libopendkim != NULL);
08241 
08242        libopendkim->dkiml_sig_handle = func;
08243 
08244        return DKIM_STAT_OK;
08245 }
08246 
08247 /*
08248 **  DKIM_SET_SIGNATURE_HANDLE_FREE -- set the user handle deallocation function
08249 **
08250 **  Parameters:
08251 **     libopendkim -- DKIM library handle
08252 **     func -- function to call
08253 **
08254 **  Return value:
08255 **     DKIM_STAT_OK
08256 */
08257 
08258 DKIM_STAT
08259 dkim_set_signature_handle_free(DKIM_LIB *libopendkim,
08260                                void (*func)(void *closure, void *user))
08261 {
08262        assert(libopendkim != NULL);
08263 
08264        libopendkim->dkiml_sig_handle_free = func;
08265 
08266        return DKIM_STAT_OK;
08267 }
08268 
08269 /*
08270 **  DKIM_SET_SIGNATURE_TAGVALUES -- set the user handle population function
08271 **
08272 **  Parameters:
08273 **     libopendkim -- DKIM library handle
08274 **     func -- function to call
08275 **
08276 **  Return value:
08277 **     DKIM_STAT_OK
08278 */
08279 
08280 DKIM_STAT
08281 dkim_set_signature_tagvalues(DKIM_LIB *libopendkim, void (*func)(void *user,
08282                                                                  dkim_param_t pcode,
08283                                                                  const u_char *param,
08284                                                                  const u_char *value))
08285 {
08286        assert(libopendkim != NULL);
08287 
08288        libopendkim->dkiml_sig_tagvalues = func;
08289 
08290        return DKIM_STAT_OK;
08291 }
08292 
08293 /*
08294 **  DKIM_SET_PRESCREEN -- set the user prescreen function
08295 **
08296 **  Parameters:
08297 **     libopendkim -- DKIM library handle
08298 **     func -- function to call
08299 **
08300 **  Return value:
08301 **     DKIM_STAT_OK
08302 */
08303 
08304 DKIM_STAT
08305 dkim_set_prescreen(DKIM_LIB *libopendkim, DKIM_CBSTAT (*func)(DKIM *dkim,
08306                                                               DKIM_SIGINFO **sigs,
08307                                                               int nsigs))
08308 {
08309        assert(libopendkim != NULL);
08310 
08311        libopendkim->dkiml_prescreen = func;
08312 
08313        return DKIM_STAT_OK;
08314 }
08315 
08316 /*
08317 **  DKIM_SET_FINAL -- set the user final scan function
08318 **
08319 **  Parameters:
08320 **     libopendkim -- DKIM library handle
08321 **     func -- function to call
08322 **
08323 **  Return value:
08324 **     DKIM_STAT_OK
08325 */
08326 
08327 DKIM_STAT
08328 dkim_set_final(DKIM_LIB *libopendkim, DKIM_CBSTAT (*func)(DKIM *dkim,
08329                                                           DKIM_SIGINFO **sigs,
08330                                                           int nsigs))
08331 {
08332        assert(libopendkim != NULL);
08333 
08334        libopendkim->dkiml_final = func;
08335 
08336        return DKIM_STAT_OK;
08337 }
08338 
08339 /*
08340 **  DKIM_SIG_GETCONTEXT -- retrieve user-provided context from a DKIM_SIGINFO
08341 **
08342 **  Parameters:
08343 **     siginfo -- pointer to a DKIM_SIGINFO from which to extract context
08344 **
08345 **  Return value:
08346 **     Pointer to the user context provided by an earlier call to the
08347 **     handle allocator (see above), or NULL if none was ever set.
08348 */
08349 
08350 void *
08351 dkim_sig_getcontext(DKIM_SIGINFO *siginfo)
08352 {
08353        assert(siginfo != NULL);
08354 
08355        return siginfo->sig_context;
08356 }
08357 
08358 /*
08359 **  DKIM_SIG_GETSELECTOR -- retrieve selector from a DKIM_SIGINFO
08360 **
08361 **  Parameters:
08362 **     siginfo -- pointer to a DKIM_SIGINFO from which to extract the selector
08363 **
08364 **  Return value:
08365 **     Pointer to the selector associated with the DKIM_SIGINFO.
08366 */
08367 
08368 unsigned char *
08369 dkim_sig_getselector(DKIM_SIGINFO *siginfo)
08370 {
08371        assert(siginfo != NULL);
08372 
08373        return siginfo->sig_selector;
08374 }
08375 
08376 /*
08377 **  DKIM_SIG_GETDOMAIN -- retrieve domain from a DKIM_SIGINFO
08378 **
08379 **  Parameters:
08380 **     siginfo -- pointer to a DKIM_SIGINFO from which to extract the domain
08381 **
08382 **  Return value:
08383 **     Pointer to the domain associated with the DKIM_SIGINFO.
08384 */
08385 
08386 unsigned char *
08387 dkim_sig_getdomain(DKIM_SIGINFO *siginfo)
08388 {
08389        assert(siginfo != NULL);
08390 
08391        return siginfo->sig_domain;
08392 }
08393 
08394 /*
08395 **  DKIM_SIG_GETERROR -- retrieve an error code from a DKIM_SIGINFO
08396 **
08397 **  Parameters:
08398 **     siginfo -- pointer to a DKIM_SIGINFO from which to extract context
08399 **
08400 **  Return value:
08401 **     A DKIM_SIGERROR_* constant.
08402 */
08403 
08404 int
08405 dkim_sig_geterror(DKIM_SIGINFO *siginfo)
08406 {
08407        assert(siginfo != NULL);
08408 
08409        return siginfo->sig_error;
08410 }
08411 
08412 /*
08413 **  DKIM_SIG_GETERRORSTR -- translate a DKIM_SIGERROR_* constant to a string
08414 **
08415 **  Parameters:
08416 **     sigerr -- DKIM_SIGERROR_* constant to translate
08417 **
08418 **  Return value:
08419 **     A pointer to a human-readable expression of "sigerr", or NULL if none
08420 **     exists.
08421 */
08422 
08423 const char *
08424 dkim_sig_geterrorstr(DKIM_SIGERROR sigerr)
08425 {
08426        return dkim_code_to_name(sigerrors, sigerr);
08427 }
08428 
08429 /*
08430 **  DKIM_SIG_IGNORE -- mark a signature referenced by a DKIM_SIGINFO with
08431 **                     an "ignore" flag
08432 **
08433 **  Parameters:
08434 **     siginfo -- pointer to a DKIM_SIGINFO to update
08435 **
08436 **  Return value:
08437 **     None.
08438 */
08439 
08440 void
08441 dkim_sig_ignore(DKIM_SIGINFO *siginfo)
08442 {
08443        assert(siginfo != NULL);
08444 
08445        siginfo->sig_flags |= DKIM_SIGFLAG_IGNORE;
08446 }
08447 
08448 /*
08449 **  DKIM_SSL_VERSION -- return version of OpenSSL that was used to build
08450 **                      the library
08451 **
08452 **  Parameters:
08453 **     None.
08454 **
08455 **  Return value:
08456 **     The constant OPENSSL_VERSION_NUMBER as defined by OpenSSL.
08457 */
08458 
08459 unsigned long
08460 dkim_ssl_version(void)
08461 {
08462 #ifdef USE_GNUTLS
08463        return (GNUTLS_VERSION_NUMBER << 8);
08464 #else /* USE_GNUTLS */
08465        return OPENSSL_VERSION_NUMBER;
08466 #endif /* USE_GNUTLS */
08467 }
08468 
08469 /*
08470 **  DKIM_FLUSH_CACHE -- purge expired records from the cache
08471 **
08472 **  Parameters:
08473 **     lib -- DKIM library handle, returned by dkim_init()
08474 **
08475 **  Return value:
08476 **     -1 -- caching is not in effect
08477 **     >= 0 -- number of purged records
08478 */
08479 
08480 int
08481 dkim_flush_cache(DKIM_LIB *lib)
08482 {
08483 #ifdef QUERY_CACHE
08484        int err;
08485 #endif /* QUERY_CACHE */
08486 
08487        assert(lib != NULL);
08488 
08489 #ifdef QUERY_CACHE
08490        if (lib->dkiml_cache == NULL)
08491               return -1;
08492 
08493        return dkim_cache_expire(lib->dkiml_cache, 0, &err);
08494 #else /* QUERY_CACHE */
08495        return -1;
08496 #endif /* QUERY_CACHE */
08497 }
08498 
08499 /*
08500 **  DKIM_GETCACHESTATS -- retrieve cache statistics
08501 **
08502 **  Parameters:
08503 **     queries -- number of queries handled (returned)
08504 **     hits -- number of cache hits (returned)
08505 **     expired -- number of expired hits (returned)
08506 **
08507 **  Return value:
08508 **     DKIM_STAT_OK -- request completed
08509 **     DKIM_STAT_NOTIMPLEMENT -- function not implemented
08510 **
08511 **  Notes:
08512 **     Any of the parameters may be NULL if the corresponding datum
08513 **     is not of interest.
08514 */
08515 
08516 DKIM_STAT
08517 dkim_getcachestats(u_int *queries, u_int *hits, u_int *expired)
08518 {
08519 #ifdef QUERY_CACHE
08520        dkim_cache_stats(queries, hits, expired);
08521        return DKIM_STAT_OK;
08522 #else /* QUERY_CACHE */
08523        return DKIM_STAT_NOTIMPLEMENT;
08524 #endif /* QUERY_CACHE */
08525 }
08526 
08527 /*
08528 **  DKIM_GET_REPUTATION -- query reputation service about a signature
08529 **                         (OBSOLETE; moved to libdkimrep)
08530 **  
08531 **  Parameters:
08532 **     dkim -- DKIM handle
08533 **     sig -- DKIM_SIGINFO handle
08534 **     qroot -- query root
08535 **     rep -- integer reputation (returned)
08536 **
08537 **  Return value:
08538 **     DKIM_STAT_NOTIMPLEMENT -- not implemented
08539 */
08540 
08541 DKIM_STAT
08542 dkim_get_reputation(DKIM *dkim, DKIM_SIGINFO *sig, char *qroot, int *rep)
08543 {
08544        return DKIM_STAT_NOTIMPLEMENT;
08545 }
08546 
08547 /*
08548 **  DKIM_GET_SIGSUBSTRING -- retrieve a minimal signature substring for
08549 **                           disambiguation
08550 **
08551 **  Parameters:
08552 **     dkim -- DKIM handle
08553 **     sig -- DKIM_SIGINFO handle
08554 **     buf -- buffer into which to put the substring
08555 **     buflen -- bytes available at "buf"
08556 **
08557 **  Return value:
08558 **     A DKIM_STAT_* constant.
08559 */
08560 
08561 DKIM_STAT
08562 dkim_get_sigsubstring(DKIM *dkim, DKIM_SIGINFO *sig, char *buf, size_t *buflen)
08563 {
08564        int c;
08565        int d;
08566        int x;
08567        int b1len;
08568        int b2len;
08569        int minlen;
08570        char *b1;
08571        char *b2;
08572 
08573        assert(dkim != NULL);
08574        assert(sig != NULL);
08575        assert(buf != NULL);
08576        assert(buflen != NULL);
08577 
08578        if (dkim->dkim_minsiglen == 0)
08579        {
08580               dkim->dkim_minsiglen = MINSIGLEN;
08581 
08582               for (c = 0; c < dkim->dkim_sigcount - 1; c++)
08583               {
08584                      b1 = (char *) dkim_param_get(dkim->dkim_siglist[c]->sig_taglist,
08585                                                   (u_char *) "b");
08586                      if (b1 == NULL)
08587                             continue;
08588 
08589                      b1len = strlen(b1);
08590 
08591                      for (d = c + 1; d < dkim->dkim_sigcount; d++)
08592                      {
08593                             b2 = (char *) dkim_param_get(dkim->dkim_siglist[d]->sig_taglist,
08594                                                          (u_char *) "b");
08595                             if (b2 == NULL)
08596                                    continue;
08597 
08598                             if (strncmp(b1, b2, dkim->dkim_minsiglen) != 0)
08599                                    continue;
08600 
08601                             b2len = strlen(b2);
08602 
08603                             minlen = MIN(strlen(b1), strlen(b2));
08604 
08605                             for (x = dkim->dkim_minsiglen; x < minlen; x++)
08606                             {
08607                                    if (b1[x] != b2[x])
08608                                           break;
08609                             }
08610 
08611                             dkim->dkim_minsiglen = x + 1;
08612                      }
08613               }
08614        }
08615 
08616        b1 = (char *) dkim_param_get(sig->sig_taglist, (u_char *) "b");
08617        if (b1 == NULL)
08618               return DKIM_STAT_SYNTAX;
08619 
08620        minlen = MIN(*buflen, dkim->dkim_minsiglen);
08621        strncpy(buf, b1, minlen);
08622        if (minlen < *buflen)
08623               buf[minlen] = '\0';
08624        *buflen = minlen;
08625 
08626        return DKIM_STAT_OK;
08627 }
08628 
08629 /*
08630 **  DKIM_LIBFEATURE -- determine whether or not a particular library feature
08631 **                     is actually available
08632 **
08633 **  Parameters:
08634 **     lib -- library handle
08635 **     fc -- feature code to check
08636 **
08637 **  Return value:
08638 **     TRUE iff the specified feature was compiled in
08639 */
08640 
08641 _Bool
08642 dkim_libfeature(DKIM_LIB *lib, u_int fc)
08643 {
08644        u_int idx;
08645        u_int offset;
08646 
08647        idx = fc / (8 * sizeof(int));
08648        offset = fc % (8 * sizeof(int));
08649 
08650        if (idx > lib->dkiml_flsize)
08651               return FALSE;
08652        return ((lib->dkiml_flist[idx] & (1 << offset)) != 0);
08653 }
08654 
08655 /*
08656 **  DKIM_LIBVERSION -- return version of libopendkim at runtime
08657 **
08658 **  Parameters:
08659 **     None.
08660 **
08661 **  Return value:
08662 **     Library version, i.e. value of the OPENDKIM_LIB_VERSION macro.
08663 */
08664 
08665 uint32_t
08666 dkim_libversion(void)
08667 {
08668        return OPENDKIM_LIB_VERSION;
08669 }
08670 
08671 /*
08672 **  DKIM_SIG_GETTAGVALUE -- retrieve a tag's value from a signature or its key
08673 **
08674 **  Parameters:
08675 **     sig -- DKIM_SIGINFO handle
08676 **     keytag -- TRUE iff we want a key's tag
08677 **     tag -- name of the tag of interest
08678 **
08679 **  Return value:
08680 **     Pointer to the string containing the value of the requested key,
08681 **     or NULL if not present.
08682 **
08683 **  Notes:
08684 **     This was added for use in determining whether or not a key or
08685 **     signature contained particular data, for gathering general statistics
08686 **     about DKIM use.  It is not intended to give applications direct access
08687 **     to unprocessed signature or key data.  The data returned has not
08688 **     necessarily been vetted in any way.  Caveat emptor.
08689 */
08690 
08691 u_char *
08692 dkim_sig_gettagvalue(DKIM_SIGINFO *sig, _Bool keytag, u_char *tag)
08693 {
08694        DKIM_SET *set;
08695 
08696        assert(sig != NULL);
08697        assert(tag != NULL);
08698 
08699        if (keytag)
08700               set = sig->sig_keytaglist;
08701        else
08702               set = sig->sig_taglist;
08703 
08704        if (set == NULL)
08705               return NULL;
08706        else
08707               return dkim_param_get(set, tag);
08708 }
08709 
08710 /*
08711 **  DKIM_SIG_GETSIGNEDHDRS -- retrieve the signed header fields covered by
08712 **                            a signature that passed
08713 **
08714 **  Parameters:
08715 **     dkim -- DKIM instance
08716 **     sig -- signature
08717 **     hdrs -- rectangular array of header field strings
08718 **     hdrlen -- length of each element of "hdrs"
08719 **     nhdrs -- size of "hdrs" array (updated)
08720 **
08721 **  Return value:
08722 **     A DKIM_STAT_* constant.
08723 */
08724 
08725 DKIM_STAT
08726 dkim_sig_getsignedhdrs(DKIM *dkim, DKIM_SIGINFO *sig,
08727                        u_char *hdrs, size_t hdrlen, u_int *nhdrs)
08728 {
08729        int status;
08730        u_int n;
08731        u_char *h;
08732        u_char *p;
08733        struct dkim_header **sighdrs;
08734 
08735        assert(dkim != NULL);
08736        assert(sig != NULL);
08737        assert(nhdrs != NULL);
08738 
08739        if ((sig->sig_flags & DKIM_SIGFLAG_PASSED) == 0 ||
08740            sig->sig_bh != DKIM_SIGBH_MATCH)
08741               return DKIM_STAT_INVALID;
08742 
08743        h = dkim_param_get(sig->sig_taglist, "h");
08744        assert(h != NULL);
08745 
08746        n = 1;
08747        for (p = h; *p != '\0'; p++)
08748        {
08749               if (*p == ':')
08750                      n++;
08751        }
08752 
08753        if (*nhdrs < n)
08754        {
08755               *nhdrs = n;
08756               return DKIM_STAT_NORESOURCE;
08757        }
08758 
08759        assert(hdrs != NULL);
08760 
08761        sighdrs = (struct dkim_header **) DKIM_MALLOC(dkim,
08762                                                      sizeof(struct dkim_header *) * n);
08763        if (sighdrs == NULL)
08764        {
08765               *nhdrs = 0;
08766               return DKIM_STAT_NORESOURCE;
08767        }
08768 
08769        status = dkim_canon_selecthdrs(dkim, h, sighdrs, n);
08770        if (status == -1)
08771        {
08772               DKIM_FREE(dkim, sighdrs);
08773               return DKIM_STAT_INTERNAL;
08774        }
08775 
08776        *nhdrs = status;
08777 
08778        for (n = 0; n < status; n++)
08779               strlcpy(&hdrs[n * hdrlen], sighdrs[n]->hdr_text, hdrlen);
08780 
08781        DKIM_FREE(dkim, sighdrs);
08782 
08783        return DKIM_STAT_OK;
08784 }
08785 
08786 /*
08787 **  DKIM_DNS_SET_QUERY_SERVICE -- stores a handle representing the DNS
08788 **                                query service to be used, returning any
08789 **                                previous handle
08790 **
08791 **  Parameters:
08792 **     lib -- DKIM library handle
08793 **     h -- handle to be used
08794 **
08795 **  Return value:
08796 **     Previously stored handle, or NULL if none.
08797 */
08798 
08799 void *
08800 dkim_dns_set_query_service(DKIM_LIB *lib, void *h)
08801 {
08802        void *old;
08803 
08804        old = lib->dkiml_dns_service;
08805 
08806        lib->dkiml_dns_service = h;
08807 
08808        return old;
08809 }
08810 
08811 /*
08812 **  DKIM_DNS_SET_QUERY_START -- stores a pointer to a query start function
08813 **
08814 **  Parameters:
08815 **     lib -- DKIM library handle
08816 **     func -- function to use to start queries
08817 **
08818 **  Return value:
08819 **     None.
08820 **
08821 **  Notes:
08822 **     "func" should match the following prototype:
08823 **            returns int (status)
08824 **            void *dns -- receives handle stored by
08825 **                         dkim_dns_set_query_service()
08826 **            int type -- DNS RR query type (C_IN assumed)
08827 **            char *query -- question to ask
08828 **            char *buf -- buffer into which to write reply
08829 **            size_t buflen -- size of buf
08830 **            void **qh -- returned query handle
08831 */
08832 
08833 void
08834 dkim_dns_set_query_start(DKIM_LIB *lib, int (*func)(void *, int,
08835                                                     unsigned char *,
08836                                                     unsigned char *,
08837                                                     size_t, void **))
08838 {
08839        assert(lib != NULL);
08840 
08841        if (func != NULL)
08842               lib->dkiml_dns_start = func;
08843        else
08844               lib->dkiml_dns_start = dkim_res_query;
08845 }
08846 
08847 /*
08848 **  DKIM_DNS_SET_QUERY_CANCEL -- stores a pointer to a query cancel function
08849 **
08850 **  Parameters:
08851 **     lib -- DKIM library handle
08852 **     func -- function to use to cancel running queries
08853 **
08854 **  Return value:
08855 **     None.
08856 **
08857 **  Notes:
08858 **     "func" should match the following prototype:
08859 **            returns int (status)
08860 **            void *dns -- DNS service handle
08861 **            void *qh -- query handle to be canceled
08862 */
08863 
08864 void
08865 dkim_dns_set_query_cancel(DKIM_LIB *lib, int (*func)(void *, void *))
08866 {
08867        assert(lib != NULL);
08868 
08869        if (func != NULL)
08870               lib->dkiml_dns_cancel = func;
08871        else
08872               lib->dkiml_dns_cancel = dkim_res_cancel;
08873 }
08874 
08875 /*
08876 **  DKIM_DNS_SET_QUERY_WAITREPLY -- stores a pointer to wait for a DNS reply
08877 **
08878 **  Parameters:
08879 **     lib -- DKIM library handle
08880 **     func -- function to use to wait for a reply
08881 **
08882 **  Return value:
08883 **     None.
08884 **
08885 **  Notes:
08886 **     "func" should match the following prototype:
08887 **            returns int (status)
08888 **            void *dns -- DNS service handle
08889 **            void *qh -- handle of query that has completed
08890 **            struct timeval *timeout -- how long to wait
08891 **            size_t *bytes -- bytes returned
08892 **            int *error -- error code returned
08893 **            int *dnssec -- DNSSEC status returned
08894 */
08895 
08896 void
08897 dkim_dns_set_query_waitreply(DKIM_LIB *lib, int (*func)(void *, void *,
08898                                                         struct timeval *,
08899                                                         size_t *, int *,
08900                                                         int *))
08901 {
08902        assert(lib != NULL);
08903 
08904        if (func != NULL)
08905               lib->dkiml_dns_waitreply = func;
08906        else
08907               lib->dkiml_dns_waitreply = dkim_res_waitreply;
08908 }
08909 
08910 /*
08911 **  DKIM_ADD_XTAG -- add an extension tag/value
08912 **
08913 **  Parameters:
08914 **     dkim -- DKIM signing handle to extend
08915 **     tag -- name of tag to add
08916 **     value -- value to include
08917 **
08918 **  Return value:
08919 **     A DKIM_STAT_* constant.
08920 **
08921 **  Notes:
08922 **     A value that contains spaces won't be wrapped nicely by the signature
08923 **     generation code.  Support for this should be added later.
08924 */
08925 
08926 DKIM_STAT
08927 dkim_add_xtag(DKIM *dkim, const char *tag, const char *value)
08928 {
08929        u_char last = '\0';
08930        dkim_param_t pcode;
08931        u_char *p;
08932        struct dkim_xtag *x;
08933 
08934        assert(dkim != NULL);
08935        assert(tag != NULL);
08936        assert(value != NULL);
08937 
08938        if (dkim->dkim_mode != DKIM_MODE_SIGN)
08939               return DKIM_STAT_INVALID;
08940 
08941        /* check that it's not in sigparams */
08942        if (tag[0] == '\0' || value[0] == '\0')
08943               return DKIM_STAT_INVALID;
08944        pcode = dkim_name_to_code(sigparams, tag);
08945        if (pcode != (dkim_param_t) -1)
08946               return DKIM_STAT_INVALID;
08947 
08948        /* confirm valid syntax, per RFC6376 */
08949        for (p = (u_char *) tag; *p != '\0'; p++)
08950        {
08951               if (!(isascii(*p) && (isalnum(*p) || *p == '_')))
08952                      return DKIM_STAT_INVALID;
08953        }
08954 
08955        if (value[0] == '\n' ||
08956            value[0] == '\r' ||
08957            value[0] == '\t' ||
08958            value[0] == ' ')
08959               return DKIM_STAT_INVALID;
08960 
08961        for (p = (u_char *) value; *p != '\0'; p++)
08962        {
08963               /* valid characters in general */
08964               if (!(*p == '\n' ||
08965                     *p == '\r' ||
08966                     *p == '\t' ||
08967                     *p == ' ' ||
08968                     (*p >= 0x21 && *p <= 0x7e && *p != 0x3b)))
08969                      return DKIM_STAT_INVALID;
08970 
08971               /* CR has to be followed by LF */
08972               if (last == '\r' && *p != '\n')
08973                      return DKIM_STAT_INVALID;
08974 
08975               /* LF has to be followed by space or tab */
08976               if (last == '\n' && *p != ' ' && *p != '\t')
08977                      return DKIM_STAT_INVALID;
08978 
08979               last = *p;
08980        }
08981 
08982        /* can't end with space */
08983        if (last == '\n' || last == '\r' ||
08984            last == '\t' || last == ' ')
08985               return DKIM_STAT_INVALID;
08986 
08987        /* check for dupicates */
08988        for (x = dkim->dkim_xtags; x != NULL; x = x->xt_next)
08989        {
08990               if (strcmp(x->xt_tag, tag) == 0)
08991                      return DKIM_STAT_INVALID;
08992        }
08993 
08994        x = (struct dkim_xtag *) DKIM_MALLOC(dkim, sizeof(struct dkim_xtag));
08995        if (x == NULL)
08996        {
08997               dkim_error(dkim, "unable to allocate %d byte(s)",
08998                          sizeof(struct dkim_xtag));
08999               return DKIM_STAT_NORESOURCE;
09000        }
09001 
09002        x->xt_tag = tag;
09003        x->xt_value = value;
09004        x->xt_next = dkim->dkim_xtags;
09005        dkim->dkim_xtags = x;
09006 
09007        return DKIM_STAT_OK;
09008 }
09009 
09010 /*
09011 **  DKIM_QI_GETNAME -- retrieve the DNS name from a DKIM_QUERYINFO object
09012 **
09013 **  Parameters:
09014 **     query -- DKIM_QUERYINFO handle
09015 **
09016 **  Return value:
09017 **     A pointer to a NULL-terminated string indicating the name to be
09018 **     queried, or NULL on error.
09019 */
09020 
09021 const char *
09022 dkim_qi_getname(DKIM_QUERYINFO *query)
09023 {
09024        assert(query != NULL);
09025 
09026        return query->dq_name;
09027 }
09028 
09029 /*
09030 **  DKIM_QI_GETTYPE -- retrieve the DNS RR type from a DKIM_QUERYINFO object
09031 **
09032 **  Parameters:
09033 **     query -- DKIM_QUERYINFO handle
09034 **
09035 **  Return value:
09036 **     The DNS RR type to be queried, or -1 on error.
09037 */
09038 
09039 int
09040 dkim_qi_gettype(DKIM_QUERYINFO *query)
09041 {
09042        assert(query != NULL);
09043 
09044        return query->dq_type;
09045 }
09046 
09047 /*
09048 **  DKIM_SIG_GETQUERIES -- retrieve the queries needed to validate a signature
09049 **
09050 **  Parameters:
09051 **     dkim -- DKIM handle
09052 **     sig -- DKIM_SIGINFO handle
09053 **     qi -- DKIM_QUERYINFO handle array (returned)
09054 **     nqi -- number of entries in the "qi" array
09055 **
09056 **  Return value:
09057 **     A DKIM_STAT_* constant.
09058 */
09059 
09060 DKIM_STAT
09061 dkim_sig_getqueries(DKIM *dkim, DKIM_SIGINFO *sig,
09062                     DKIM_QUERYINFO ***qi, unsigned int *nqi)
09063 {
09064        DKIM_QUERYINFO **new;
09065        DKIM_QUERYINFO *newp;
09066 
09067        assert(dkim != NULL);
09068        assert(sig != NULL);
09069        assert(qi != NULL);
09070        assert(nqi != NULL);
09071 
09072        new = DKIM_MALLOC(dkim, sizeof(struct dkim_queryinfo *));
09073        if (new == NULL)
09074               return DKIM_STAT_NORESOURCE;
09075 
09076        newp = DKIM_MALLOC(dkim, sizeof(struct dkim_queryinfo));
09077        if (newp == NULL)
09078        {
09079               DKIM_FREE(dkim, new);
09080               return DKIM_STAT_NORESOURCE;
09081        }
09082 
09083        memset(newp, '\0', sizeof(struct dkim_queryinfo));
09084 
09085        if (sig->sig_selector != NULL && sig->sig_domain != NULL)
09086        {
09087               newp->dq_type = T_TXT;
09088               snprintf((char *) newp->dq_name, sizeof newp->dq_name,
09089                        "%s.%s.%s",
09090                        sig->sig_selector, DKIM_DNSKEYNAME, sig->sig_domain);
09091        }
09092 
09093        new[0] = newp;
09094 
09095        *qi = new;
09096        *nqi = 1;
09097 
09098        return DKIM_STAT_OK;
09099 }
09100 
09101 /*
09102 **  DKIM_POLICY_GETQUERIES -- retrieve the queries needed to conduct ADSP
09103 **                            checks
09104 **
09105 **  Parameters:
09106 **     dkim -- DKIM handle
09107 **     qi -- DKIM_QUERYINFO handle array (returned)
09108 **     nqi -- number of entries in the "qi" array
09109 **
09110 **  Return value:
09111 **     A DKIM_STAT_* constant.
09112 */
09113 
09114 DKIM_STAT
09115 dkim_policy_getqueries(DKIM *dkim,
09116                        DKIM_QUERYINFO ***qi, unsigned int *nqi)
09117 {
09118        int c;
09119        DKIM_QUERYINFO **new;
09120 
09121        assert(dkim != NULL);
09122        assert(qi != NULL);
09123        assert(nqi != NULL);
09124 
09125        new = DKIM_MALLOC(dkim, 4 * sizeof(struct dkim_queryinfo *));
09126        if (new == NULL)
09127               return DKIM_STAT_NORESOURCE;
09128 
09129        memset(new, '\0', 4 * sizeof(struct dkim_queryinfo *));
09130 
09131        for (c = 0; c < 4; c++)
09132        {
09133               new[c] = DKIM_MALLOC(dkim, sizeof(struct dkim_queryinfo));
09134               if (new[c] == NULL)
09135               {
09136                      int d;
09137 
09138                      for (d = 0; d < c; d++)
09139                             free(new[d]);
09140 
09141                      free(new);
09142 
09143                      return DKIM_STAT_NORESOURCE;
09144               }
09145 
09146               memset(new[c], '\0', sizeof(struct dkim_queryinfo));
09147 
09148               switch (c)
09149               {
09150                 case 0:
09151                      new[c]->dq_type = T_A;
09152                      break;
09153 
09154                 case 1:
09155                      new[c]->dq_type = T_AAAA;
09156                      break;
09157 
09158                 case 2:
09159                      new[c]->dq_type = T_MX;
09160                      break;
09161 
09162                 case 3:
09163                      new[c]->dq_type = T_TXT;
09164                      break;
09165               }
09166 
09167               if (dkim->dkim_domain != NULL)
09168               {
09169                      if (c != 3)
09170                      {
09171                             strlcpy((char *) new[c]->dq_name,
09172                                     dkim->dkim_domain,
09173                                      sizeof new[c]->dq_name);
09174                      }
09175                      else
09176                      {
09177                             snprintf((char *) new[c]->dq_name,
09178                                      sizeof new[c]->dq_name,
09179                                      "%s.%s.%s",
09180                                      DKIM_DNSPOLICYNAME, DKIM_DNSKEYNAME,
09181                                      dkim->dkim_domain);
09182                      }
09183               }
09184        }
09185 
09186        *qi = new;
09187        *nqi = 4;
09188 
09189        return DKIM_STAT_OK;
09190 }
09191 
09192 /*
09193 **  DKIM_SIG_GETHASHES -- retrieve hashes
09194 **
09195 **  Parameters:
09196 **     sig -- signature from which to get completed hashes
09197 **     hh -- pointer to header hash buffer (returned)
09198 **     hhlen -- bytes used at hh (returned)
09199 **     bh -- pointer to body hash buffer (returned)
09200 **     bhlen -- bytes used at bh (returned)
09201 **
09202 **  Return value:
09203 **     DKIM_STAT_OK -- successful completion
09204 **     DKIM_STAT_INVALID -- hashing hasn't been completed
09205 */
09206 
09207 DKIM_STAT
09208 dkim_sig_gethashes(DKIM_SIGINFO *sig, void **hh, size_t *hhlen,
09209                    void **bh, size_t *bhlen)
09210 {
09211        return dkim_canon_gethashes(sig, hh, hhlen, bh, bhlen);
09212 }