Back to index

opendkim  2.6.4
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 (size_t) -1;
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        (void) dkim_canon_closebody(dkim);
02407        status = dkim_canon_getfinal(sig->sig_bodycanon, &hash, &hashlen);
02408        if (status != DKIM_STAT_OK)
02409        {
02410               dkim_error(dkim, "dkim_canon_getfinal() failed");
02411               if (always != NULL)
02412                      (void) DKIM_FREE(dkim, always);
02413               return (size_t) -1;
02414        }
02415 
02416        status = dkim_base64_encode(hash, hashlen,
02417                                    b64hash, sizeof b64hash);
02418 
02419        dkim_dstring_printf(dstr, ";%sbh=%s", delim, b64hash);
02420 
02421        /* l= */
02422        if (dkim->dkim_partial)
02423        {
02424               dkim_dstring_printf(dstr, ";%sl=%lu", delim,
02425                                   (u_long) sig->sig_bodycanon->canon_wrote);
02426        }
02427 
02428        /* h= */
02429        for (n = 0; n < dkim->dkim_libhandle->dkiml_nalwayshdrs; n++)
02430               always[n] = TRUE;
02431 
02432        firsthdr = TRUE;
02433 
02434        for (hdr = dkim->dkim_hhead; hdr != NULL; hdr = hdr->hdr_next)
02435        {
02436               if ((hdr->hdr_flags & DKIM_HDR_SIGNED) == 0)
02437                      continue;
02438 
02439               if (!firsthdr)
02440               {
02441                      dkim_dstring_cat1(dstr, ':');
02442               }
02443               else
02444               {
02445                      dkim_dstring_cat1(dstr, ';');
02446                      dkim_dstring_catn(dstr, (u_char *) delim, delimlen);
02447                      dkim_dstring_catn(dstr, (u_char *) "h=", 2);
02448               }
02449 
02450               firsthdr = FALSE;
02451 
02452               dkim_dstring_catn(dstr, hdr->hdr_text, hdr->hdr_namelen);
02453 
02454               if (dkim->dkim_libhandle->dkiml_alwayshdrs != NULL)
02455               {
02456                      u_char **ah = dkim->dkim_libhandle->dkiml_alwayshdrs;
02457 
02458                      for (n = 0; ah[n] != NULL; n++)
02459                      {
02460                             if (strncasecmp((char *) hdr->hdr_text,
02461                                             (char *) ah[n],
02462                                             hdr->hdr_namelen) == 0)
02463                             {
02464                                    always[n] = FALSE;
02465                                    break;
02466                             }
02467                      }
02468               }
02469        }
02470 
02471        /* apply any "always sign" list */
02472        if (dkim->dkim_libhandle->dkiml_alwayshdrs != NULL)
02473        {
02474               u_char **ah = dkim->dkim_libhandle->dkiml_alwayshdrs;
02475 
02476               for (n = 0; ah[n] != NULL; n++)
02477               {
02478                      if (always[n])
02479                      {
02480                             if (!firsthdr)
02481                             {
02482                                    dkim_dstring_cat1(dstr, ':');
02483                             }
02484                             else
02485                             {
02486                                    dkim_dstring_cat1(dstr, ';');
02487                                    dkim_dstring_catn(dstr,
02488                                                      (u_char *) delim,
02489                                                      delimlen);
02490                                    dkim_dstring_catn(dstr,
02491                                                      (u_char *) "h=", 2);
02492                             }
02493 
02494                             firsthdr = FALSE;
02495 
02496                             dkim_dstring_cat(dstr, ah[n]);
02497                      }
02498               }
02499        }
02500 
02501 #ifdef _FFR_OVERSIGN
02502        if (dkim->dkim_libhandle->dkiml_oversignhdrs != NULL)
02503        {
02504               if (firsthdr)
02505               {
02506                      dkim_dstring_cat1(dstr, ';');
02507                      dkim_dstring_catn(dstr, delim, delimlen);
02508                      dkim_dstring_catn(dstr, "h=", 2);
02509               }
02510               else
02511               {
02512                      dkim_dstring_cat1(dstr, ':');
02513               }
02514 
02515               for (n = 0;
02516                    dkim->dkim_libhandle->dkiml_oversignhdrs[n] != NULL;
02517                    n++)
02518               {
02519                      if (n != 0)
02520                             dkim_dstring_cat1(dstr, ':');
02521 
02522                      dkim_dstring_cat(dstr,
02523                                       dkim->dkim_libhandle->dkiml_oversignhdrs[n]);
02524               }
02525        }
02526 #endif /* _FFR_OVERSIGN */
02527 
02528        /* if diagnostic headers were requested, include 'em */
02529        if (dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_ZTAGS)
02530        {
02531               _Bool first;
02532               int status;
02533               size_t len;
02534               u_char *p;
02535               u_char *q;
02536               u_char *end;
02537               u_char *hend;
02538               u_char *colon;
02539               unsigned char name[DKIM_MAXHEADER + 1];
02540 
02541               dkim_dstring_cat1(dstr, ';');
02542               dkim_dstring_catn(dstr, (u_char *) delim, delimlen);
02543               dkim_dstring_catn(dstr, (u_char *) "z=", 2);
02544 
02545               first = TRUE;
02546               end = tmp + sizeof tmp - 1;
02547 
02548               for (hdr = dkim->dkim_hhead; hdr != NULL; hdr = hdr->hdr_next)
02549               {
02550                      /* apply "skip" header and "sign" header lists */
02551                      hend = hdr->hdr_text + hdr->hdr_textlen;
02552                      colon = memchr(hdr->hdr_text, ':', hdr->hdr_textlen);
02553                      if (colon != NULL)
02554                      {
02555                             hend = colon;
02556 
02557                             while (hend > hdr->hdr_text &&
02558                                    isascii(*(hend - 1)) &&
02559                                    isspace(*(hend - 1)))
02560                                    hend--;
02561                      }
02562 
02563                      strlcpy((char *) name, (char *) hdr->hdr_text,
02564                              sizeof name);
02565                      if (hend != NULL)
02566                             name[hend - hdr->hdr_text] = '\0';
02567 
02568                      if (dkim->dkim_libhandle->dkiml_skipre)
02569                      {
02570                             status = regexec(&dkim->dkim_libhandle->dkiml_skiphdrre,
02571                                              (char *) name, 0, NULL, 0);
02572 
02573                             if (status == 0)
02574                                    continue;
02575                             else
02576                                    assert(status == REG_NOMATCH);
02577                      }
02578 
02579                      if (dkim->dkim_libhandle->dkiml_signre)
02580                      {
02581                             status = regexec(&dkim->dkim_libhandle->dkiml_hdrre,
02582                                              (char *) name, 0, NULL, 0);
02583 
02584                             if (status == REG_NOMATCH)
02585                                    continue;
02586                             else
02587                                    assert(status == 0);
02588                      }
02589 
02590                      q = tmp;
02591                      len = 0;
02592 
02593                      if (!first)
02594                      {
02595                             *q = '|';
02596                             q++;
02597                             len++;
02598                      }
02599 
02600                      first = FALSE;
02601 
02602                      for (p = hdr->hdr_text; *p != '\0'; p++)
02603                      {
02604                             if (q >= end)
02605                                    break;
02606 
02607                             if ((*p >= 0x21 && *p <= 0x3a) ||
02608                                 *p == 0x3c ||
02609                                 (*p >= 0x3e && *p <= 0x7e))
02610                             {
02611                                    *q = *p;
02612                                    q++;
02613                                    len++;
02614                             }
02615                             else if (q < end - 4)
02616                             {
02617                                    snprintf((char *) q, 4,
02618                                             "=%02X", *p);
02619                                    q += 3;
02620                                    len += 3;
02621                             }
02622                      }
02623 
02624                      dkim_dstring_catn(dstr, tmp, len);
02625               }
02626        }
02627 
02628        /* and finally, an empty b= */
02629        dkim_dstring_cat1(dstr, ';');
02630        dkim_dstring_catn(dstr, (u_char *) delim, delimlen);
02631        dkim_dstring_catn(dstr, (u_char *) "b=", 2);
02632 
02633        if (always != NULL)
02634               DKIM_FREE(dkim, always);
02635 
02636        return dkim_dstring_len(dstr);
02637 }
02638 
02639 /*
02640 **  DKIM_GETSENDER -- determine sender and store it in the handle
02641 **
02642 **  Parameters:
02643 **     dkim -- DKIM handle
02644 **     hdrs -- list of header names to find
02645 **
02646 **  Return value:
02647 **     A DKIM_STAT_* constant.
02648 */
02649 
02650 static DKIM_STAT
02651 dkim_getsender(DKIM *dkim, u_char **hdrs)
02652 {
02653        int c;
02654        size_t hlen;
02655        DKIM_STAT status;
02656        unsigned char *domain;
02657        unsigned char *user;
02658        struct dkim_header *sender = NULL;
02659        struct dkim_header *cur;
02660 
02661        assert(dkim != NULL);
02662        assert(hdrs != NULL);
02663 
02664        if (dkim->dkim_sender != NULL)
02665               return DKIM_STAT_OK;
02666 
02667        for (c = 0; hdrs[c] != NULL; c++)
02668        {
02669               hlen = strlen((char *) hdrs[c]);
02670 
02671               for (cur = dkim->dkim_hhead; cur != NULL; cur = cur->hdr_next)
02672               {
02673                      if (hlen == cur->hdr_namelen &&
02674                          strncasecmp((char *) hdrs[c],
02675                                      (char *) cur->hdr_text,
02676                                      hlen) == 0)
02677                      {
02678                             sender = cur;
02679                             break;
02680                      }
02681               }
02682        }
02683 
02684        if (sender == NULL)
02685        {
02686               dkim_error(dkim, "no sender headers detected");
02687               return DKIM_STAT_SYNTAX;
02688        }
02689        dkim->dkim_senderhdr = sender;
02690 
02691        if (sender->hdr_colon == NULL)
02692        {
02693               dkim_error(dkim, "syntax error in headers");
02694               return DKIM_STAT_SYNTAX;
02695        }
02696 
02697        dkim->dkim_sender = dkim_strdup(dkim, sender->hdr_colon + 1, 0);
02698        if (dkim->dkim_sender == NULL)
02699               return DKIM_STAT_NORESOURCE;
02700 
02701        status = dkim_mail_parse(dkim->dkim_sender, &user, &domain);
02702        if (status != 0 || domain == NULL || user == NULL ||
02703            domain[0] == '\0' || user[0] == '\0')
02704        {
02705               dkim_error(dkim, "can't determine sender address");
02706               return DKIM_STAT_SYNTAX;
02707        }
02708 
02709        if (dkim->dkim_domain == NULL)
02710        {
02711               dkim->dkim_domain = dkim_strdup(dkim, domain, 0);
02712               if (dkim->dkim_domain == NULL)
02713                      return DKIM_STAT_NORESOURCE;
02714        }
02715 
02716        dkim->dkim_user = dkim_strdup(dkim, user, 0);
02717        if (dkim->dkim_user == NULL)
02718               return DKIM_STAT_NORESOURCE;
02719 
02720        return DKIM_STAT_OK;
02721 }
02722 
02723 /*
02724 **  DKIM_GET_POLICY -- request and parse a domain's policy record
02725 **
02726 **  Parameters:
02727 **     dkim -- DKIM handle
02728 **     query -- string to query
02729 **     excheck -- existence check rather than TXT query
02730 **     qstatus -- query status (returned)
02731 **     policy -- policy found (returned)
02732 **     pflags -- policy flags (returned) (unused)
02733 **
02734 **  Return value:
02735 **     A DKIM_STAT_* constant.
02736 */
02737 
02738 static DKIM_STAT
02739 dkim_get_policy(DKIM *dkim, u_char *query, _Bool excheck, int *qstatus,
02740                 dkim_policy_t *policy, u_int *pflags)
02741 {
02742        int status = 0;
02743        int qstat = NOERROR;
02744        unsigned int lpflags;
02745        dkim_policy_t lpolicy;
02746        DKIM_STAT pstatus;
02747        unsigned char buf[BUFRSZ + 1];
02748 
02749        assert(dkim != NULL);
02750        assert(query != NULL);
02751        assert(qstatus != NULL);
02752        assert(policy != NULL);
02753        assert(pflags != NULL);
02754 
02755        if (dkim->dkim_libhandle->dkiml_policy_lookup != NULL)
02756        {
02757               DKIM_CBSTAT cbstatus;
02758 
02759               cbstatus = dkim->dkim_libhandle->dkiml_policy_lookup(dkim,
02760                                                                    query,
02761                                                                    excheck,
02762                                                                    buf,
02763                                                                    sizeof buf,
02764                                                                    &qstat);
02765 
02766               switch (cbstatus)
02767               {
02768                 case DKIM_CBSTAT_CONTINUE:
02769                      status = 1;
02770                      break;
02771 
02772                 case DKIM_CBSTAT_REJECT:
02773                      return DKIM_STAT_CBREJECT;
02774 
02775                 case DKIM_CBSTAT_TRYAGAIN:
02776                      return DKIM_STAT_CBTRYAGAIN;
02777 
02778                 case DKIM_CBSTAT_NOTFOUND:
02779                      break;
02780 
02781                 case DKIM_CBSTAT_ERROR:
02782                      return DKIM_STAT_CBERROR;
02783 
02784                 default:
02785                      return DKIM_STAT_CBINVALID;
02786               }
02787        }
02788        else
02789        {
02790               switch (dkim->dkim_libhandle->dkiml_querymethod)
02791               {
02792                 case DKIM_QUERY_UNKNOWN:
02793                 case DKIM_QUERY_DNS:
02794                      status = dkim_get_policy_dns(dkim, query, excheck,
02795                                                   buf, sizeof buf, &qstat);
02796                      break;
02797 
02798                 case DKIM_QUERY_FILE:
02799                      status = dkim_get_policy_file(dkim, query, buf,
02800                                                    sizeof buf, &qstat);
02801                      break;
02802 
02803                 default:
02804                      assert(0);
02805                      /* just to silence -Wall */
02806                      return -1;
02807               }
02808        }
02809 
02810        if (status == -1)
02811               return DKIM_STAT_CANTVRFY;
02812        else if (status == 0)
02813               qstat = NXDOMAIN;
02814 
02815        *qstatus = qstat;
02816 
02817        if (!excheck && qstat == NOERROR && status == 1)
02818        {
02819               u_char *p;
02820               struct dkim_set *set;
02821 
02822               pstatus = dkim_process_set(dkim, DKIM_SETTYPE_POLICY,
02823                                          buf, strlen((char *) buf),
02824                                          NULL, FALSE, NULL);
02825               if ((dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_REPORTBADADSP) == 0 &&
02826                   pstatus == DKIM_STAT_SYNTAX)
02827               {
02828                      *policy = DKIM_POLICY_DEFAULT;
02829                      *qstatus = NXDOMAIN;
02830                      *pflags = 0;
02831               }
02832               else if (pstatus != DKIM_STAT_OK)
02833               {
02834                      return pstatus;
02835               }
02836 
02837               lpolicy = DKIM_POLICY_DEFAULT;
02838               lpflags = 0;
02839 
02840               set = dkim_set_first(dkim, DKIM_SETTYPE_POLICY);
02841 
02842               p = dkim_param_get(set, (u_char *) "dkim");
02843               if (p != NULL)
02844                      lpolicy = dkim_name_to_code(policies, (char *) p);
02845 
02846               *policy = lpolicy;
02847               *pflags = lpflags;
02848        }
02849 
02850        return DKIM_STAT_OK;
02851 }
02852 
02853 /*
02854 **  DKIM_GET_KEY -- acquire a public key used for verification
02855 **
02856 **  Parameters:
02857 **     dkim -- DKIM handle
02858 **     sig -- DKIM_SIGINFO handle
02859 **     test -- skip signature-specific validity checks
02860 **
02861 **  Return value:
02862 **     A DKIM_STAT_* constant.
02863 */
02864 
02865 DKIM_STAT
02866 dkim_get_key(DKIM *dkim, DKIM_SIGINFO *sig, _Bool test)
02867 {
02868        _Bool gotkey = FALSE;                     /* key stored */
02869        _Bool gotset = FALSE;                     /* set parsed */
02870        _Bool gotreply = FALSE;                   /* reply received */
02871        int status;
02872        int c;
02873        DKIM_SIGINFO *osig;
02874        struct dkim_set *set = NULL;
02875        struct dkim_set *nextset;
02876        unsigned char *p;
02877        unsigned char buf[BUFRSZ + 1];
02878 
02879        assert(dkim != NULL);
02880        assert(sig != NULL);
02881        assert(sig->sig_selector != NULL);
02882        assert(sig->sig_domain != NULL);
02883 
02884        memset(buf, '\0', sizeof buf);
02885 
02886        /* see if one of the other signatures already has the key we need */
02887        for (c = 0; c < dkim->dkim_sigcount; c++)
02888        {
02889               osig = dkim->dkim_siglist[c];
02890 
02891               /* don't self-search */
02892               if (sig == osig)
02893                      continue;
02894 
02895               /* skip unprocessed signatures */
02896               if ((osig->sig_flags & DKIM_SIGFLAG_PROCESSED) == 0)
02897                      continue;
02898 
02899               /* skip unless selector and domain match */
02900               if (strcmp((char *) osig->sig_domain,
02901                          (char *) sig->sig_domain) != 0 ||
02902                   strcmp((char *) osig->sig_selector,
02903                          (char *) sig->sig_selector) != 0)
02904                      continue;
02905 
02906               /* we got a match!  copy the key data (if any)... */
02907               if (osig->sig_key != NULL)
02908               {
02909                      sig->sig_key = DKIM_MALLOC(dkim, osig->sig_b64keylen);
02910                      if (sig->sig_key == NULL)
02911                      {
02912                             dkim_error(dkim,
02913                                        "unable to allocate %d byte(s)",
02914                                        osig->sig_b64keylen);
02915                             return DKIM_STAT_NORESOURCE;
02916                      }
02917 
02918                      memcpy(sig->sig_key, osig->sig_key,
02919                             osig->sig_b64keylen);
02920 
02921                      sig->sig_keylen = osig->sig_keylen;
02922 
02923                      gotkey = TRUE;
02924               }
02925 
02926               /* ...and the key tag list (if any) */
02927               if (osig->sig_keytaglist != NULL)
02928               {
02929                      sig->sig_keytaglist = osig->sig_keytaglist;
02930                      set = sig->sig_keytaglist;
02931 
02932                      gotset = TRUE;
02933                      gotreply = TRUE;
02934               }
02935 
02936               break;
02937        }
02938 
02939        /* try a local function if there was one defined */
02940        if (!gotkey && dkim->dkim_libhandle->dkiml_key_lookup != NULL)
02941        {
02942               DKIM_CBSTAT cbstatus;
02943 
02944               cbstatus = dkim->dkim_libhandle->dkiml_key_lookup(dkim,
02945                                                                 sig,
02946                                                                 buf,
02947                                                                 sizeof buf);
02948               switch (cbstatus)
02949               {
02950                 case DKIM_CBSTAT_CONTINUE:
02951                      gotreply = TRUE;
02952                      break;
02953 
02954                 case DKIM_CBSTAT_REJECT:
02955                      return DKIM_STAT_CBREJECT;
02956 
02957                 case DKIM_CBSTAT_TRYAGAIN:
02958                      return DKIM_STAT_CBTRYAGAIN;
02959 
02960                 case DKIM_CBSTAT_NOTFOUND:
02961                      return DKIM_STAT_NOKEY;
02962 
02963                 case DKIM_CBSTAT_ERROR:
02964                      return DKIM_STAT_CBERROR;
02965 
02966                 default:
02967                      return DKIM_STAT_CBINVALID;
02968               }
02969        }
02970 
02971        /* if no local function or it returned no result, make the query */
02972        if (!gotreply)
02973        {
02974               /* use appropriate get method */
02975               switch (sig->sig_query)
02976               {
02977                 case DKIM_QUERY_DNS:
02978                      status = (int) dkim_get_key_dns(dkim, sig, buf,
02979                                                      sizeof buf);
02980                      if (status != (int) DKIM_STAT_OK)
02981                             return (DKIM_STAT) status;
02982                      break;
02983 
02984                 case DKIM_QUERY_FILE:
02985                      status = (int) dkim_get_key_file(dkim, sig, buf,
02986                                                       sizeof buf);
02987                      if (status != (int) DKIM_STAT_OK)
02988                             return (DKIM_STAT) status;
02989                      break;
02990 
02991                 default:
02992                      assert(0);
02993               }
02994        }
02995 
02996        /* decode the payload */
02997        if (!gotset)
02998        {
02999               if (buf[0] == '\0')
03000               {
03001                      dkim_error(dkim, "empty key record");
03002                      return DKIM_STAT_SYNTAX;
03003               }
03004 
03005               status = dkim_process_set(dkim, DKIM_SETTYPE_KEY, buf,
03006                                         strlen((char *) buf), NULL, FALSE,
03007                                         NULL);
03008               if (status != DKIM_STAT_OK)
03009                      return status;
03010 
03011               /* get the last key */
03012               set = dkim_set_first(dkim, DKIM_SETTYPE_KEY);
03013               assert(set != NULL);
03014               for (;;)
03015               {
03016                      nextset = dkim_set_next(set, DKIM_SETTYPE_KEY);
03017                      if (nextset == NULL)
03018                             break;
03019                      set = nextset;
03020               }
03021               assert(set != NULL);
03022 
03023               sig->sig_keytaglist = set;
03024        }
03025 
03026        /* verify key version first */
03027        p = dkim_param_get(set, (u_char *) "v");
03028        if (p != NULL && strcmp((char *) p, DKIM_VERSION_KEY) != 0)
03029        {
03030               dkim_error(dkim, "invalid key version '%s'", p);
03031               sig->sig_error = DKIM_SIGERROR_KEYVERSION;
03032               return DKIM_STAT_SYNTAX;
03033        }
03034 
03035        /* then make sure the hash type is something we can handle */
03036        p = dkim_param_get(set, (u_char *) "h");
03037        if (!dkim_key_hashesok(dkim->dkim_libhandle, p))
03038        {
03039               dkim_error(dkim, "unknown hash '%s'", p);
03040               sig->sig_error = DKIM_SIGERROR_KEYUNKNOWNHASH;
03041               return DKIM_STAT_SYNTAX;
03042        }
03043        /* ...and that this key is approved for this signature's hash */
03044        else if (!test && !dkim_key_hashok(sig, p))
03045        {
03046               dkim_error(dkim, "signature-key hash mismatch");
03047               sig->sig_error = DKIM_SIGERROR_KEYHASHMISMATCH;
03048               return DKIM_STAT_CANTVRFY;
03049        }
03050 
03051        /* make sure it's a key designated for e-mail */
03052        if (!dkim_key_smtp(set))
03053        {
03054               dkim_error(dkim, "key type mismatch");
03055               sig->sig_error = DKIM_SIGERROR_NOTEMAILKEY;
03056               return DKIM_STAT_CANTVRFY;
03057        }
03058 
03059        /* then key type */
03060        p = dkim_param_get(set, (u_char *) "k");
03061        if (p == NULL)
03062        {
03063               dkim_error(dkim, "key type missing");
03064               sig->sig_error = DKIM_SIGERROR_KEYTYPEMISSING;
03065               return DKIM_STAT_SYNTAX;
03066        }
03067        else if (dkim_name_to_code(keytypes, (char *) p) == -1)
03068        {
03069               dkim_error(dkim, "unknown key type '%s'", p);
03070               sig->sig_error = DKIM_SIGERROR_KEYTYPEUNKNOWN;
03071               return DKIM_STAT_SYNTAX;
03072        }
03073 
03074        if (!gotkey)
03075        {
03076               /* decode the key */
03077               sig->sig_b64key = dkim_param_get(set, (u_char *) "p");
03078               if (sig->sig_b64key == NULL)
03079               {
03080                      dkim_error(dkim, "key missing");
03081                      return DKIM_STAT_SYNTAX;
03082               }
03083               else if (sig->sig_b64key[0] == '\0')
03084               {
03085                      return DKIM_STAT_REVOKED;
03086               }
03087               sig->sig_b64keylen = strlen((char *) sig->sig_b64key);
03088 
03089               sig->sig_key = DKIM_MALLOC(dkim, sig->sig_b64keylen);
03090               if (sig->sig_key == NULL)
03091               {
03092                      dkim_error(dkim, "unable to allocate %d byte(s)",
03093                                 sig->sig_b64keylen);
03094                      return DKIM_STAT_NORESOURCE;
03095               }
03096 
03097               status = dkim_base64_decode(sig->sig_b64key, sig->sig_key,
03098                                           sig->sig_b64keylen);
03099               if (status < 0)
03100               {
03101                      dkim_error(dkim, "key missing");
03102                      return DKIM_STAT_SYNTAX;
03103               }
03104 
03105               sig->sig_keylen = status;
03106        }
03107 
03108        /* store key flags */
03109        p = dkim_param_get(set, (u_char *) "t");
03110        if (p != NULL)
03111        {
03112               u_int flag;
03113               char *t;
03114               char *last;
03115               char tmp[BUFRSZ + 1];
03116 
03117               strlcpy(tmp, (char *) p, sizeof tmp);
03118 
03119               for (t = strtok_r(tmp, ":", &last);
03120                    t != NULL;
03121                    t = strtok_r(NULL, ":", &last))
03122               {
03123                      flag = (u_int) dkim_name_to_code(keyflags, t);
03124                      if (flag != (u_int) -1)
03125                             sig->sig_flags |= flag;
03126               }
03127        }
03128 
03129        return DKIM_STAT_OK;
03130 }
03131 
03132 /*
03133 **  DKIM_HEADERCHECK -- check header validity
03134 **
03135 **  Parameters:
03136 **     dkim -- DKIM handle
03137 **
03138 **  Return value:
03139 **     TRUE iff the header meets sanity checks.
03140 */
03141 
03142 static _Bool
03143 dkim_headercheck(DKIM *dkim)
03144 {
03145        struct dkim_header *hdr;
03146 
03147        assert(dkim != NULL);
03148 
03149        if ((dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_STRICTHDRS) != 0)
03150        {
03151               /* Date (must be exactly one) */
03152               hdr = dkim_get_header(dkim, "Date", 4, 0);
03153               if (hdr == NULL)
03154               {
03155                      dkim_error(dkim, "Date: header field absent");
03156                      return FALSE;
03157               }
03158 
03159               hdr = dkim_get_header(dkim, "Date", 4, 1);
03160               if (hdr != NULL)
03161               {
03162                      dkim_error(dkim,
03163                                 "multiple Date: header fields present");
03164                      return FALSE;
03165               }
03166 
03167               /* From (must be exactly one) */
03168               hdr = dkim_get_header(dkim, "From", 4, 0);
03169               if (hdr == NULL)
03170               {
03171                      dkim_error(dkim, "From: header field absent");
03172                      return FALSE;
03173               }
03174 
03175               hdr = dkim_get_header(dkim, "From", 4, 1);
03176               if (hdr != NULL)
03177               {
03178                      dkim_error(dkim,
03179                                 "multiple From: header fields present");
03180                      return FALSE;
03181               }
03182 
03183               /* Sender (no more than one) */
03184               hdr = dkim_get_header(dkim, "Sender", 6, 1);
03185               if (hdr != NULL)
03186               {
03187                      dkim_error(dkim,
03188                                 "multiple Sender: header fields present");
03189                      return FALSE;
03190               }
03191 
03192               /* Reply-To (no more than one) */
03193               hdr = dkim_get_header(dkim, "Reply-To", 8, 1);
03194               if (hdr != NULL)
03195               {
03196                      dkim_error(dkim,
03197                                 "multiple Reply-To: header fields present");
03198                      return FALSE;
03199               }
03200 
03201               /* To (no more than one) */
03202               hdr = dkim_get_header(dkim, "To", 2, 1);
03203               if (hdr != NULL)
03204               {
03205                      dkim_error(dkim,
03206                                 "multiple To: header fields present");
03207                      return FALSE;
03208               }
03209 
03210               /* Cc (no more than one) */
03211               hdr = dkim_get_header(dkim, "Cc", 2, 1);
03212               if (hdr != NULL)
03213               {
03214                      dkim_error(dkim,
03215                                 "multiple Cc: header fields present");
03216                      return FALSE;
03217               }
03218 
03219               /* Bcc (should we even bother?) */
03220               hdr = dkim_get_header(dkim, "Bcc", 3, 1);
03221               if (hdr != NULL)
03222               {
03223                      dkim_error(dkim,
03224                                 "multiple Bcc: header fields present");
03225                      return FALSE;
03226               }
03227 
03228               /* Message-ID (no more than one) */
03229               hdr = dkim_get_header(dkim, "Message-ID", 10, 1);
03230               if (hdr != NULL)
03231               {
03232                      dkim_error(dkim,
03233                                 "multiple Message-ID: header fields present");
03234                      return FALSE;
03235               }
03236 
03237               /* In-Reply-To (no more than one) */
03238               hdr = dkim_get_header(dkim, "In-Reply-To", 11, 1);
03239               if (hdr != NULL)
03240               {
03241                      dkim_error(dkim,
03242                                 "multiple In-Reply-To: header fields present");
03243                      return FALSE;
03244               }
03245 
03246               /* References (no more than one) */
03247               hdr = dkim_get_header(dkim, "References", 10, 1);
03248               if (hdr != NULL)
03249               {
03250                      dkim_error(dkim,
03251                                 "multiple References: header fields present");
03252                      return FALSE;
03253               }
03254 
03255               /* Subject (no more than one) */
03256               hdr = dkim_get_header(dkim, "Subject", 7, 1);
03257               if (hdr != NULL)
03258               {
03259                      dkim_error(dkim,
03260                                 "multiple Subject: header fields present");
03261                      return FALSE;
03262               }
03263        }
03264 
03265        return TRUE;
03266 }
03267 
03268 /*
03269 **  DKIM_EOH_SIGN -- declare end-of-headers; prepare for signing
03270 ** 
03271 **  Parameters:
03272 **     dkim -- DKIM handle
03273 **
03274 **  Return value:
03275 **     A DKIM_STAT_* constant.
03276 */
03277 
03278 static DKIM_STAT
03279 dkim_eoh_sign(DKIM *dkim)
03280 {
03281        _Bool keep;
03282        _Bool tmp;
03283        u_char *hn = NULL;
03284        DKIM_STAT status;
03285        int hashtype = DKIM_HASHTYPE_UNKNOWN;
03286        DKIM_CANON *bc;
03287        DKIM_CANON *hc;
03288        DKIM_LIB *lib;
03289 
03290        assert(dkim != NULL);
03291 
03292 #ifdef _FFR_RESIGN
03293        if (dkim->dkim_hdrbind)
03294               return DKIM_STAT_INVALID;
03295 #endif /* _FFR_RESIGN */
03296 
03297        if (dkim->dkim_state >= DKIM_STATE_EOH2)
03298               return DKIM_STAT_INVALID;
03299        if (dkim->dkim_state < DKIM_STATE_EOH2)
03300               dkim->dkim_state = DKIM_STATE_EOH2;
03301 
03302        lib = dkim->dkim_libhandle;
03303        assert(lib != NULL);
03304 
03305        tmp = ((lib->dkiml_flags & DKIM_LIBFLAGS_TMPFILES) != 0);
03306        keep = ((lib->dkiml_flags & DKIM_LIBFLAGS_KEEPFILES) != 0);
03307 
03308        dkim->dkim_version = lib->dkiml_version;
03309 
03310        /* check for header validity */
03311        if (!dkim_headercheck(dkim))
03312        {
03313               dkim->dkim_state = DKIM_STATE_UNUSABLE;
03314               return DKIM_STAT_SYNTAX;
03315        }
03316 
03317        /*
03318        **  Verify that all the required headers are present and
03319        **  marked for signing.
03320        */
03321 
03322        hn = (u_char *) dkim_check_requiredhdrs(dkim);
03323        if (hn != NULL)
03324        {
03325               dkim_error(dkim, "required header \"%s\" not found", hn);
03326               dkim->dkim_state = DKIM_STATE_UNUSABLE;
03327               return DKIM_STAT_SYNTAX;
03328        }
03329 
03330        /* determine hash type */
03331        switch (dkim->dkim_signalg)
03332        {
03333          case DKIM_SIGN_RSASHA1:
03334               hashtype = DKIM_HASHTYPE_SHA1;
03335               break;
03336 
03337          case DKIM_SIGN_RSASHA256:
03338               hashtype = DKIM_HASHTYPE_SHA256;
03339               break;
03340 
03341          default:
03342               assert(0);
03343               /* NOTREACHED */
03344        }
03345 
03346        if (dkim->dkim_siglist == NULL)
03347        {
03348               /* initialize signature and canonicalization for signing */
03349               dkim->dkim_siglist = DKIM_MALLOC(dkim, sizeof(DKIM_SIGINFO **));
03350               if (dkim->dkim_siglist == NULL)
03351               {
03352                      dkim_error(dkim, "failed to allocate %d byte(s)",
03353                                 sizeof(DKIM_SIGINFO *));
03354                      return DKIM_STAT_NORESOURCE;
03355               }
03356 
03357               dkim->dkim_siglist[0] = DKIM_MALLOC(dkim,
03358                                                   sizeof(struct dkim_siginfo));
03359               if (dkim->dkim_siglist[0] == NULL)
03360               {
03361                      dkim_error(dkim, "failed to allocate %d byte(s)",
03362                                 sizeof(struct dkim_siginfo));
03363                      return DKIM_STAT_NORESOURCE;
03364               }
03365               dkim->dkim_sigcount = 1;
03366               memset(dkim->dkim_siglist[0], '\0',
03367                      sizeof(struct dkim_siginfo));
03368               dkim->dkim_siglist[0]->sig_domain = dkim->dkim_domain;
03369               dkim->dkim_siglist[0]->sig_selector = dkim->dkim_selector;
03370               dkim->dkim_siglist[0]->sig_hashtype = hashtype;
03371               dkim->dkim_siglist[0]->sig_signalg = dkim->dkim_signalg;
03372 
03373               status = dkim_add_canon(dkim, TRUE, dkim->dkim_hdrcanonalg,
03374                                       hashtype, NULL, NULL, 0, &hc);
03375               if (status != DKIM_STAT_OK)
03376                      return status;
03377 
03378               status = dkim_add_canon(dkim, FALSE, dkim->dkim_bodycanonalg,
03379                                       hashtype, NULL, NULL,
03380                                       dkim->dkim_signlen, &bc);
03381               if (status != DKIM_STAT_OK)
03382                      return status;
03383 
03384               dkim->dkim_siglist[0]->sig_hdrcanon = hc;
03385               dkim->dkim_siglist[0]->sig_hdrcanonalg = dkim->dkim_hdrcanonalg;
03386               dkim->dkim_siglist[0]->sig_bodycanon = bc;
03387               dkim->dkim_siglist[0]->sig_bodycanonalg = dkim->dkim_bodycanonalg;
03388 
03389               if (dkim->dkim_libhandle->dkiml_fixedtime != 0)
03390               {
03391                      dkim->dkim_siglist[0]->sig_timestamp = dkim->dkim_libhandle->dkiml_fixedtime;
03392               }
03393               else
03394               {
03395                      time_t now;
03396 
03397                      (void) time(&now);
03398 
03399                      dkim->dkim_siglist[0]->sig_timestamp = (uint64_t) now;
03400               }
03401        }
03402 
03403        /* initialize all canonicalizations */
03404        status = dkim_canon_init(dkim, tmp, keep);
03405        if (status != DKIM_STAT_OK)
03406               return status;
03407 
03408        /* run the headers */
03409        status = dkim_canon_runheaders(dkim);
03410        if (status != DKIM_STAT_OK)
03411               return status;
03412 
03413        return DKIM_STAT_OK;
03414 }
03415 
03416 /*
03417 **  DKIM_EOH_VERIFY -- declare end-of-headers; set up verification
03418 ** 
03419 **  Parameters:
03420 **     dkim -- DKIM handle
03421 **
03422 **  Return value:
03423 **     A DKIM_STAT_* constant.
03424 */
03425 
03426 static DKIM_STAT
03427 dkim_eoh_verify(DKIM *dkim)
03428 {
03429        _Bool keep;
03430        _Bool tmp;
03431        _Bool bsh;
03432        DKIM_STAT status;
03433        int c;
03434        DKIM_LIB *lib;
03435        DKIM_SET *set;
03436 
03437        assert(dkim != NULL);
03438 
03439        if (dkim->dkim_state >= DKIM_STATE_EOH2)
03440               return DKIM_STAT_INVALID;
03441        if (dkim->dkim_state < DKIM_STATE_EOH1)
03442               dkim->dkim_state = DKIM_STATE_EOH1;
03443 
03444        lib = dkim->dkim_libhandle;
03445        assert(lib != NULL);
03446 
03447        bsh = ((lib->dkiml_flags & DKIM_LIBFLAGS_BADSIGHANDLES) != 0);
03448        tmp = ((lib->dkiml_flags & DKIM_LIBFLAGS_TMPFILES) != 0);
03449        keep = ((lib->dkiml_flags & DKIM_LIBFLAGS_KEEPFILES) != 0);
03450 
03451        /* populate some stuff like dkim_sender, dkim_domain, dkim_user */
03452        status = dkim_getsender(dkim, dkim->dkim_libhandle->dkiml_senderhdrs);
03453        if (status != DKIM_STAT_OK && !bsh)
03454        {
03455               dkim->dkim_state = DKIM_STATE_UNUSABLE;
03456               return status;
03457        }
03458 
03459        /* check for header validity */
03460        if (!dkim_headercheck(dkim))
03461        {
03462               dkim->dkim_state = DKIM_STATE_UNUSABLE;
03463               return DKIM_STAT_SYNTAX;
03464        }
03465 
03466        /* allocate the siginfo array if not already done */
03467        if (dkim->dkim_siglist == NULL)
03468        {
03469               /* count the signatures */
03470               for (set = dkim_set_first(dkim, DKIM_SETTYPE_SIGNATURE);
03471                    set != NULL;
03472                    set = dkim_set_next(set, DKIM_SETTYPE_SIGNATURE))
03473               {
03474                      if (!set->set_bad || bsh)
03475                             dkim->dkim_sigcount++;
03476               }
03477 
03478               /* if no signatures, return such */
03479               if (dkim->dkim_sigcount == 0)
03480               {
03481                      dkim->dkim_skipbody = TRUE;
03482                      return DKIM_STAT_NOSIG;
03483               }
03484 
03485               status = dkim_siglist_setup(dkim);
03486               if (status != DKIM_STAT_OK)
03487                      return status;
03488 
03489               /* initialize all discovered canonicalizations */
03490               status = dkim_canon_init(dkim, tmp, keep);
03491               if (status != DKIM_STAT_OK)
03492                      return status;
03493        }
03494 
03495        /* call the prescreen callback, if defined */
03496        if (lib->dkiml_prescreen != NULL && !dkim->dkim_eoh_reentry)
03497        {
03498               status = lib->dkiml_prescreen(dkim,
03499                                             dkim->dkim_siglist,
03500                                             dkim->dkim_sigcount);
03501               switch (status)
03502               {
03503                 case DKIM_CBSTAT_CONTINUE:
03504                      break;
03505 
03506                 case DKIM_CBSTAT_REJECT:
03507                      return DKIM_STAT_CBREJECT;
03508 
03509                 case DKIM_CBSTAT_TRYAGAIN:
03510                      return DKIM_STAT_CBTRYAGAIN;
03511 
03512                 case DKIM_CBSTAT_ERROR:
03513                      return DKIM_STAT_CBERROR;
03514 
03515                 default:
03516                      return DKIM_STAT_CBINVALID;
03517               }
03518        }
03519 
03520        dkim->dkim_state = DKIM_STATE_EOH2;
03521 
03522        /* if set to ignore everything, treat message as unsigned */
03523        set = NULL;
03524        for (c = 0; c < dkim->dkim_sigcount; c++)
03525        {
03526               if (!(dkim->dkim_siglist[c]->sig_flags & DKIM_SIGFLAG_IGNORE))
03527               {
03528                      set = dkim->dkim_siglist[c]->sig_taglist;
03529                      break;
03530               }
03531        }
03532 
03533        if (set == NULL)
03534        {
03535               dkim->dkim_skipbody = TRUE;
03536               return DKIM_STAT_NOSIG;
03537        }
03538 
03539        /* run the headers */
03540        if (!dkim->dkim_eoh_reentry)
03541        {
03542               status = dkim_canon_runheaders(dkim);
03543               if (status != DKIM_STAT_OK)
03544                      return status;
03545        }
03546 
03547        /* do public key verification of all still-enabled signatures here */
03548        if ((lib->dkiml_flags & DKIM_LIBFLAGS_DELAYSIGPROC) == 0)
03549        {
03550               for (c = 0; c < dkim->dkim_sigcount; c++)
03551               {
03552                      if (!(dkim->dkim_siglist[c]->sig_flags & DKIM_SIGFLAG_PROCESSED) &&
03553                          !(dkim->dkim_siglist[c]->sig_flags & DKIM_SIGFLAG_IGNORE) &&
03554                          dkim->dkim_siglist[c]->sig_error == DKIM_SIGERROR_UNKNOWN)
03555                      {
03556                             status = dkim_sig_process(dkim,
03557                                                       dkim->dkim_siglist[c]);
03558                             if (status != DKIM_STAT_OK)
03559                             {
03560                                    if (status == DKIM_STAT_CBTRYAGAIN)
03561                                           dkim->dkim_eoh_reentry = TRUE;
03562 
03563                                    return status;
03564                             }
03565                      }
03566               }
03567        }
03568 
03569        /*
03570        **  Possible short-circuit here if all signatures are:
03571        **  - marked to be ignored
03572        **  - definitely invalid
03573        **  - verification attempted but failed
03574        */
03575 
03576        if ((lib->dkiml_flags & DKIM_LIBFLAGS_EOHCHECK) != 0)
03577        {
03578               _Bool good = FALSE;
03579               DKIM_SIGINFO *sig;
03580 
03581               for (c = 0; c < dkim->dkim_sigcount; c++)
03582               {
03583                      sig = dkim->dkim_siglist[c];
03584 
03585                      /* ignored? */
03586                      if ((sig->sig_flags & DKIM_SIGFLAG_IGNORE) != 0)
03587                             continue;
03588 
03589                      /* had a processing error? */
03590                      if (sig->sig_error != DKIM_SIGERROR_UNKNOWN &&
03591                          sig->sig_error != DKIM_SIGERROR_OK)
03592                             continue;
03593 
03594                      /* processed but didn't pass? */
03595                      if ((sig->sig_flags & DKIM_SIGFLAG_PROCESSED) != 0 &&
03596                          (sig->sig_flags & DKIM_SIGFLAG_PASSED) == 0)
03597                             continue;
03598 
03599                      /* OK we had a good one */
03600                      good = TRUE;
03601                      break;
03602               }
03603 
03604               /* no good ones */
03605               if (!good)
03606               {
03607                      /* report error on the last one */
03608                      if (sig->sig_error != DKIM_SIGERROR_UNKNOWN &&
03609                          sig->sig_error != DKIM_SIGERROR_OK)
03610                      {
03611                             dkim_error(dkim,
03612                                        dkim_code_to_name(sigerrors,
03613                                                          sig->sig_error));
03614                      }
03615 
03616                      return DKIM_STAT_CANTVRFY;
03617               }
03618        }
03619 
03620        return DKIM_STAT_OK;
03621 }
03622 
03623 /*
03624 **  DKIM_EOM_SIGN -- declare end-of-body; complete signing
03625 **
03626 **  Parameters:
03627 **     dkim -- DKIM handle
03628 **
03629 **  Return value:
03630 **     A DKIM_STAT_* constant.
03631 */
03632 
03633 static DKIM_STAT
03634 dkim_eom_sign(DKIM *dkim)
03635 {
03636        int status;
03637        u_int l;
03638        size_t diglen;
03639        size_t siglen = 0;
03640        size_t len;
03641        DKIM_STAT ret;
03642        u_char *digest;
03643        u_char *sighdr;
03644        u_char *signature = NULL;
03645        DKIM_SIGINFO *sig;
03646        DKIM_CANON *hc;
03647        struct dkim_dstring *tmphdr;
03648        struct dkim_rsa *rsa = NULL;
03649        struct dkim_header hdr;
03650 
03651        assert(dkim != NULL);
03652 
03653 #ifdef _FFR_RESIGN
03654        if (dkim->dkim_resign != NULL)
03655        {
03656               if (dkim->dkim_hdrbind)
03657               {
03658                      if (dkim->dkim_state != DKIM_STATE_INIT ||
03659                          dkim->dkim_resign->dkim_state != DKIM_STATE_EOM2)
03660                             return DKIM_STAT_INVALID;
03661               }
03662               else
03663               {
03664                      if (dkim->dkim_state < DKIM_STATE_EOH1 ||
03665                          dkim->dkim_resign->dkim_state != DKIM_STATE_EOM2)
03666                             return DKIM_STAT_INVALID;
03667               }
03668        }
03669        else if (dkim->dkim_state >= DKIM_STATE_EOM2 ||
03670                 dkim->dkim_state < DKIM_STATE_EOH1)
03671        {
03672               return DKIM_STAT_INVALID;
03673        }
03674 #else /* _FFR_RESIGN */
03675        if (dkim->dkim_state >= DKIM_STATE_EOM2 ||
03676            dkim->dkim_state < DKIM_STATE_EOH1)
03677               return DKIM_STAT_INVALID;
03678 #endif /* _FFR_RESIGN */
03679 
03680        if (dkim->dkim_chunkstate != DKIM_CHUNKSTATE_INIT &&
03681            dkim->dkim_chunkstate != DKIM_CHUNKSTATE_DONE)
03682               return DKIM_STAT_INVALID;
03683 
03684        if (dkim->dkim_state < DKIM_STATE_EOM2)
03685               dkim->dkim_state = DKIM_STATE_EOM2;
03686 
03687 #ifdef _FFR_RESIGN
03688        /*
03689        **  Verify that all the required headers are present and
03690        **  marked for signing.
03691        */
03692 
03693        if (dkim->dkim_resign != NULL)
03694        {
03695               char *hn;
03696 
03697               if (dkim->dkim_hdrbind)
03698                      dkim->dkim_hhead = dkim->dkim_resign->dkim_hhead;
03699 
03700               hn = (u_char *) dkim_check_requiredhdrs(dkim);
03701               if (hn != NULL)
03702               {
03703                      dkim_error(dkim, "required header \"%s\" not found",
03704                                 hn);
03705                      dkim->dkim_state = DKIM_STATE_UNUSABLE;
03706                      return DKIM_STAT_SYNTAX;
03707               }
03708        }
03709 #endif /* _FFR_RESIGN */
03710 
03711        /* finalize body canonicalizations */
03712        (void) dkim_canon_closebody(dkim);
03713 
03714        dkim->dkim_bodydone = TRUE;
03715 
03716        /* set signature timestamp */
03717        if (dkim->dkim_libhandle->dkiml_fixedtime != 0)
03718        {
03719               dkim->dkim_timestamp = dkim->dkim_libhandle->dkiml_fixedtime;
03720        }
03721        else
03722        {
03723               time_t now;
03724 
03725               (void) time(&now);
03726               dkim->dkim_timestamp = (uint64_t) now;
03727        }
03728 
03729        /* sign with l= if requested */
03730        if ((dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_SIGNLEN) != 0)
03731               dkim->dkim_partial = TRUE;
03732 
03733        /* get signature and canonicalization handles */
03734        assert(dkim->dkim_siglist != NULL);
03735        assert(dkim->dkim_siglist[0] != NULL);
03736        sig = dkim->dkim_siglist[0];
03737        hc = sig->sig_hdrcanon;
03738 
03739        if (dkim->dkim_keydata == NULL)
03740        {
03741               if (dkim_privkey_load(dkim) != DKIM_STAT_OK)
03742                      return DKIM_STAT_NORESOURCE;
03743        }
03744 
03745        rsa = dkim->dkim_keydata;
03746 #ifdef USE_GNUTLS
03747        if (rsa->rsa_privkey == NULL)
03748 #else /* USE_GNUTLS */
03749        if (rsa->rsa_rsa == NULL)
03750 #endif /* USE_GNUTLS */
03751        {
03752               dkim_error(dkim, "private key load failed");
03753               return DKIM_STAT_NORESOURCE;
03754        }
03755 
03756        sig->sig_keybits = rsa->rsa_keysize;
03757        sig->sig_signature = dkim->dkim_keydata;
03758        sig->sig_flags |= DKIM_SIGFLAG_KEYLOADED;
03759 
03760        switch (sig->sig_signalg)
03761        {
03762          case DKIM_SIGN_RSASHA1:
03763          case DKIM_SIGN_RSASHA256:
03764          {
03765               assert(sig->sig_hashtype == DKIM_HASHTYPE_SHA1 ||
03766                      sig->sig_hashtype == DKIM_HASHTYPE_SHA256);
03767 
03768               if (sig->sig_hashtype == DKIM_HASHTYPE_SHA256)
03769               {
03770                      assert(dkim_libfeature(dkim->dkim_libhandle,
03771                                              DKIM_FEATURE_SHA256));
03772               }
03773 
03774               sig->sig_signature = (void *) dkim->dkim_keydata;
03775               sig->sig_keytype = DKIM_KEYTYPE_RSA;
03776 
03777               break;
03778          }
03779 
03780          default:
03781               assert(0);
03782        }
03783 
03784        /* construct the DKIM signature header to be canonicalized */
03785        tmphdr = dkim_dstring_new(dkim, BUFRSZ, MAXBUFRSZ);
03786        if (tmphdr == NULL)
03787               return DKIM_STAT_NORESOURCE;
03788 
03789        dkim_dstring_catn(tmphdr, (u_char *) DKIM_SIGNHEADER ": ",
03790                          sizeof DKIM_SIGNHEADER + 1);
03791 
03792        ret = dkim_getsighdr_d(dkim, dkim_dstring_len(tmphdr), &sighdr, &len);
03793        if (ret != DKIM_STAT_OK)
03794        {
03795               dkim_dstring_free(tmphdr);
03796               return ret;
03797        }
03798 
03799        dkim_dstring_catn(tmphdr, sighdr, len);
03800        len = dkim_dstring_len(tmphdr);
03801 
03802        hdr.hdr_text = dkim_dstring_get(tmphdr);
03803        hdr.hdr_colon = hdr.hdr_text + DKIM_SIGNHEADER_LEN;
03804        hdr.hdr_namelen = DKIM_SIGNHEADER_LEN;
03805        hdr.hdr_textlen = len;
03806        hdr.hdr_flags = 0;
03807        hdr.hdr_next = NULL;
03808 
03809        /* canonicalize */
03810 #ifdef _FFR_RESIGN
03811        if (dkim->dkim_resign != NULL && dkim->dkim_hdrbind)
03812               dkim->dkim_canonhead = dkim->dkim_resign->dkim_canonhead;
03813 #endif /* _FFR_RESIGN */
03814        dkim_canon_signature(dkim, &hdr);
03815 
03816        dkim_dstring_free(tmphdr);
03817 
03818        /* finalize */
03819        ret = dkim_canon_getfinal(hc, &digest, &diglen);
03820        if (ret != DKIM_STAT_OK)
03821        {
03822               dkim_error(dkim, "dkim_canon_getfinal() failed");
03823               return DKIM_STAT_INTERNAL;
03824        }
03825 
03826        /* compute and store the signature */
03827        switch (sig->sig_signalg)
03828        {
03829 #ifdef USE_GNUTLS
03830          case DKIM_SIGN_RSASHA1:
03831          case DKIM_SIGN_RSASHA256:
03832          {
03833               int alg;
03834               gnutls_datum_t dd;
03835               struct dkim_rsa *rsa;
03836 
03837               rsa = (struct dkim_rsa *) sig->sig_signature;
03838 
03839               dd.data = digest;
03840               dd.size = diglen;
03841 
03842               if (sig->sig_signalg == DKIM_SIGN_RSASHA1)
03843                      alg = GNUTLS_DIG_SHA1;
03844               else
03845                      alg = GNUTLS_DIG_SHA256;
03846 
03847               status = gnutls_privkey_sign_hash(rsa->rsa_privkey, alg, 0,
03848                                                 &dd, &rsa->rsa_rsaout);
03849               if (status != GNUTLS_E_SUCCESS)
03850               {
03851                      dkim_error(dkim,
03852                                 "signature generation failed (status %d)",
03853                                 status);
03854                      return DKIM_STAT_INTERNAL;
03855               }
03856 
03857               signature = rsa->rsa_rsaout.data;
03858               siglen = rsa->rsa_rsaout.size;
03859 
03860               break;
03861          }
03862 #else /* USE_GNUTLS */
03863          case DKIM_SIGN_RSASHA1:
03864          case DKIM_SIGN_RSASHA256:
03865          {
03866               int nid;
03867               struct dkim_rsa *rsa;
03868 
03869               rsa = (struct dkim_rsa *) sig->sig_signature;
03870 
03871               nid = NID_sha1;
03872 
03873               if (dkim_libfeature(dkim->dkim_libhandle,
03874                                   DKIM_FEATURE_SHA256) &&
03875                   sig->sig_hashtype == DKIM_HASHTYPE_SHA256)
03876                      nid = NID_sha256;
03877 
03878               status = RSA_sign(nid, digest, diglen,
03879                                  rsa->rsa_rsaout, &l, rsa->rsa_rsa);
03880               if (status != 1 || l == 0)
03881               {
03882                      RSA_free(rsa->rsa_rsa);
03883                      rsa->rsa_rsa = NULL;
03884                      BIO_free(rsa->rsa_keydata);
03885                      rsa->rsa_keydata = NULL;
03886                      dkim_error(dkim,
03887                                 "signature generation failed (status %d, length %d)",
03888                                 status, l);
03889                      return DKIM_STAT_INTERNAL;
03890               }
03891 
03892               rsa->rsa_rsaoutlen = l;
03893 
03894               signature = rsa->rsa_rsaout;
03895               siglen = rsa->rsa_rsaoutlen;
03896 
03897               break;
03898          }
03899 #endif /* USE_GNUTLS */
03900 
03901          default:
03902               assert(0);
03903        }
03904 
03905        /* base64-encode the signature */
03906        dkim->dkim_b64siglen = siglen * 3 + 5;
03907        dkim->dkim_b64siglen += (dkim->dkim_b64siglen / 60);
03908        dkim->dkim_b64sig = DKIM_MALLOC(dkim, dkim->dkim_b64siglen);
03909        if (dkim->dkim_b64sig == NULL)
03910        {
03911               dkim_error(dkim, "unable to allocate %d byte(s)",
03912                          dkim->dkim_b64siglen);
03913 #ifndef USE_GNUTLS
03914               BIO_free(rsa->rsa_keydata);
03915               rsa->rsa_keydata = NULL;
03916 #endif /* ! USE_GNUTLS */
03917               return DKIM_STAT_NORESOURCE;
03918        }
03919        memset(dkim->dkim_b64sig, '\0', dkim->dkim_b64siglen);
03920 
03921        status = dkim_base64_encode(signature, siglen, dkim->dkim_b64sig,
03922                                    dkim->dkim_b64siglen);
03923 
03924 #ifndef USE_GNUTLS
03925        BIO_free(rsa->rsa_keydata);
03926        rsa->rsa_keydata = NULL;
03927 #endif /* ! USE_GNUTLS */
03928 
03929        if (status == -1)
03930        {
03931               dkim_error(dkim,
03932                          "base64 encoding error (buffer too small)");
03933               return DKIM_STAT_NORESOURCE;
03934        }
03935 
03936        dkim->dkim_signature = sig;
03937 
03938        return DKIM_STAT_OK;
03939 }
03940 
03941 /*
03942 **  DKIM_EOM_VERIFY -- declare end-of-body; complete verification
03943 **
03944 **  Parameters:
03945 **     dkim -- DKIM handle
03946 **     testkey -- TRUE iff the a matching key was found but is marked as a
03947 **                test key (returned)
03948 **
03949 **  Return value:
03950 **     A DKIM_STAT_* constant.
03951 */
03952 
03953 static DKIM_STAT
03954 dkim_eom_verify(DKIM *dkim, _Bool *testkey)
03955 {
03956        DKIM_STAT ret;
03957        int c;
03958        int status;
03959        DKIM_SIGINFO *sig = NULL;
03960        struct dkim_header *hdr;
03961        DKIM_LIB *lib;
03962 
03963        assert(dkim != NULL);
03964 
03965        if (dkim->dkim_state >= DKIM_STATE_EOM2 ||
03966            dkim->dkim_state < DKIM_STATE_EOH1)
03967               return DKIM_STAT_INVALID;
03968        if (dkim->dkim_state < DKIM_STATE_EOM1)
03969               dkim->dkim_state = DKIM_STATE_EOM1;
03970 
03971        if (dkim->dkim_chunkstate != DKIM_CHUNKSTATE_INIT &&
03972            dkim->dkim_chunkstate != DKIM_CHUNKSTATE_DONE)
03973               return DKIM_STAT_INVALID;
03974 
03975        /* finalize body canonicalizations */
03976        (void) dkim_canon_closebody(dkim);
03977 
03978        dkim->dkim_bodydone = TRUE;
03979 
03980        if (dkim->dkim_sigcount == 0)
03981        {                                  /* unsigned */
03982               if (dkim->dkim_domain == NULL)
03983               {
03984                      u_char *domain;
03985                      u_char *user;
03986 
03987                      hdr = dkim_get_header(dkim, (u_char *) DKIM_FROMHEADER,
03988                                            DKIM_FROMHEADER_LEN, 0);
03989                      if (hdr == NULL)
03990                      {
03991                             dkim_error(dkim, "no %s header found",
03992                                        DKIM_FROMHEADER);
03993                             return DKIM_STAT_CANTVRFY;
03994                      }
03995 
03996                      if (hdr->hdr_colon == NULL)
03997                      {
03998                             dkim_error(dkim, "%s header malformed",
03999                                        DKIM_FROMHEADER);
04000                             return DKIM_STAT_CANTVRFY;
04001                      }
04002 
04003                      status = dkim_mail_parse(hdr->hdr_colon + 1,
04004                                               &user, &domain);
04005                      if (status != 0 || domain == NULL || domain[0] == '\0')
04006                      {
04007                             dkim_error(dkim, "%s header malformed",
04008                                        DKIM_FROMHEADER);
04009                             return DKIM_STAT_CANTVRFY;
04010                      }
04011 
04012                      dkim->dkim_domain = dkim_strdup(dkim, domain, 0);
04013                      if (dkim->dkim_domain == NULL)
04014                             return DKIM_STAT_NORESOURCE;
04015               }
04016 
04017               dkim->dkim_state = DKIM_STATE_EOM2;
04018 
04019               return DKIM_STAT_NOSIG;
04020        }
04021 
04022        lib = dkim->dkim_libhandle;
04023 
04024        /*
04025        **  If a signature has "l=" set but it was greater than the
04026        **  canonicalized body length, the signature is invalid.
04027        */
04028 
04029        for (c = 0; c < dkim->dkim_sigcount; c++)
04030        {
04031               sig = dkim->dkim_siglist[c];
04032 
04033               if (sig->sig_bodycanon != NULL &&
04034                   sig->sig_bodycanon->canon_length != (ssize_t) -1 &&
04035                   sig->sig_bodycanon->canon_wrote < sig->sig_bodycanon->canon_length)
04036                      sig->sig_error = DKIM_SIGERROR_TOOLARGE_L;
04037        }
04038 
04039        /* invoke the final callback if defined */
04040        if (lib->dkiml_final != NULL)
04041        {
04042               status = lib->dkiml_final(dkim, dkim->dkim_siglist,
04043                                         dkim->dkim_sigcount);
04044               switch (status)
04045               {
04046                 case DKIM_CBSTAT_CONTINUE:
04047                      break;
04048 
04049                 case DKIM_CBSTAT_REJECT:
04050                      return DKIM_STAT_CBREJECT;
04051 
04052                 case DKIM_CBSTAT_TRYAGAIN:
04053                      return DKIM_STAT_CBTRYAGAIN;
04054 
04055                 case DKIM_CBSTAT_ERROR:
04056                      return DKIM_STAT_CBERROR;
04057 
04058                 default:
04059                      return DKIM_STAT_CBINVALID;
04060               }
04061        }
04062 
04063        dkim->dkim_state = DKIM_STATE_EOM2;
04064 
04065        /* see if we have a passing signature with bh match */
04066        for (c = 0; c < dkim->dkim_sigcount; c++)
04067        {
04068               sig = dkim->dkim_siglist[c];
04069 
04070               if ((sig->sig_flags & DKIM_SIGFLAG_PASSED) != 0 &&
04071                   (sig->sig_flags & DKIM_SIGFLAG_IGNORE) == 0 &&
04072                   sig->sig_bh == DKIM_SIGBH_MATCH)
04073                      break;
04074 
04075               sig = NULL;
04076        }
04077 
04078        /* run 'em until we get one */
04079        if (sig == NULL)
04080        {
04081               DKIM_SIGINFO *firstgood = NULL;
04082 
04083               for (c = 0; c < dkim->dkim_sigcount; c++)
04084               {
04085                      sig = dkim->dkim_siglist[c];
04086 
04087                      /* if not ignoring */
04088                      if ((sig->sig_flags & DKIM_SIGFLAG_IGNORE) == 0)
04089                      {
04090                             /* run this signature */
04091                             status = dkim_sig_process(dkim, sig);
04092                             if (status != DKIM_STAT_OK)
04093                             {
04094                                    sig = NULL;
04095                                    continue;
04096                             }
04097 
04098                             /* pass and bh match? */
04099                             if ((sig->sig_flags & DKIM_SIGFLAG_PASSED) != 0 &&
04100                                 sig->sig_bh == DKIM_SIGBH_MATCH)
04101                             {
04102                                    if (firstgood == NULL)
04103                                           firstgood = sig;
04104 
04105                                    /* continue? */
04106                                    if ((lib->dkiml_flags & DKIM_LIBFLAGS_VERIFYONE) != 0)
04107                                           break;
04108                             }
04109                      }
04110 
04111                      sig = NULL;
04112               }
04113 
04114               if (sig == NULL)
04115                      sig = firstgood;
04116        }
04117 
04118        /*
04119        **  If still none, we're going to fail so just use the
04120        **  first one.
04121        */
04122 
04123        if (sig == NULL)
04124        {
04125               for (c = 0; c < dkim->dkim_sigcount; c++)
04126               {
04127                      sig = dkim->dkim_siglist[c];
04128                      if ((sig->sig_flags & DKIM_SIGFLAG_IGNORE) == 0)
04129                             break;
04130                      sig = NULL;
04131               }
04132        }
04133 
04134        /* caller marked everything with "ignore" */
04135        if (sig == NULL)
04136        {
04137               dkim_error(dkim, "all signatures ignored by caller");
04138               return DKIM_STAT_NOSIG;
04139        }
04140 
04141        dkim->dkim_signature = sig;
04142 
04143        /* things for which we return DKIM_STAT_CANTVRFY */
04144        if (sig->sig_error != DKIM_SIGERROR_OK &&
04145            sig->sig_error != DKIM_SIGERROR_UNKNOWN &&
04146            sig->sig_error != DKIM_SIGERROR_KEYFAIL &&
04147            sig->sig_error != DKIM_SIGERROR_BADSIG &&
04148            sig->sig_error != DKIM_SIGERROR_KEYREVOKED &&
04149            sig->sig_error != DKIM_SIGERROR_NOKEY)
04150        {
04151               if (dkim->dkim_error == NULL ||
04152                   dkim->dkim_error[0] == '\0')
04153               {
04154                      dkim_error(dkim, dkim_code_to_name(sigerrors,
04155                                                         sig->sig_error));
04156               }
04157 
04158               return DKIM_STAT_CANTVRFY;
04159        }
04160 
04161        /* initialize final result */
04162        ret = DKIM_STAT_OK;
04163        if (sig->sig_error == DKIM_SIGERROR_NOKEY)
04164               ret = DKIM_STAT_NOKEY;
04165        else if (sig->sig_error == DKIM_SIGERROR_KEYFAIL)
04166               ret = DKIM_STAT_KEYFAIL;
04167        else if (sig->sig_error == DKIM_SIGERROR_KEYREVOKED)
04168               ret = DKIM_STAT_REVOKED;
04169        else if ((sig->sig_flags & DKIM_SIGFLAG_PASSED) == 0)
04170               ret = DKIM_STAT_BADSIG;
04171        else if (sig->sig_bh == DKIM_SIGBH_MISMATCH)
04172               ret = DKIM_STAT_BADSIG;
04173        else if (sig->sig_error == DKIM_SIGERROR_BADSIG)
04174               ret = DKIM_STAT_BADSIG;
04175 
04176        /* set testkey based on the key flags */
04177        if (testkey != NULL &&
04178            (sig->sig_flags & DKIM_SIGFLAG_TESTKEY) != 0)
04179               *testkey = TRUE;
04180 
04181        return ret;
04182 }
04183 
04184 /*
04185 **  DKIM_NEW -- allocate a new message context
04186 **
04187 **  Parameters:
04188 **     libhandle -- DKIM_LIB handle
04189 **     id -- transaction ID string
04190 **     memclosure -- memory closure
04191 **     hdrcanon_alg -- canonicalization algorithm to use for headers
04192 **     bodycanon_alg -- canonicalization algorithm to use for headers
04193 **     sign_alg -- signature algorithm to use
04194 **     statp -- status (returned)
04195 **
04196 **  Return value:
04197 **     A new DKIM handle, or NULL on failure.
04198 */
04199 
04200 static DKIM *
04201 dkim_new(DKIM_LIB *libhandle, const unsigned char *id, void *memclosure,
04202          dkim_canon_t hdrcanon_alg, dkim_canon_t bodycanon_alg,
04203          dkim_alg_t sign_alg, DKIM_STAT *statp)
04204 {
04205        DKIM *new;
04206 
04207        assert(libhandle != NULL);
04208 
04209        /* allocate the handle */
04210        new = (DKIM *) dkim_malloc(libhandle, memclosure,
04211                                   sizeof(struct dkim));
04212        if (new == NULL)
04213        {
04214               *statp = DKIM_STAT_NORESOURCE;
04215               return NULL;
04216        }
04217 
04218        /* populate defaults */
04219        memset(new, '\0', sizeof(struct dkim));
04220        new->dkim_id = id;
04221        new->dkim_signalg = (sign_alg == -1 ? DKIM_SIGN_DEFAULT
04222                                            : sign_alg);
04223        new->dkim_hdrcanonalg = (hdrcanon_alg == -1 ? DKIM_CANON_DEFAULT
04224                                                    : hdrcanon_alg);
04225        new->dkim_bodycanonalg = (bodycanon_alg == -1 ? DKIM_CANON_DEFAULT
04226                                                      : bodycanon_alg);
04227        new->dkim_querymethod = DKIM_QUERY_DEFAULT;
04228        new->dkim_mode = DKIM_MODE_UNKNOWN;
04229        new->dkim_chunkcrlf = DKIM_CRLF_UNKNOWN;
04230        new->dkim_state = DKIM_STATE_INIT;
04231        new->dkim_presult = DKIM_PRESULT_NONE;
04232        new->dkim_dnssec_policy = DKIM_DNSSEC_UNKNOWN;
04233        new->dkim_margin = (size_t) DKIM_HDRMARGIN;
04234        new->dkim_closure = memclosure;
04235        new->dkim_libhandle = libhandle;
04236        new->dkim_tmpdir = libhandle->dkiml_tmpdir;
04237        new->dkim_timeout = libhandle->dkiml_timeout;
04238 
04239        *statp = DKIM_STAT_OK;
04240 
04241 #ifdef QUERY_CACHE
04242        if ((libhandle->dkiml_flags & DKIM_LIBFLAGS_CACHE) != 0 &&
04243            libhandle->dkiml_cache == NULL)
04244        {
04245               int err = 0;
04246 
04247               libhandle->dkiml_cache = dkim_cache_init(&err,
04248                                                        libhandle->dkiml_tmpdir);
04249        }
04250 #endif /* QUERY_CACHE */
04251 
04252        return new;
04253 }
04254 
04255 #ifndef USE_GNUTLS
04256 /*
04257 **  DKIM_INIT_OPENSSL -- initialize OpenSSL algorithms if needed
04258 **
04259 **  Parameters:
04260 **     None.
04261 **
04262 **  Return value:
04263 **     None.
04264 */
04265 
04266 static pthread_mutex_t openssl_lock = PTHREAD_MUTEX_INITIALIZER;
04267 static unsigned openssl_refcount = 0;
04268 
04269 static void
04270 dkim_init_openssl(void)
04271 {
04272        pthread_mutex_lock(&openssl_lock);
04273 
04274        if (openssl_refcount == 0)
04275               OpenSSL_add_all_algorithms();
04276        openssl_refcount++;
04277 
04278        pthread_mutex_unlock(&openssl_lock);
04279 }
04280 
04281 /*
04282 **  DKIM_CLOSE_OPENSSL -- clean up OpenSSL algorithms if needed
04283 **
04284 **  Parameters:
04285 **     None.
04286 **
04287 **  Return value:
04288 **     None.
04289 */
04290 
04291 static void
04292 dkim_close_openssl(void)
04293 {
04294        assert(openssl_refcount > 0);
04295 
04296        pthread_mutex_lock(&openssl_lock);
04297 
04298        openssl_refcount--;
04299        if (openssl_refcount == 0)
04300               EVP_cleanup();
04301 
04302        pthread_mutex_unlock(&openssl_lock);
04303 }
04304 #endif /* ! USE_GNUTLS */
04305 
04306 /* ========================= PUBLIC SECTION ========================== */
04307 
04308 /*
04309 **  DKIM_INIT -- initialize a DKIM library context
04310 **
04311 **  Parameters:
04312 **     caller_mallocf -- caller-provided memory allocation function
04313 **     caller_freef -- caller-provided memory release function
04314 **
04315 **  Return value:
04316 **     A new DKIM_LIB handle suitable for use with other DKIM functions, or
04317 **     NULL on failure.
04318 **
04319 **  Side effects:
04320 **     Crop circles near Birmingham.
04321 */
04322 
04323 DKIM_LIB *
04324 dkim_init(void *(*caller_mallocf)(void *closure, size_t nbytes),
04325           void (*caller_freef)(void *closure, void *p))
04326 {
04327        u_char *td;
04328        DKIM_LIB *libhandle;
04329 
04330 #ifndef USE_GNUTLS
04331        /* initialize OpenSSL algorithms */
04332        dkim_init_openssl();
04333 #endif /* USE_GNUTLS */
04334 
04335        /* copy the parameters */
04336        libhandle = (DKIM_LIB *) malloc(sizeof(struct dkim_lib));
04337        if (libhandle == NULL)
04338               return NULL;
04339 
04340        td = (u_char *) getenv("DKIM_TMPDIR");
04341        if (td == NULL || td[0] == '\0')
04342               td = (u_char *) DEFTMPDIR;
04343 
04344        libhandle->dkiml_signre = FALSE;
04345        libhandle->dkiml_skipre = FALSE;
04346        libhandle->dkiml_malloc = caller_mallocf;
04347        libhandle->dkiml_free = caller_freef;
04348        strlcpy((char *) libhandle->dkiml_tmpdir, (char *) td, 
04349                sizeof libhandle->dkiml_tmpdir);
04350        libhandle->dkiml_flags = DKIM_LIBFLAGS_DEFAULT;
04351        libhandle->dkiml_timeout = DEFTIMEOUT;
04352        libhandle->dkiml_senderhdrs = (u_char **) dkim_default_senderhdrs;
04353        libhandle->dkiml_alwayshdrs = NULL;
04354 #ifdef _FFR_OVERSIGN
04355        libhandle->dkiml_oversignhdrs = NULL;
04356 #endif /* _FFR_OVERSIGN */
04357        libhandle->dkiml_nalwayshdrs = 0;
04358        libhandle->dkiml_mbs = NULL;
04359        libhandle->dkiml_querymethod = DKIM_QUERY_UNKNOWN;
04360        memset(libhandle->dkiml_queryinfo, '\0',
04361               sizeof libhandle->dkiml_queryinfo);
04362 #ifdef QUERY_CACHE
04363        libhandle->dkiml_cache = NULL;
04364 #endif /* QUERY_CACHE */
04365        libhandle->dkiml_fixedtime = 0;
04366        libhandle->dkiml_sigttl = 0;
04367        libhandle->dkiml_clockdrift = DEFCLOCKDRIFT;
04368 
04369        libhandle->dkiml_key_lookup = NULL;
04370        libhandle->dkiml_policy_lookup = NULL;
04371        libhandle->dkiml_sig_handle = NULL;
04372        libhandle->dkiml_sig_handle_free = NULL;
04373        libhandle->dkiml_sig_tagvalues = NULL;
04374        libhandle->dkiml_prescreen = NULL;
04375        libhandle->dkiml_final = NULL;
04376        libhandle->dkiml_dns_callback = NULL;
04377        libhandle->dkiml_dns_start = dkim_res_query;
04378        libhandle->dkiml_dns_cancel = dkim_res_cancel;
04379        libhandle->dkiml_dns_waitreply = dkim_res_waitreply;
04380        
04381 #define FEATURE_INDEX(x)    ((x) / (8 * sizeof(u_int)))
04382 #define FEATURE_OFFSET(x)   ((x) % (8 * sizeof(u_int)))
04383 #define FEATURE_ADD(lib,x)  (lib)->dkiml_flist[FEATURE_INDEX((x))] |= (1 << FEATURE_OFFSET(x))
04384 
04385        libhandle->dkiml_flsize = (FEATURE_INDEX(DKIM_FEATURE_MAX)) + 1;
04386        libhandle->dkiml_flist = (u_int *) malloc(sizeof(u_int) * libhandle->dkiml_flsize);
04387        if (libhandle->dkiml_flist == NULL)
04388        {
04389               free(libhandle);
04390               return NULL;
04391        }
04392        memset(libhandle->dkiml_flist, '\0',
04393               sizeof(u_int) * libhandle->dkiml_flsize);
04394 
04395 #ifdef _FFR_DIFFHEADERS
04396        FEATURE_ADD(libhandle, DKIM_FEATURE_DIFFHEADERS);
04397 #endif /* _FFR_DIFFHEADERS */
04398 #ifdef QUERY_CACHE
04399        FEATURE_ADD(libhandle, DKIM_FEATURE_QUERY_CACHE);
04400 #endif /* QUERY_CACHE */
04401 #ifdef HAVE_SHA256
04402        FEATURE_ADD(libhandle, DKIM_FEATURE_SHA256);
04403 #endif /* HAVE_SHA256 */
04404 #ifdef _FFR_DNSSEC
04405        FEATURE_ADD(libhandle, DKIM_FEATURE_DNSSEC);
04406 #endif /* _FFR_DNSSEC */
04407 #ifdef _FFR_RESIGN
04408        FEATURE_ADD(libhandle, DKIM_FEATURE_RESIGN);
04409 #endif /* _FFR_RESIGN */
04410 #ifdef _FFR_ATPS
04411        FEATURE_ADD(libhandle, DKIM_FEATURE_ATPS);
04412 #endif /* _FFR_ATPS */
04413 #ifdef _FFR_OVERSIGN
04414        FEATURE_ADD(libhandle, DKIM_FEATURE_OVERSIGN);
04415 #endif /* _FFR_OVERSIGN */
04416        FEATURE_ADD(libhandle, DKIM_FEATURE_XTAGS);
04417 #ifdef _FFR_DKIM_REPUTATION
04418        FEATURE_ADD(libhandle, DKIM_FEATURE_DKIM_REPUTATION);
04419 #endif /* _FFR_DKIM_REPUTATION */
04420 
04421        /* initialize the resolver */
04422        (void) res_init();
04423 
04424        return libhandle;
04425 }
04426 
04427 /*
04428 **  DKIM_CLOSE -- shut down a DKIM library package
04429 **
04430 **  Parameters:
04431 **     lib -- library handle to shut down
04432 **
04433 **  Return value:
04434 **     None.
04435 */
04436 
04437 void
04438 dkim_close(DKIM_LIB *lib)
04439 {
04440        assert(lib != NULL);
04441 
04442 #ifdef QUERY_CACHE
04443        if (lib->dkiml_cache != NULL)
04444               (void) dkim_cache_close(lib->dkiml_cache);
04445 #endif /* QUERY_CACHE */
04446 
04447        if (lib->dkiml_skipre)
04448               (void) regfree(&lib->dkiml_skiphdrre);
04449        
04450        if (lib->dkiml_signre)
04451               (void) regfree(&lib->dkiml_hdrre);
04452 
04453 
04454 #ifdef _FFR_OVERSIGN
04455        if (lib->dkiml_oversignhdrs != NULL)
04456               dkim_clobber_array((char **) lib->dkiml_oversignhdrs);
04457 #endif /* _FFR_OVERSIGN */
04458 
04459        if (lib->dkiml_senderhdrs != (u_char **) dkim_default_senderhdrs)
04460               dkim_clobber_array((char **) lib->dkiml_senderhdrs);
04461 
04462        if (lib->dkiml_alwayshdrs != NULL)
04463               dkim_clobber_array((char **) lib->dkiml_alwayshdrs);
04464 
04465        if (lib->dkiml_mbs != NULL)
04466               dkim_clobber_array((char **) lib->dkiml_mbs);
04467 
04468        free(lib->dkiml_flist);
04469        
04470        free((void *) lib);
04471 
04472 #ifndef USE_GNUTLS
04473        dkim_close_openssl();
04474 #endif /* ! USE_GNUTLS */
04475 }
04476 
04477 /*
04478 **  DKIM_ERROR -- log an error into a DKIM handle
04479 **
04480 **  Parameters:
04481 **     dkim -- DKIM context in which this is performed
04482 **     format -- format to apply
04483 **     ... -- arguments
04484 **
04485 **  Return value:
04486 **     None.
04487 */
04488 
04489 void
04490 dkim_error(DKIM *dkim, const char *format, ...)
04491 {
04492        int flen;
04493        int saverr;
04494        u_char *new;
04495        va_list va;
04496 
04497        assert(dkim != NULL);
04498        assert(format != NULL);
04499 
04500        saverr = errno;
04501 
04502        if (dkim->dkim_error == NULL)
04503        {
04504               dkim->dkim_error = DKIM_MALLOC(dkim, DEFERRLEN);
04505               if (dkim->dkim_error == NULL)
04506               {
04507                      errno = saverr;
04508                      return;
04509               }
04510               dkim->dkim_errlen = DEFERRLEN;
04511        }
04512 
04513        for (;;)
04514        {
04515               va_start(va, format);
04516               flen = vsnprintf((char *) dkim->dkim_error, dkim->dkim_errlen,
04517                                format, va);
04518               va_end(va);
04519 
04520               /* compensate for broken vsnprintf() implementations */
04521               if (flen == -1)
04522                      flen = dkim->dkim_errlen * 2;
04523 
04524               if (flen >= dkim->dkim_errlen)
04525               {
04526                      new = DKIM_MALLOC(dkim, flen + 1);
04527                      if (new == NULL)
04528                      {
04529                             errno = saverr;
04530                             return;
04531                      }
04532 
04533                      DKIM_FREE(dkim, dkim->dkim_error);
04534                      dkim->dkim_error = new;
04535                      dkim->dkim_errlen = flen + 1;
04536               }
04537               else
04538               {
04539                      break;
04540               }
04541        }
04542 
04543        errno = saverr;
04544 }
04545 
04546 /*
04547 **  DKIM_OPTIONS -- get or set a library option
04548 **
04549 **  Parameters:
04550 **     lib -- DKIM library handle
04551 **     op -- operation to perform
04552 **     opt -- option to get/set
04553 **     ptr -- pointer to its old/new value
04554 **     len -- memory available at "ptr"
04555 **
04556 **  Return value:
04557 **     A DKIM_STAT constant.
04558 */
04559 
04560 DKIM_STAT
04561 dkim_options(DKIM_LIB *lib, int op, dkim_opts_t opt, void *ptr, size_t len)
04562 {
04563        assert(lib != NULL);
04564        assert(op == DKIM_OP_SETOPT || op == DKIM_OP_GETOPT);
04565        assert(len != 0);
04566 
04567        switch (opt)
04568        {
04569          case DKIM_OPTS_TMPDIR:
04570               if (op == DKIM_OP_GETOPT)
04571               {
04572                      strlcpy((char *) ptr, (char *) lib->dkiml_tmpdir, len);
04573               }
04574               else if (ptr == NULL)
04575               {
04576                      strlcpy((char *) lib->dkiml_tmpdir, DEFTMPDIR,
04577                              sizeof lib->dkiml_tmpdir);
04578               }
04579               else
04580               {
04581                      strlcpy((char *) lib->dkiml_tmpdir, (char *) ptr,
04582                              sizeof lib->dkiml_tmpdir);
04583               }
04584               return DKIM_STAT_OK;
04585 
04586          case DKIM_OPTS_FIXEDTIME:
04587               if (ptr == NULL)
04588                      return DKIM_STAT_INVALID;
04589 
04590               if (len != sizeof lib->dkiml_fixedtime)
04591                      return DKIM_STAT_INVALID;
04592 
04593               if (op == DKIM_OP_GETOPT)
04594               {
04595                      memcpy(ptr, &lib->dkiml_fixedtime, len);
04596               }
04597               else
04598               {
04599                      memcpy(&lib->dkiml_fixedtime, ptr, len);
04600               }
04601               return DKIM_STAT_OK;
04602 
04603          case DKIM_OPTS_SIGNATURETTL:
04604               if (ptr == NULL)
04605                      return DKIM_STAT_INVALID;
04606 
04607               if (len != sizeof lib->dkiml_sigttl)
04608                      return DKIM_STAT_INVALID;
04609 
04610               if (op == DKIM_OP_GETOPT)
04611               {
04612                      memcpy(ptr, &lib->dkiml_sigttl, len);
04613               }
04614               else
04615               {
04616                      memcpy(&lib->dkiml_sigttl, ptr, len);
04617               }
04618               return DKIM_STAT_OK;
04619 
04620          case DKIM_OPTS_CLOCKDRIFT:
04621               if (ptr == NULL)
04622                      return DKIM_STAT_INVALID;
04623 
04624               if (len != sizeof lib->dkiml_clockdrift)
04625                      return DKIM_STAT_INVALID;
04626 
04627               if (op == DKIM_OP_GETOPT)
04628               {
04629                      memcpy(ptr, &lib->dkiml_clockdrift, len);
04630               }
04631               else
04632               {
04633                      memcpy(&lib->dkiml_clockdrift, ptr, len);
04634               }
04635               return DKIM_STAT_OK;
04636 
04637          case DKIM_OPTS_FLAGS:
04638               if (ptr == NULL)
04639                      return DKIM_STAT_INVALID;
04640 
04641               if (len != sizeof lib->dkiml_flags)
04642                      return DKIM_STAT_INVALID;
04643 
04644               if (op == DKIM_OP_GETOPT)
04645               {
04646                      memcpy(ptr, &lib->dkiml_flags, len);
04647               }
04648               else
04649               {
04650                      memcpy(&lib->dkiml_flags, ptr, len);
04651               }
04652               return DKIM_STAT_OK;
04653 
04654          case DKIM_OPTS_TIMEOUT:
04655               if (ptr == NULL)
04656                      return DKIM_STAT_INVALID;
04657 
04658               if (len != sizeof lib->dkiml_timeout)
04659                      return DKIM_STAT_INVALID;
04660 
04661               if (op == DKIM_OP_GETOPT)
04662               {
04663                      memcpy(ptr, &lib->dkiml_timeout, len);
04664               }
04665               else
04666               {
04667                      memcpy(&lib->dkiml_timeout, ptr, len);
04668               }
04669               return DKIM_STAT_OK;
04670 
04671          case DKIM_OPTS_SENDERHDRS:
04672               if (len != sizeof lib->dkiml_senderhdrs)
04673                      return DKIM_STAT_INVALID;
04674 
04675               if (op == DKIM_OP_GETOPT)
04676               {
04677                      memcpy(ptr, &lib->dkiml_senderhdrs, len);
04678               }
04679               else if (ptr == NULL)
04680               {
04681                      if (lib->dkiml_senderhdrs != (u_char **) dkim_default_senderhdrs)
04682                             dkim_clobber_array((char **) lib->dkiml_senderhdrs);
04683 
04684                      lib->dkiml_senderhdrs = (u_char **) dkim_default_senderhdrs;
04685               }
04686               else
04687               {
04688                      const char **tmp;
04689 
04690                      tmp = dkim_copy_array(ptr);
04691                      if (tmp == NULL)
04692                             return DKIM_STAT_NORESOURCE;
04693 
04694                      if (lib->dkiml_senderhdrs != (u_char **) dkim_default_senderhdrs)
04695                             dkim_clobber_array((char **) lib->dkiml_senderhdrs);
04696 
04697                      lib->dkiml_senderhdrs = (u_char **) tmp;
04698               }
04699               return DKIM_STAT_OK;
04700 
04701 #ifdef _FFR_OVERSIGN
04702          case DKIM_OPTS_OVERSIGNHDRS:
04703               if (len != sizeof lib->dkiml_oversignhdrs)
04704                      return DKIM_STAT_INVALID;
04705 
04706               if (op == DKIM_OP_GETOPT)
04707               {
04708                      memcpy(ptr, &lib->dkiml_oversignhdrs, len);
04709               }
04710               else
04711               {
04712                      const char **tmp;
04713 
04714                      tmp = dkim_copy_array(ptr);
04715                      if (tmp == NULL)
04716                             return DKIM_STAT_NORESOURCE;
04717 
04718                      if (lib->dkiml_oversignhdrs != NULL)
04719                             dkim_clobber_array((char **) lib->dkiml_oversignhdrs);
04720 
04721                      lib->dkiml_oversignhdrs = (u_char **) tmp;
04722               }
04723               return DKIM_STAT_OK;
04724 #endif /* _FFR_OVERSIGN */
04725 
04726          case DKIM_OPTS_ALWAYSHDRS:
04727               if (len != sizeof lib->dkiml_alwayshdrs)
04728                      return DKIM_STAT_INVALID;
04729 
04730               if (op == DKIM_OP_GETOPT)
04731               {
04732                      memcpy(ptr, &lib->dkiml_alwayshdrs, len);
04733               }
04734               else if (ptr == NULL)
04735               {
04736                      if (lib->dkiml_alwayshdrs != NULL)
04737                             dkim_clobber_array((char **) lib->dkiml_alwayshdrs);
04738 
04739                      lib->dkiml_alwayshdrs = NULL;
04740                      lib->dkiml_nalwayshdrs = 0;
04741               }
04742               else
04743               {
04744                      u_int n;
04745                      const char **tmp;
04746 
04747                      tmp = dkim_copy_array(ptr);
04748                      if (tmp == NULL)
04749                             return DKIM_STAT_NORESOURCE;
04750 
04751                      if (lib->dkiml_alwayshdrs != NULL)
04752                             dkim_clobber_array((char **) lib->dkiml_alwayshdrs);
04753 
04754                      lib->dkiml_alwayshdrs = (u_char **) tmp;
04755                      for (n = 0; lib->dkiml_alwayshdrs[n] != NULL; n++)
04756                             continue;
04757                      lib->dkiml_nalwayshdrs = n;
04758               }
04759               return DKIM_STAT_OK;
04760 
04761          case DKIM_OPTS_MUSTBESIGNED:
04762               if (len != sizeof lib->dkiml_mbs)
04763                      return DKIM_STAT_INVALID;
04764 
04765               if (op == DKIM_OP_GETOPT)
04766               {
04767                      memcpy(ptr, &lib->dkiml_mbs, len);
04768               }
04769               else if (ptr == NULL)
04770               {
04771                      lib->dkiml_mbs = NULL;
04772               }
04773               else
04774               {
04775                      const char **tmp;
04776 
04777                      tmp = dkim_copy_array(ptr);
04778                      if (tmp == NULL)
04779                             return DKIM_STAT_NORESOURCE;
04780 
04781                      if (lib->dkiml_mbs != NULL)
04782                             dkim_clobber_array((char **) lib->dkiml_mbs);
04783 
04784                      lib->dkiml_mbs = (u_char **) tmp;
04785               }
04786               return DKIM_STAT_OK;
04787 
04788          case DKIM_OPTS_SIGNHDRS:
04789               if (len != sizeof(char **) || op == DKIM_OP_GETOPT)
04790               {
04791                      return DKIM_STAT_INVALID;
04792               }
04793               else if (ptr == NULL)
04794               {
04795                      if (lib->dkiml_signre)
04796                      {
04797                             (void) regfree(&lib->dkiml_hdrre);
04798                             lib->dkiml_signre = FALSE;
04799                      }
04800               }
04801               else
04802               {
04803                      int status;
04804                      u_char **hdrs;
04805                      char buf[BUFRSZ + 1];
04806 
04807                      if (lib->dkiml_signre)
04808                      {
04809                             (void) regfree(&lib->dkiml_hdrre);
04810                             lib->dkiml_signre = FALSE;
04811                      }
04812 
04813                      memset(buf, '\0', sizeof buf);
04814 
04815                      hdrs = (u_char **) ptr;
04816 
04817                      (void) strlcpy(buf, "^(", sizeof buf);
04818 
04819                      if (!dkim_hdrlist((u_char *) buf, sizeof buf,
04820                                        (u_char **) required_signhdrs, TRUE))
04821                             return DKIM_STAT_INVALID;
04822                      if (!dkim_hdrlist((u_char *) buf, sizeof buf,
04823                                        hdrs, FALSE))
04824                             return DKIM_STAT_INVALID;
04825 
04826                      if (strlcat(buf, ")$", sizeof buf) >= sizeof buf)
04827                             return DKIM_STAT_INVALID;
04828 
04829                      status = regcomp(&lib->dkiml_hdrre, buf,
04830                                       (REG_EXTENDED|REG_ICASE));
04831                      if (status != 0)
04832                             return DKIM_STAT_INTERNAL;
04833 
04834                      lib->dkiml_signre = TRUE;
04835               }
04836               return DKIM_STAT_OK;
04837 
04838          case DKIM_OPTS_SKIPHDRS:
04839               if (len != sizeof(char **) || op == DKIM_OP_GETOPT)
04840               {
04841                      return DKIM_STAT_INVALID;
04842               }
04843               else if (ptr == NULL)
04844               {
04845                      if (lib->dkiml_skipre)
04846                      {
04847                             (void) regfree(&lib->dkiml_skiphdrre);
04848                             lib->dkiml_skipre = FALSE;
04849                      }
04850               }
04851               else
04852               {
04853                      int status;
04854                      u_char **hdrs;
04855                      char buf[BUFRSZ + 1];
04856 
04857                      if (lib->dkiml_skipre)
04858                      {
04859                             (void) regfree(&lib->dkiml_skiphdrre);
04860                             lib->dkiml_skipre = FALSE;
04861                      }
04862 
04863                      memset(buf, '\0', sizeof buf);
04864 
04865                      hdrs = (u_char **) ptr;
04866 
04867                      (void) strlcpy(buf, "^(", sizeof buf);
04868 
04869                      if (!dkim_hdrlist((u_char *) buf, sizeof buf,
04870                                        hdrs, TRUE))
04871                             return DKIM_STAT_INVALID;
04872 
04873                      if (strlcat(buf, ")$", sizeof buf) >= sizeof buf)
04874                             return DKIM_STAT_INVALID;
04875 
04876                      status = regcomp(&lib->dkiml_skiphdrre, buf,
04877                                       (REG_EXTENDED|REG_ICASE));
04878                      if (status != 0)
04879                             return DKIM_STAT_INTERNAL;
04880 
04881                      lib->dkiml_skipre = TRUE;
04882               }
04883               return DKIM_STAT_OK;
04884 
04885          case DKIM_OPTS_QUERYMETHOD:
04886               if (ptr == NULL)
04887                      return DKIM_STAT_INVALID;
04888 
04889               if (len != sizeof lib->dkiml_querymethod)
04890                      return DKIM_STAT_INVALID;
04891 
04892               if (op == DKIM_OP_GETOPT)
04893               {
04894                      memcpy(ptr, &lib->dkiml_querymethod, len);
04895               }
04896               else
04897               {
04898                      memcpy(&lib->dkiml_querymethod, ptr, len);
04899               }
04900               return DKIM_STAT_OK;
04901 
04902          case DKIM_OPTS_QUERYINFO:
04903               if (ptr == NULL)
04904                      return DKIM_STAT_INVALID;
04905 
04906               if (op == DKIM_OP_GETOPT)
04907               {
04908                      strlcpy(ptr, (char *) lib->dkiml_queryinfo, len);
04909               }
04910               else
04911               {
04912                      strlcpy((char *) lib->dkiml_queryinfo, ptr,
04913                              sizeof lib->dkiml_queryinfo);
04914               }
04915               return DKIM_STAT_OK;
04916 
04917          default:
04918               return DKIM_STAT_INVALID;
04919        }
04920 }
04921 
04922 /*
04923 **  DKIM_FREE -- destroy a DKIM handle
04924 **
04925 **  Parameters:
04926 **     dkim -- DKIM handle to destroy
04927 **
04928 **  Return value:
04929 **     A DKIM_STAT constant.
04930 */
04931 
04932 DKIM_STAT
04933 dkim_free(DKIM *dkim)
04934 {
04935        assert(dkim != NULL);
04936 
04937 #ifdef _FFR_RESIGN
04938        /* XXX -- this should be mutex-protected */
04939        if (dkim->dkim_resign != NULL)
04940        {
04941               if (dkim->dkim_resign->dkim_refcnt == 0)
04942                      dkim_free(dkim->dkim_resign);
04943               else
04944                      dkim->dkim_resign->dkim_refcnt--;
04945        }
04946        else if (dkim->dkim_refcnt != 0)
04947        {
04948               return DKIM_STAT_INVALID;
04949        }
04950 #endif /* _FFR_RESIGN */
04951 
04952        /* blast the headers */
04953 #ifdef _FFR_RESIGN
04954        if (dkim->dkim_resign == NULL && dkim->dkim_hhead != NULL)
04955 #else /* _FFR_RESIGN */
04956        if (dkim->dkim_hhead != NULL)
04957 #endif /* _FFR_RESIGN */
04958        {
04959               struct dkim_header *next;
04960               struct dkim_header *hdr;
04961 
04962               for (hdr = dkim->dkim_hhead; hdr != NULL; )
04963               {
04964                      next = hdr->hdr_next;
04965 
04966                      CLOBBER(hdr->hdr_text);
04967                      CLOBBER(hdr);
04968 
04969                      hdr = next;
04970               }
04971        }
04972 
04973        /* blast the data sets */
04974 #ifdef _FFR_RESIGN
04975        if (dkim->dkim_resign == NULL && dkim->dkim_sethead != NULL)
04976 #else /* _FFR_RESIGN */
04977        if (dkim->dkim_sethead != NULL)
04978 #endif /* _FFR_RESIGN */
04979        {
04980               DKIM_SET *set;
04981               DKIM_SET *next;
04982 
04983               for (set = dkim->dkim_sethead; set != NULL; )
04984               {
04985                      next = set->set_next;
04986 
04987                      dkim_set_free(dkim, set);
04988 
04989                      set = next;
04990               }
04991        }
04992 
04993        /* trash the signature list */
04994        if (dkim->dkim_siglist != NULL)
04995        {
04996               int c;
04997 
04998               for (c = 0; c < dkim->dkim_sigcount; c++)
04999               {
05000                      if (dkim->dkim_siglist[c]->sig_context != NULL &&
05001                          dkim->dkim_libhandle->dkiml_sig_handle_free != NULL)
05002                      {
05003                             dkim->dkim_libhandle->dkiml_sig_handle_free(dkim->dkim_closure,
05004                                                                         dkim->dkim_siglist[c]->sig_context);
05005                      }
05006 
05007                      CLOBBER(dkim->dkim_siglist[c]->sig_key);
05008                      CLOBBER(dkim->dkim_siglist[c]->sig_sig);
05009                      if (dkim->dkim_siglist[c]->sig_keytype == DKIM_KEYTYPE_RSA)
05010                      {
05011                             struct dkim_rsa *rsa;
05012 
05013                             rsa = dkim->dkim_siglist[c]->sig_signature;
05014                             if (rsa != NULL)
05015                             {
05016 #ifdef USE_GNUTLS
05017                                    KEY_CLOBBER(rsa->rsa_key);
05018                                    PUBKEY_CLOBBER(rsa->rsa_pubkey);
05019                                    PRIVKEY_CLOBBER(rsa->rsa_privkey);
05020                                    HCLOBBER(rsa->rsa_rsaout.data);
05021 #else /* USE_GNUTLS */
05022                                    BIO_CLOBBER(rsa->rsa_keydata);
05023                                    EVP_CLOBBER(rsa->rsa_pkey);
05024                                    RSA_CLOBBER(rsa->rsa_rsa);
05025                                    CLOBBER(rsa->rsa_rsaout);
05026 #endif /* USE_GNUTLS */
05027                             }
05028                      }
05029                      CLOBBER(dkim->dkim_siglist[c]->sig_signature);
05030                      CLOBBER(dkim->dkim_siglist[c]);
05031               }
05032 
05033               CLOBBER(dkim->dkim_siglist);
05034        }
05035 
05036        if (dkim->dkim_xtags != NULL)
05037        {
05038               struct dkim_xtag *cur;
05039               struct dkim_xtag *next;
05040 
05041               cur = dkim->dkim_xtags;
05042               while (cur != NULL)
05043               {
05044                      next = cur->xt_next;
05045                      free(cur);
05046                      cur = next;
05047               }
05048        }
05049 
05050        /* destroy canonicalizations */
05051        dkim_canon_cleanup(dkim);
05052 
05053        CLOBBER(dkim->dkim_b64sig);
05054        CLOBBER(dkim->dkim_selector);
05055        CLOBBER(dkim->dkim_domain);
05056        CLOBBER(dkim->dkim_user);
05057        CLOBBER(dkim->dkim_key);
05058        CLOBBER(dkim->dkim_sender);
05059        CLOBBER(dkim->dkim_signer);
05060        CLOBBER(dkim->dkim_error);
05061        CLOBBER(dkim->dkim_zdecode);
05062        CLOBBER(dkim->dkim_hdrlist);
05063 
05064        DSTRING_CLOBBER(dkim->dkim_hdrbuf);
05065        DSTRING_CLOBBER(dkim->dkim_canonbuf);
05066 
05067        dkim_mfree(dkim->dkim_libhandle, dkim->dkim_closure, dkim);
05068 
05069        return DKIM_STAT_OK;
05070 }
05071 
05072 /*
05073 **  DKIM_SIGN -- allocate a handle for use in a signature operation
05074 **
05075 **  Parameters:
05076 **     libhandle -- DKIM_LIB handle
05077 **     id -- identification string (e.g. job ID) for logging
05078 **     memclosure -- memory closure for allocations (or NULL)
05079 **     secretkey -- secret key (PEM format)
05080 **     selector -- selector to be used when generating the signature header
05081 **     domain -- domain for which this message is being signed
05082 **     hdrcanonalg -- canonicalization algorithm to use for headers
05083 **     bodycanonalg -- canonicalization algorithm to use for body
05084 **     signalg -- signing algorithm to use
05085 **     length -- how many bytes of the body to sign (-1 for all)
05086 **     statp -- status (returned)
05087 **
05088 **  Return value:
05089 **     A new signing handle, or NULL.
05090 */
05091 
05092 DKIM *
05093 dkim_sign(DKIM_LIB *libhandle, const unsigned char *id, void *memclosure,
05094           const dkim_sigkey_t secretkey, const unsigned char *selector,
05095           const unsigned char *domain, dkim_canon_t hdrcanonalg,
05096          dkim_canon_t bodycanonalg, dkim_alg_t signalg,
05097           ssize_t length, DKIM_STAT *statp)
05098 {
05099        DKIM *new;
05100 
05101        assert(libhandle != NULL);
05102        assert(secretkey != NULL);
05103        assert(selector != NULL);
05104        assert(domain != NULL);
05105        assert(hdrcanonalg == DKIM_CANON_SIMPLE ||
05106               hdrcanonalg == DKIM_CANON_RELAXED);
05107        assert(bodycanonalg == DKIM_CANON_SIMPLE ||
05108               bodycanonalg == DKIM_CANON_RELAXED);
05109        assert(signalg == DKIM_SIGN_DEFAULT ||
05110               signalg == DKIM_SIGN_RSASHA1 || signalg == DKIM_SIGN_RSASHA256);
05111        assert(statp != NULL);
05112 
05113        if (dkim_libfeature(libhandle, DKIM_FEATURE_SHA256))
05114        {
05115               if (signalg == DKIM_SIGN_DEFAULT)
05116                      signalg = DKIM_SIGN_RSASHA256;
05117        }
05118        else
05119        {
05120               if (signalg == DKIM_SIGN_RSASHA256)
05121               {
05122                      *statp = DKIM_STAT_INVALID;
05123                      return NULL;
05124               }
05125 
05126               if (signalg == DKIM_SIGN_DEFAULT)
05127                      signalg = DKIM_SIGN_RSASHA1;
05128        }
05129 
05130        new = dkim_new(libhandle, id, memclosure, hdrcanonalg, bodycanonalg,
05131                       signalg, statp);
05132 
05133        if (new != NULL)
05134        {
05135               new->dkim_mode = DKIM_MODE_SIGN;
05136 
05137               /* do DER decoding here if needed */
05138               if (strncmp((char *) secretkey, "MII", 3) == 0)
05139               {
05140                      size_t b64len;
05141 
05142                      b64len = strlen((char *) secretkey);
05143 
05144                      new->dkim_key = (unsigned char *) DKIM_MALLOC(new,
05145                                                                    b64len);
05146                      if (new->dkim_key == NULL)
05147                      {
05148                             *statp = DKIM_STAT_NORESOURCE;
05149                             dkim_free(new);
05150                             return NULL;
05151                      }
05152 
05153                      new->dkim_keylen = dkim_base64_decode(secretkey,
05154                                                            new->dkim_key,
05155                                                            b64len);
05156                      if (new->dkim_keylen <= 0)
05157                      {
05158                             *statp = DKIM_STAT_NORESOURCE;
05159                             dkim_free(new);
05160                             return NULL;
05161                      }
05162               }
05163               else
05164               {
05165                      new->dkim_keylen = strlen((const char *) secretkey);
05166                      new->dkim_key = dkim_strdup(new, secretkey, 0);
05167 
05168                      if (new->dkim_key == NULL)
05169                      {
05170                             *statp = DKIM_STAT_NORESOURCE;
05171                             dkim_free(new);
05172                             return NULL;
05173                      }
05174               }
05175 
05176               new->dkim_selector = dkim_strdup(new, selector, 0);
05177               new->dkim_domain = dkim_strdup(new, domain, 0);
05178               if (length == (ssize_t) -1)
05179                      new->dkim_signlen = ULONG_MAX;
05180               else
05181                      new->dkim_signlen = length;
05182        }
05183 
05184        return new;
05185 }
05186 
05187 /*
05188 **  DKIM_VERIFY -- allocate a handle for use in a verify operation
05189 **
05190 **  Parameters:
05191 **     libhandle -- DKIM_LIB handle
05192 **     id -- identification string (e.g. job ID) for logging
05193 **     memclosure -- memory closure for allocations (or NULL)
05194 **     statp -- status (returned)
05195 **
05196 **  Return value:
05197 **     A new signing handle, or NULL.
05198 */
05199 
05200 DKIM *
05201 dkim_verify(DKIM_LIB *libhandle, const unsigned char *id, void *memclosure,
05202             DKIM_STAT *statp)
05203 {
05204        DKIM *new;
05205 
05206        assert(libhandle != NULL);
05207        assert(statp != NULL);
05208 
05209        new = dkim_new(libhandle, id, memclosure, DKIM_CANON_UNKNOWN,
05210                       DKIM_CANON_UNKNOWN, DKIM_SIGN_UNKNOWN, statp);
05211 
05212        if (new != NULL)
05213               new->dkim_mode = DKIM_MODE_VERIFY;
05214 
05215        return new;
05216 }
05217 
05218 /*
05219 **  DKIM_RESIGN -- bind a new signing handle to a completed handle
05220 **
05221 **  Parameters:
05222 **     new -- new signing handle
05223 **     old -- old signing/verifying handle
05224 **     hdrbind -- bind "new"'s header canonicalization to "old" as well
05225 **                as the body
05226 **
05227 **  Return value:
05228 **     DKIM_STAT_OK -- success
05229 **     DKIM_STAT_INVALID -- invalid state of one or both handles
05230 **
05231 **  Side effects:
05232 **     Sets up flags such that the two are bound; dkim_free() on "old"
05233 **     is now an invalid operation until "new" has been free'd.
05234 */
05235 
05236 DKIM_STAT
05237 dkim_resign(DKIM *new, DKIM *old, _Bool hdrbind)
05238 {
05239 #ifdef _FFR_RESIGN
05240        _Bool keep;
05241        _Bool tmp;
05242        DKIM_STAT status;
05243        int hashtype = DKIM_HASHTYPE_UNKNOWN;
05244        DKIM_CANON *bc;
05245        DKIM_CANON *hc;
05246        DKIM_LIB *lib;
05247 
05248        assert(new != NULL);
05249        assert(old != NULL);
05250 
05251        if (new->dkim_mode != DKIM_MODE_SIGN ||
05252            new->dkim_state != DKIM_STATE_INIT)
05253               return DKIM_STAT_INVALID;
05254 
05255        if (old->dkim_mode != DKIM_MODE_VERIFY ||
05256            old->dkim_state >= DKIM_STATE_EOH1 ||
05257            old->dkim_resign != NULL)
05258               return DKIM_STAT_INVALID;
05259 
05260        new->dkim_resign = old;
05261        new->dkim_hdrbind = hdrbind;
05262        /* XXX -- should be mutex-protected? */
05263        old->dkim_refcnt++;
05264 
05265        lib = old->dkim_libhandle;
05266        assert(lib != NULL);
05267 
05268        tmp = ((lib->dkiml_flags & DKIM_LIBFLAGS_TMPFILES) != 0);
05269        keep = ((lib->dkiml_flags & DKIM_LIBFLAGS_KEEPFILES) != 0);
05270 
05271        new->dkim_version = lib->dkiml_version;
05272 
05273        /* determine hash type */
05274        switch (new->dkim_signalg)
05275        {
05276          case DKIM_SIGN_RSASHA1:
05277               hashtype = DKIM_HASHTYPE_SHA1;
05278               break;
05279 
05280          case DKIM_SIGN_RSASHA256:
05281               hashtype = DKIM_HASHTYPE_SHA256;
05282               break;
05283 
05284          default:
05285               assert(0);
05286               /* NOTREACHED */
05287        }
05288 
05289        /* initialize signature and canonicalization for signing */
05290        new->dkim_siglist = DKIM_MALLOC(new, sizeof(DKIM_SIGINFO *));
05291        if (new->dkim_siglist == NULL)
05292        {
05293               dkim_error(new, "failed to allocate %d byte(s)",
05294                          sizeof(DKIM_SIGINFO *));
05295               return DKIM_STAT_NORESOURCE;
05296        }
05297 
05298        new->dkim_siglist[0] = DKIM_MALLOC(new, sizeof(struct dkim_siginfo));
05299        if (new->dkim_siglist[0] == NULL)
05300        {
05301               dkim_error(new, "failed to allocate %d byte(s)",
05302                          sizeof(struct dkim_siginfo));
05303               return DKIM_STAT_NORESOURCE;
05304        }
05305 
05306        new->dkim_sigcount = 1;
05307        memset(new->dkim_siglist[0], '\0', sizeof(struct dkim_siginfo));
05308        new->dkim_siglist[0]->sig_domain = new->dkim_domain;
05309        new->dkim_siglist[0]->sig_selector = new->dkim_selector;
05310        new->dkim_siglist[0]->sig_hashtype = hashtype;
05311        new->dkim_siglist[0]->sig_signalg = new->dkim_signalg;
05312 
05313        status = dkim_add_canon(hdrbind ? old : new, TRUE,
05314                                new->dkim_hdrcanonalg, hashtype,
05315                                NULL, NULL, 0, &hc);
05316        if (status != DKIM_STAT_OK)
05317               return status;
05318 
05319        status = dkim_add_canon(old, FALSE, new->dkim_bodycanonalg,
05320                                hashtype, NULL, NULL, new->dkim_signlen, &bc);
05321        if (status != DKIM_STAT_OK)
05322               return status;
05323 
05324        new->dkim_siglist[0]->sig_hdrcanon = hc;
05325        new->dkim_siglist[0]->sig_hdrcanonalg = new->dkim_hdrcanonalg;
05326        new->dkim_siglist[0]->sig_bodycanon = bc;
05327        new->dkim_siglist[0]->sig_bodycanonalg = new->dkim_bodycanonalg;
05328 
05329        if (new->dkim_libhandle->dkiml_fixedtime != 0)
05330        {
05331               new->dkim_siglist[0]->sig_timestamp = new->dkim_libhandle->dkiml_fixedtime;
05332        }
05333        else
05334        {
05335               time_t now;
05336 
05337               (void) time(&now);
05338 
05339               new->dkim_siglist[0]->sig_timestamp = (uint64_t) now;
05340        }
05341 
05342        return DKIM_STAT_OK;
05343 #else /* _FFR_RESIGN */
05344        return DKIM_STAT_NOTIMPLEMENT;
05345 #endif /* _FFR_RESIGN */
05346 }
05347 
05348 /*
05349 **  DKIM_POLICY_STATE_NEW -- initialize and return a DKIM policy state handle
05350 **
05351 **  Parameters:
05352 **     dkim -- DKIM handle from which to do an allocation
05353 **
05354 **  Return value:
05355 **     A DKIM_PSTATE handle, or NULL on failure.
05356 */
05357 
05358 DKIM_PSTATE *
05359 dkim_policy_state_new(DKIM *dkim)
05360 {
05361        DKIM_PSTATE *ret;
05362 
05363        assert(dkim != NULL);
05364 
05365        ret = DKIM_MALLOC(dkim, sizeof(DKIM_PSTATE));
05366 
05367        if (ret != NULL)
05368        {
05369               memset(ret, '\0', sizeof(DKIM_PSTATE));
05370               ret->ps_dkim = dkim;
05371        }
05372 
05373        return ret;
05374 }
05375 
05376 /*
05377 **  DKIM_POLICY_STATE_FREE -- destroy a DKIM policy state handle
05378 **
05379 **  Parameters:
05380 **     pstate -- previously allocated policy state handle
05381 **
05382 **  Return value:
05383 **     None.
05384 */
05385 
05386 void
05387 dkim_policy_state_free(DKIM_PSTATE *pstate)
05388 {
05389        assert(pstate != NULL);
05390 
05391        DKIM_FREE(pstate->ps_dkim, pstate);
05392 }
05393 
05394 /*
05395 **  DKIM_POLICY -- parse policy associated with the sender's domain
05396 **
05397 **  Parameters:
05398 **     dkim -- DKIM handle
05399 **     pcode -- discovered policy (returned)
05400 **     pflags -- discovered policy flags (returned)
05401 **     pstate -- state, for re-entrancy (updated; can be NULL)
05402 **
05403 **  Return value:
05404 **     A DKIM_STAT_* constant.
05405 */
05406 
05407 DKIM_STAT
05408 dkim_policy(DKIM *dkim, dkim_policy_t *pcode, u_int *pflags,
05409             DKIM_PSTATE *pstate)
05410 {
05411        int wlen;
05412        int qstatus = NOERROR;
05413        unsigned int lpflags;
05414        DKIM_STAT status;
05415        dkim_policy_t policy = DKIM_POLICY_NONE;
05416        unsigned char query[DKIM_MAXHOSTNAMELEN + 1];
05417 
05418        assert(dkim != NULL);
05419 
05420        /* fail for signing handles */
05421        if (dkim->dkim_mode == DKIM_MODE_SIGN)
05422               return DKIM_STAT_INVALID;
05423 
05424        /* fail if no domain could be determined */
05425        if (dkim->dkim_domain == NULL)
05426               return DKIM_STAT_SYNTAX;
05427 
05428        /* initialize */
05429        dkim->dkim_presult = DKIM_PRESULT_NONE;
05430        if (pstate != NULL)
05431        {
05432               qstatus = pstate->ps_qstatus;
05433               policy = pstate->ps_policy;
05434               lpflags = pstate->ps_pflags;
05435        }
05436 
05437        /*
05438        **  Apply RFC5617: Verify domain existence.
05439        */
05440 
05441        if (pstate == NULL || pstate->ps_state < 1)
05442        {
05443               status = dkim_get_policy(dkim, dkim->dkim_domain, TRUE,
05444                                        &qstatus, &policy, &lpflags);
05445               if (status != DKIM_STAT_OK)
05446               {
05447                      if (status == DKIM_STAT_CBTRYAGAIN && pstate != NULL)
05448                      {
05449                             pstate->ps_qstatus = qstatus;
05450                             pstate->ps_policy = policy;
05451                             pstate->ps_pflags = lpflags;
05452                      }
05453 
05454                      return status;
05455               }
05456 
05457               if (pstate != NULL)
05458                      pstate->ps_state = 1;
05459        }
05460 
05461        if (qstatus == NXDOMAIN)
05462        {
05463               dkim->dkim_presult = DKIM_PRESULT_NXDOMAIN;
05464               if (pcode != NULL)
05465                      *pcode = policy;
05466               return DKIM_STAT_OK;
05467        }
05468 
05469        /*
05470        **  Apply RFC5617: Retrieve policy.
05471        */
05472 
05473        if (pstate == NULL || pstate->ps_state < 2)
05474        {
05475               wlen = snprintf((char *) query, sizeof query, "%s.%s.%s",
05476                               DKIM_DNSPOLICYNAME, DKIM_DNSKEYNAME,
05477                               dkim->dkim_domain);
05478               if (wlen >= sizeof query)
05479               {
05480                      dkim_error(dkim, "policy query name overflow");
05481                      return DKIM_STAT_NORESOURCE;
05482               }
05483 
05484               status = dkim_get_policy(dkim, query, FALSE,
05485                                        &qstatus, &policy, &lpflags);
05486               if (status != DKIM_STAT_OK)
05487               {
05488                      if (status == DKIM_STAT_CBTRYAGAIN && pstate != NULL)
05489                      {
05490                             pstate->ps_qstatus = qstatus;
05491                             pstate->ps_policy = policy;
05492                             pstate->ps_pflags = lpflags;
05493                      }
05494 
05495                      return status;
05496               }
05497 
05498               if (pstate != NULL)
05499                      pstate->ps_state = 2;
05500        }
05501 
05502        if (qstatus == NOERROR)
05503               dkim->dkim_presult = DKIM_PRESULT_FOUND;
05504        if (pcode != NULL)
05505               *pcode = policy;
05506        if (pflags != NULL)
05507               *pflags = lpflags;
05508 
05509        return DKIM_STAT_OK;
05510 }
05511 
05512 /*
05513 **  DKIM_POLICY_GETDNSSEC -- retrieve DNSSEC results for a policy
05514 **
05515 **  Parameters:
05516 **     dkim -- DKIM handle
05517 **
05518 **  Return value:
05519 **     A DKIM_DNSSEC_* constant.
05520 */
05521 
05522 int
05523 dkim_policy_getdnssec(DKIM *dkim)
05524 {
05525        assert(dkim != NULL);
05526 
05527        return dkim->dkim_dnssec_policy;
05528 }
05529 
05530 /*
05531 **  DKIM_POLICY_GETREPORTINFO -- retrieve reporting information from policy
05532 **
05533 **  Parameters:
05534 **     dkim -- DKIM handle
05535 **     addr -- address buffer (or NULL)
05536 **     addrlen -- size of addr
05537 **     opts -- options buffer (or NULL)
05538 **     optslen -- size of opts
05539 **     smtp -- SMTP prefix buffer (or NULL)
05540 **     smtplen -- size of smtp
05541 **     pct -- requested report percentage (or NULL)
05542 **
05543 **  Return value:
05544 **     A DKIM_STAT_* constant.
05545 */
05546 
05547 DKIM_STAT
05548 dkim_policy_getreportinfo(DKIM *dkim,
05549                           u_char *addr, size_t addrlen,
05550                           u_char *opts, size_t optslen,
05551                           u_char *smtp, size_t smtplen,
05552                           u_int *pct)
05553 {
05554        u_char *p;
05555        DKIM_SET *set;
05556 
05557        assert(dkim != NULL);
05558 
05559        if (dkim->dkim_state != DKIM_STATE_EOM2 ||
05560            dkim->dkim_mode != DKIM_MODE_VERIFY)
05561               return DKIM_STAT_INVALID;
05562 
05563        set = dkim_set_first(dkim, DKIM_SETTYPE_POLICY);
05564        if (set == NULL)
05565               return DKIM_STAT_CANTVRFY;
05566 
05567        if (addr != NULL)
05568        {
05569               p = dkim_param_get(set, (u_char *) "ra");
05570               if (p != NULL)
05571               {
05572                      memset(addr, '\0', addrlen);
05573                      (void) dkim_qp_decode(p, addr, addrlen - 1);
05574                      p = (u_char *) strchr((char *) addr, '@');
05575                      if (p != NULL)
05576                             *p = '\0';
05577               }
05578        }
05579 
05580        if (opts != NULL)
05581        {
05582               p = dkim_param_get(set, (u_char *) "ro");
05583               if (p != NULL)
05584                      strlcpy((char *) opts, (char *) p, optslen);
05585        }
05586 
05587        if (smtp != NULL)
05588        {
05589               p = dkim_param_get(set, (u_char *) "rs");
05590               if (p != NULL)
05591               {
05592                      memset(smtp, '\0', smtplen);
05593                      (void) dkim_qp_decode(p, smtp, smtplen - 1);
05594               }
05595        }
05596 
05597        if (pct != NULL)
05598        {
05599               p = dkim_param_get(set, (u_char *) "rp");
05600               if (p != NULL)
05601               {
05602                      u_int out;
05603                      char *q;
05604 
05605                      out = strtoul((char *) p, &q, 10);
05606                      if (*q == '\0')
05607                             *pct = out;
05608               }
05609        }
05610 
05611        return DKIM_STAT_OK;
05612 }
05613 
05614 /*
05615 **  DKIM_SIG_PROCESS -- process a signature
05616 **
05617 **  Parameters:
05618 **     dkim -- DKIM handle
05619 **     sig -- DKIM_SIGINFO handle
05620 **
05621 **  Return value:
05622 **     A DKIM_STAT_* constant.
05623 */
05624 
05625 DKIM_STAT
05626 dkim_sig_process(DKIM *dkim, DKIM_SIGINFO *sig)
05627 {
05628        DKIM_STAT status;
05629        int nid;
05630        int rsastat;
05631        size_t diglen = 0;
05632 #ifdef USE_GNUTLS
05633        gnutls_datum_t key;
05634 #else /* USE_GNUTLS */
05635        BIO *key;
05636 #endif /* USE_GNUTLS */
05637        u_char *digest = NULL;
05638        struct dkim_rsa *rsa;
05639 
05640        assert(dkim != NULL);
05641        assert(sig != NULL);
05642 
05643        /* skip it if we're supposed to ignore it */
05644        if ((sig->sig_flags & DKIM_SIGFLAG_IGNORE) != 0)
05645               return DKIM_STAT_OK;
05646 
05647        /* skip it if there was a syntax or other error */
05648        if (sig->sig_error != DKIM_SIGERROR_UNKNOWN)
05649               return DKIM_STAT_OK;
05650 
05651        /* skip the DNS part if we've already done it */
05652        if ((sig->sig_flags & DKIM_SIGFLAG_PROCESSED) == 0)
05653        {
05654               /* get the digest */
05655               status = dkim_canon_getfinal(sig->sig_hdrcanon, &digest,
05656                                            &diglen);
05657               if (status != DKIM_STAT_OK)
05658               {
05659                      dkim_error(dkim, "dkim_canon_getfinal() failed");
05660                      return DKIM_STAT_INTERNAL;
05661               }
05662               assert(digest != NULL && diglen != 0);
05663 
05664               /* retrieve the key */
05665               status = dkim_get_key(dkim, sig, FALSE);
05666               if (status == DKIM_STAT_NOKEY)
05667               {
05668                      sig->sig_flags |= DKIM_SIGFLAG_PROCESSED;
05669                      sig->sig_error = DKIM_SIGERROR_NOKEY;
05670                      return DKIM_STAT_OK;
05671               }
05672               else if (status == DKIM_STAT_KEYFAIL)
05673               {
05674                      sig->sig_flags |= DKIM_SIGFLAG_PROCESSED;
05675                      sig->sig_error = DKIM_SIGERROR_KEYFAIL;
05676                      return DKIM_STAT_OK;
05677               }
05678               else if (status == DKIM_STAT_CANTVRFY ||
05679                        status == DKIM_STAT_SYNTAX)
05680               {
05681                      sig->sig_flags |= DKIM_SIGFLAG_PROCESSED;
05682                      if (sig->sig_error == DKIM_SIGERROR_UNKNOWN)
05683                             sig->sig_error = DKIM_SIGERROR_DNSSYNTAX;
05684                      return DKIM_STAT_OK;
05685               }
05686               else if (status == DKIM_STAT_MULTIDNSREPLY)
05687               {
05688                      sig->sig_flags |= DKIM_SIGFLAG_PROCESSED;
05689                      sig->sig_error = DKIM_SIGERROR_MULTIREPLY;
05690                      return DKIM_STAT_OK;
05691               }
05692               else if (status == DKIM_STAT_REVOKED)
05693               {
05694                      sig->sig_flags |= DKIM_SIGFLAG_PROCESSED;
05695                      sig->sig_error = DKIM_SIGERROR_KEYREVOKED;
05696                      return DKIM_STAT_OK;
05697               }
05698               else if (status != DKIM_STAT_OK)
05699               {
05700                      return status;
05701               }
05702 
05703 #ifdef USE_GNUTLS
05704               key.data = sig->sig_key;
05705               key.size = sig->sig_keylen;
05706 #else /* USE_GNUTLS */
05707               /* load the public key */
05708               key = BIO_new_mem_buf(sig->sig_key, sig->sig_keylen);
05709               if (key == NULL)
05710               {
05711                      dkim_error(dkim, "BIO_new_mem_buf() failed");
05712                      return DKIM_STAT_NORESOURCE;
05713               }
05714 #endif /* USE_GNUTLS */
05715 
05716               /* set up to verify */
05717               if (sig->sig_signature == NULL)
05718               {
05719                      rsa = DKIM_MALLOC(dkim, sizeof(struct dkim_rsa));
05720                      if (rsa == NULL)
05721                      {
05722                             dkim_error(dkim,
05723                                        "unable to allocate %d byte(s)",
05724                                        sizeof(struct dkim_rsa));
05725 #ifndef USE_GNUTLS
05726                             BIO_free(key);
05727 #endif /* ! USE_GNUTLS */
05728                             return DKIM_STAT_NORESOURCE;
05729                      }
05730 
05731                      sig->sig_signature = rsa;
05732               }
05733               else
05734               {
05735                      rsa = sig->sig_signature;
05736               }
05737               memset(rsa, '\0', sizeof(struct dkim_rsa));
05738 
05739 #ifdef USE_GNUTLS
05740               rsa->rsa_sig.data = sig->sig_sig;
05741               rsa->rsa_sig.size = sig->sig_siglen;
05742 
05743               rsa->rsa_digest.data = digest;
05744               rsa->rsa_digest.size = diglen;
05745 
05746               if (gnutls_pubkey_init(&rsa->rsa_pubkey) != GNUTLS_E_SUCCESS)
05747               {
05748                      dkim_error(dkim,
05749                                 "s=%s d=%s: gnutls_pubkey_init() failed",
05750                                 dkim_sig_getselector(sig),
05751                                 dkim_sig_getdomain(sig));
05752 
05753                      sig->sig_error = DKIM_SIGERROR_KEYDECODE;
05754 
05755                      return DKIM_STAT_OK;
05756               }
05757 
05758               status = gnutls_pubkey_import(rsa->rsa_pubkey, &key,
05759                                             GNUTLS_X509_FMT_DER);
05760               if (status != GNUTLS_E_SUCCESS)
05761               {
05762                      dkim_error(dkim,
05763                                 "s=%s d=%s: gnutls_pubkey_import() failed",
05764                                 dkim_sig_getselector(sig),
05765                                 dkim_sig_getdomain(sig));
05766 
05767                      sig->sig_error = DKIM_SIGERROR_KEYDECODE;
05768 
05769                      return DKIM_STAT_OK;
05770               }
05771 
05772               rsastat = gnutls_pubkey_verify_hash(rsa->rsa_pubkey, 0,
05773                                                   &rsa->rsa_digest,
05774                                                   &rsa->rsa_sig);
05775 
05776               (void) gnutls_pubkey_get_pk_algorithm(rsa->rsa_pubkey,
05777                                                     &rsa->rsa_keysize);
05778 
05779               sig->sig_keybits = rsa->rsa_keysize;
05780 #else /* USE_GNUTLS */
05781               rsa->rsa_pkey = d2i_PUBKEY_bio(key, NULL);
05782               if (rsa->rsa_pkey == NULL)
05783               {
05784                      dkim_error(dkim, "s=%s d=%s: d2i_PUBKEY_bio() failed",
05785                                 dkim_sig_getselector(sig),
05786                                 dkim_sig_getdomain(sig));
05787                      BIO_free(key);
05788 
05789                      sig->sig_error = DKIM_SIGERROR_KEYDECODE;
05790 
05791                      return DKIM_STAT_OK;
05792               }
05793 
05794               /* set up the RSA object */
05795               rsa->rsa_rsa = EVP_PKEY_get1_RSA(rsa->rsa_pkey);
05796               if (rsa->rsa_rsa == NULL)
05797               {
05798                      dkim_error(dkim,
05799                                 "s=%s d=%s: EVP_PKEY_get1_RSA() failed",
05800                                 dkim_sig_getselector(sig),
05801                                 dkim_sig_getdomain(sig));
05802                      BIO_free(key);
05803 
05804                      sig->sig_error = DKIM_SIGERROR_KEYDECODE;
05805 
05806                      return DKIM_STAT_OK;
05807               }
05808 
05809               rsa->rsa_keysize = RSA_size(rsa->rsa_rsa);
05810               rsa->rsa_pad = RSA_PKCS1_PADDING;
05811 
05812               rsa->rsa_rsain = sig->sig_sig;
05813               rsa->rsa_rsainlen = sig->sig_siglen;
05814 
05815               sig->sig_keybits = 8 * rsa->rsa_keysize;
05816 
05817               nid = NID_sha1;
05818 
05819               if (dkim_libfeature(dkim->dkim_libhandle,
05820                                   DKIM_FEATURE_SHA256) &&
05821                   sig->sig_hashtype == DKIM_HASHTYPE_SHA256)
05822                      nid = NID_sha256;
05823 
05824               rsastat = RSA_verify(nid, digest, diglen, rsa->rsa_rsain,
05825                             rsa->rsa_rsainlen, rsa->rsa_rsa);
05826 
05827               BIO_free(key);
05828               RSA_free(rsa->rsa_rsa);
05829               rsa->rsa_rsa = NULL;
05830 #endif /* USE_GNUTLS */
05831 
05832               if (rsastat == 1)
05833                      sig->sig_flags |= DKIM_SIGFLAG_PASSED;
05834               else
05835                      sig->sig_error = DKIM_SIGERROR_BADSIG;
05836 
05837               sig->sig_flags |= DKIM_SIGFLAG_PROCESSED;
05838        }
05839 
05840        /* do the body hash check if possible */
05841        if (dkim->dkim_bodydone && sig->sig_bh == DKIM_SIGBH_UNTESTED &&
05842            (sig->sig_flags & DKIM_SIGFLAG_PASSED) != 0)
05843        {
05844               u_char *bhash;
05845               u_char b64buf[BUFRSZ];
05846 
05847               memset(b64buf, '\0', sizeof b64buf);
05848 
05849               dkim_canon_getfinal(sig->sig_bodycanon, &digest, &diglen);
05850 
05851               bhash = dkim_param_get(sig->sig_taglist, (u_char *) "bh");
05852 
05853               dkim_base64_encode(digest, diglen, b64buf, sizeof b64buf);
05854 
05855               if (strcmp((char *) bhash, (char *) b64buf) == 0)
05856                      sig->sig_bh = DKIM_SIGBH_MATCH;
05857               else
05858                      sig->sig_bh = DKIM_SIGBH_MISMATCH;
05859        }
05860 
05861        /*
05862        **  Fail if t=s was present in the key and the i= and d= domains
05863        **  don't match.
05864        */
05865 
05866        if ((sig->sig_flags & DKIM_SIGFLAG_NOSUBDOMAIN) != 0)
05867        {
05868               char *d;
05869               char *i;
05870 
05871               d = (char *) dkim_param_get(sig->sig_taglist, (u_char *) "d");
05872               i = (char *) dkim_param_get(sig->sig_taglist, (u_char *) "i");
05873 
05874               if (i != NULL && d != NULL)
05875               {
05876                      char *at;
05877 
05878                      at = strchr(i, '@');
05879                      if (at == NULL)
05880                             at = i;
05881                      else
05882                             at++;
05883 
05884                      if (strcasecmp(at, d) != 0)
05885                             sig->sig_error = DKIM_SIGERROR_SUBDOMAIN;
05886               }
05887        }
05888 
05889        /*
05890        **  Fail if the "must be signed" list was set and this signature didn't
05891        **  cover a must-be-signed header which was present.
05892        */
05893 
05894        if (dkim->dkim_libhandle->dkiml_mbs != NULL)
05895        {
05896               int c;
05897 
05898               for (c = 0; dkim->dkim_libhandle->dkiml_mbs[c] != NULL; c++)
05899               {
05900                      if (dkim_get_header(dkim,
05901                                          dkim->dkim_libhandle->dkiml_mbs[c],
05902                                          0, 0) != NULL &&
05903                          !dkim_sig_hdrsigned(sig,
05904                                              dkim->dkim_libhandle->dkiml_mbs[c]))
05905                      {
05906                             sig->sig_error = DKIM_SIGERROR_MBSFAILED;
05907                             break;
05908                      }
05909               }
05910        }
05911 
05912        if (sig->sig_error == DKIM_SIGERROR_UNKNOWN &&
05913            sig->sig_bh != DKIM_SIGBH_UNTESTED)
05914               sig->sig_error = DKIM_SIGERROR_OK;
05915 
05916        return DKIM_STAT_OK;
05917 }
05918 
05919 /*
05920 **  DKIM_OHDRS -- extract and decode original headers
05921 **
05922 **  Parameters:
05923 **     dkim -- DKIM handle
05924 **     sig -- DKIM_SIGINFO handle
05925 **     ptrs -- user-provided array of pointers to header strings (updated)
05926 **     pcnt -- number of pointers available (updated)
05927 **
05928 **  Return value:
05929 **     A DKIM_STAT_* constant.
05930 **
05931 **  Notes:
05932 **     If the returned value of pcnt is greater that what it was originally,
05933 **     then there were more headers than there were pointers.
05934 */
05935 
05936 DKIM_STAT
05937 dkim_ohdrs(DKIM *dkim, DKIM_SIGINFO *sig, u_char **ptrs, int *pcnt)
05938 {
05939        int n = 0;
05940        char *z;
05941        u_char *ch;
05942        u_char *p;
05943        u_char *q;
05944        char *last;
05945 
05946        assert(dkim != NULL);
05947        assert(ptrs != NULL);
05948        assert(pcnt != NULL);
05949 
05950        if (dkim->dkim_mode != DKIM_MODE_VERIFY)
05951               return DKIM_STAT_INVALID;
05952 
05953        /* pick the one we're going to use */
05954        if (sig == NULL)
05955        {
05956               int c;
05957 
05958               for (c = 0; c < dkim->dkim_sigcount; c++)
05959               {
05960                      sig = dkim->dkim_siglist[c];
05961                      if ((sig->sig_flags & DKIM_SIGFLAG_PROCESSED) != 0 &&
05962                          (sig->sig_flags & DKIM_SIGFLAG_IGNORE) == 0)
05963                             break;
05964 
05965                      sig = NULL;
05966               }
05967        }
05968 
05969        /* none useable; return error */
05970        if (sig == NULL)
05971               return DKIM_STAT_INVALID;
05972 
05973        /* find the tag */
05974        z = (char *) dkim_param_get(sig->sig_taglist, (u_char *) "z");
05975        if (z == NULL || *z == '\0')
05976        {
05977               *pcnt = 0;
05978               return DKIM_STAT_OK;
05979        }
05980 
05981        /* get memory for the decode */
05982        if (dkim->dkim_zdecode == NULL)
05983        {
05984               dkim->dkim_zdecode = DKIM_MALLOC(dkim, MAXHEADERS);
05985               if (dkim->dkim_zdecode == NULL)
05986               {
05987                      dkim_error(dkim, "unable to allocate %d byte(s)",
05988                                 strlen(z));
05989                      return DKIM_STAT_NORESOURCE;
05990               }
05991        }
05992 
05993        /* copy it */
05994        strlcpy((char *) dkim->dkim_zdecode, z, strlen(z));
05995 
05996        /* decode */
05997        for (ch = (u_char *) strtok_r(z, "|", &last);
05998             ch != NULL;
05999             ch = (u_char *) strtok_r(NULL, "|", &last))
06000        {
06001               for (p = ch, q = ch; *p != '\0'; p++)
06002               {
06003                      if (*p == '=')
06004                      {
06005                             char c;
06006 
06007                             if (!isxdigit(*(p + 1)) || !isxdigit(*(p + 2)))
06008                             {
06009                                    dkim_error(dkim,
06010                                               "invalid trailing character (0x%02x 0x%02x) in z= tag value",
06011                                               *(p + 1), *(p + 2));
06012 
06013                                    return DKIM_STAT_INVALID;
06014                             }
06015 
06016                             c = 16 * dkim_hexchar(*(p + 1)) + dkim_hexchar(*(p + 2));
06017 
06018                             p += 2;
06019 
06020                             *q = c;
06021                             q++;
06022                      }
06023                      else
06024                      {
06025                             if (q != p)
06026                                    *q = *p;
06027                             q++;
06028                      }
06029               }
06030 
06031               *q = '\0';
06032 
06033               if (n < *pcnt)
06034                      ptrs[n] = ch;
06035               n++;
06036        }
06037 
06038        *pcnt = n;
06039 
06040        return DKIM_STAT_OK;
06041 }
06042 
06043 /*
06044 **  DKIM_DIFFHEADERS -- compare original headers with received headers
06045 **
06046 **  Parameters:
06047 **     dkim -- DKIM handle
06048 **     canon -- header canonicalization mode in use
06049 **     maxcost -- maximum "cost" of changes to be reported
06050 **     ohdrs -- original headers, presumably extracted from a "z" tag
06051 **     nohdrs -- number of headers at "ohdrs" available
06052 **     out -- pointer to an array of struct dkim_hdrdiff objects (updated)
06053 **     nout -- counter of handles returned (updated)
06054 **
06055 **  Return value:
06056 **     A DKIM_STAT_* constant.
06057 **
06058 **  Side effects:
06059 **     A series of DKIM_HDRDIFF handles is allocated and must later be
06060 **     destroyed.
06061 */
06062 
06063 DKIM_STAT
06064 dkim_diffheaders(DKIM *dkim, dkim_canon_t canon, int maxcost,
06065                  char **ohdrs, int nohdrs,
06066                  struct dkim_hdrdiff **out, int *nout)
06067 {
06068 #ifdef _FFR_DIFFHEADERS
06069        int n = 0;
06070        int a = 0;
06071        int c;
06072        int status;
06073        u_char *p;
06074        u_char *q;
06075        u_char *end;
06076        void *cls;
06077        struct dkim_header *hdr;
06078        struct dkim_hdrdiff *diffs = NULL;
06079        struct dkim_dstring *tmphdr;
06080        struct dkim_dstring **cohdrs;
06081        DKIM_LIB *lib;
06082        regaparams_t params;
06083        regamatch_t matches;
06084        regex_t re;
06085        u_char restr[BUFRSZ + 1];
06086 
06087        assert(dkim != NULL);
06088        assert(out != NULL);
06089        assert(nout != NULL);
06090 
06091        if (dkim->dkim_mode != DKIM_MODE_VERIFY)
06092               return DKIM_STAT_INVALID;
06093        if (maxcost == 0)
06094               return DKIM_STAT_INVALID;
06095 
06096        tmphdr = dkim_dstring_new(dkim, BUFRSZ, MAXBUFRSZ);
06097        if (tmphdr == NULL)
06098        {
06099               dkim_error(dkim, "failed to allocate dynamic string");
06100               return DKIM_STAT_NORESOURCE;
06101        }
06102 
06103        lib = dkim->dkim_libhandle;
06104        cls = dkim->dkim_closure;
06105 
06106        memset(&params, '\0', sizeof params);
06107 
06108        params.cost_ins = COST_INSERT;
06109        params.cost_del = COST_DELETE;
06110        params.cost_subst = COST_SUBST;
06111 
06112        params.max_cost = maxcost;
06113        params.max_ins = DKIM_MAXHEADER;
06114        params.max_del = DKIM_MAXHEADER;
06115        params.max_subst = DKIM_MAXHEADER;
06116        params.max_err = maxcost;
06117 
06118        matches.nmatch = 0;
06119        matches.pmatch = NULL;
06120 
06121        /* canonicalize all the original header fields */
06122        cohdrs = DKIM_MALLOC(dkim, sizeof(struct dkim_dstring *) * nohdrs);
06123        if (cohdrs == NULL)
06124        {
06125               dkim_error(dkim, strerror(errno));
06126               return DKIM_STAT_NORESOURCE;
06127        }
06128 
06129        for (c = 0; c < nohdrs; c++)
06130        {
06131               cohdrs[c] = dkim_dstring_new(dkim, DKIM_MAXHEADER, 0);
06132               if (cohdrs[c] == NULL)
06133               {
06134                      for (n = 0; n < c; n++)
06135                             dkim_dstring_free(cohdrs[n]);
06136 
06137                      DKIM_FREE(dkim, cohdrs);
06138 
06139                      dkim_error(dkim, strerror(errno));
06140 
06141                      return DKIM_STAT_NORESOURCE;
06142               }
06143 
06144               status = dkim_canon_header_string(cohdrs[c], canon,
06145                                                 ohdrs[c], strlen(ohdrs[c]),
06146                                                 FALSE);
06147               if (status != DKIM_STAT_OK)
06148               {
06149                      for (n = 0; n < c; n++)
06150                             dkim_dstring_free(cohdrs[n]);
06151 
06152                      DKIM_FREE(dkim, cohdrs);
06153 
06154                      dkim_error(dkim, strerror(errno));
06155 
06156                      return status;
06157               }
06158        }
06159 
06160        for (hdr = dkim->dkim_hhead; hdr != NULL; hdr = hdr->hdr_next)
06161        {
06162               dkim_dstring_blank(tmphdr);
06163 
06164               status = dkim_canon_header_string(tmphdr, canon,
06165                                                 hdr->hdr_text,
06166                                                 hdr->hdr_textlen, FALSE);
06167               if (status != DKIM_STAT_OK)
06168               {
06169                      dkim_dstring_free(tmphdr);
06170                      for (c = 0; c < nohdrs; c++)
06171                             dkim_dstring_free(cohdrs[c]);
06172                      DKIM_FREE(dkim, cohdrs);
06173                      return status;
06174               }
06175 
06176               memset(restr, '\0', sizeof restr);
06177 
06178               end = restr + sizeof restr;
06179 
06180               for (p = dkim_dstring_get(tmphdr), q = restr;
06181                    *p != '\0' && q < end - 3;
06182                    p++)
06183               {
06184                      if (q == restr)
06185                             *q++ = '^';
06186 
06187                      if (*p == '*' ||
06188                          *p == '\\' ||
06189                          *p == '$' ||
06190                          *p == '+' ||
06191                          *p == '[' ||
06192                          *p == ']' ||
06193                          *p == '(' ||
06194                          *p == ')' ||
06195                          *p == '.' ||
06196                          *p == '|')
06197                             *q++ = '\\';
06198 
06199                      *q++ = *p;
06200               }
06201 
06202               *q = '$';
06203 
06204               status = tre_regcomp(&re, restr, REG_NOSUB);
06205               if (status != 0)
06206               {
06207                      char err[BUFRSZ + 1];
06208 
06209                      memset(err, '\0', sizeof err);
06210 
06211                      (void) tre_regerror(status, &re, err, sizeof err);
06212 
06213                      dkim_error(dkim, err);
06214 
06215                      if (diffs != NULL)
06216                             dkim_mfree(lib, cls, diffs);
06217 
06218                      dkim_dstring_free(tmphdr);
06219                      for (c = 0; c < nohdrs; c++)
06220                             dkim_dstring_free(cohdrs[c]);
06221                      DKIM_FREE(dkim, cohdrs);
06222 
06223                      return DKIM_STAT_INTERNAL;
06224               }
06225 
06226               for (c = 0; c < nohdrs; c++)
06227               {
06228                      /* not even the same header field */
06229                      if (hdr->hdr_namelen != hdr->hdr_textlen &&
06230                          strncmp(dkim_dstring_get(cohdrs[c]),
06231                                  dkim_dstring_get(tmphdr),
06232                                  hdr->hdr_namelen + 1) != 0)
06233                             continue;
06234 
06235                      /* same, no changes at all */
06236                      if (strcmp(dkim_dstring_get(cohdrs[c]),
06237                                 dkim_dstring_get(tmphdr)) == 0)
06238                             continue;
06239 
06240                      /* check for approximate match */
06241                      status = tre_regaexec(&re, dkim_dstring_get(cohdrs[c]),
06242                                            &matches, params, 0);
06243 
06244                      if (status == 0)
06245                      {
06246                             if (n + 1 > a)
06247                             {
06248                                    int sz;
06249                                    struct dkim_hdrdiff *new;
06250 
06251                                    if (a == 0)
06252                                           a = 16;
06253                                    else
06254                                           a *= 2;
06255 
06256                                    sz = a * sizeof(struct dkim_hdrdiff);
06257 
06258                                    new = (struct dkim_hdrdiff *) dkim_malloc(lib,
06259                                                                              cls,
06260                                                                              sz);
06261 
06262                                    if (new == NULL)
06263                                    {
06264                                           dkim_error(dkim,
06265                                                      "unable to allocate %d byte(s)",
06266                                                      sz);
06267 
06268                                           if (diffs != NULL)
06269                                           {
06270                                                  dkim_mfree(lib, cls,
06271                                                             diffs);
06272                                           }
06273 
06274                                           dkim_dstring_free(tmphdr);
06275                                           for (c = 0; c < nohdrs; c++)
06276                                                  dkim_dstring_free(cohdrs[c]);
06277                                           DKIM_FREE(dkim, cohdrs);
06278 
06279                                           return DKIM_STAT_NORESOURCE;
06280                                    }
06281 
06282                                    dkim_mfree(lib, cls, diffs);
06283 
06284                                    diffs = new;
06285 
06286                                    sz = (a - n) & sizeof(struct dkim_hdrdiff);
06287                                    memset(&diffs[n], '\0', sz);
06288                             }
06289 
06290                             diffs[n].hd_old = ohdrs[c];
06291                             diffs[n].hd_new = hdr->hdr_text;
06292 
06293                             n++;
06294                      }
06295               }
06296 
06297               tre_regfree(&re);
06298        }
06299 
06300        *out = diffs;
06301        *nout = n;
06302 
06303        dkim_dstring_free(tmphdr);
06304        for (c = 0; c < nohdrs; c++)
06305               dkim_dstring_free(cohdrs[c]);
06306        DKIM_FREE(dkim, cohdrs);
06307 
06308        return DKIM_STAT_OK;
06309 #else /* _FFR_DIFFHEADERS */
06310        return DKIM_STAT_NOTIMPLEMENT;
06311 #endif /* _FFR_DIFFHEADERS */
06312 }
06313 
06314 /*
06315 **  DKIM_HEADER -- process a header
06316 **
06317 **  Parameters:
06318 **     dkim -- DKIM handle
06319 **     hdr -- header text
06320 **     len -- bytes available at "hdr"
06321 **
06322 **  Return value:
06323 **     A DKIM_STAT_* constant.
06324 */
06325 
06326 DKIM_STAT
06327 dkim_header(DKIM *dkim, u_char *hdr, size_t len)
06328 {
06329        u_char *colon;
06330        u_char *semicolon;
06331        u_char *end = NULL;
06332        struct dkim_header *h;
06333 
06334        assert(dkim != NULL);
06335        assert(hdr != NULL);
06336        assert(len != 0);
06337 
06338 #ifdef _FFR_RESIGN
06339        if (dkim->dkim_hdrbind)
06340               return DKIM_STAT_INVALID;
06341 #endif /* _FFR_RESIGN */
06342 
06343        if (dkim->dkim_state > DKIM_STATE_HEADER)
06344               return DKIM_STAT_INVALID;
06345        dkim->dkim_state = DKIM_STATE_HEADER;
06346 
06347        colon = memchr(hdr, ':', len);
06348        if (colon != NULL)
06349        {
06350               end = colon;
06351 
06352               while (end > hdr && isascii(*(end - 1)) && isspace(*(end - 1)))
06353                      end--;
06354        }
06355 
06356        /* don't allow a field name containing a semicolon */
06357        semicolon = memchr(hdr, ';', len);
06358        if (semicolon != NULL && colon != NULL && semicolon < colon)
06359               return DKIM_STAT_SYNTAX;
06360 
06361        /* see if this is one we should skip */
06362        if (dkim->dkim_mode == DKIM_MODE_SIGN &&
06363            dkim->dkim_libhandle->dkiml_skipre)
06364        {
06365               int status;
06366               unsigned char name[DKIM_MAXHEADER + 1];
06367 
06368               strlcpy((char *) name, (char *) hdr, sizeof name);
06369               if (end != NULL)
06370                      name[end - hdr] = '\0';
06371 
06372               status = regexec(&dkim->dkim_libhandle->dkiml_skiphdrre,
06373                                (char *) name, 0, NULL, 0);
06374 
06375               if (status == 0)
06376                      return DKIM_STAT_OK;
06377               else
06378                      assert(status == REG_NOMATCH);
06379        }
06380 
06381        h = DKIM_MALLOC(dkim, sizeof(struct dkim_header));
06382 
06383        if (h == NULL)
06384        {
06385               dkim_error(dkim, "unable to allocate %d byte(s)",
06386                          sizeof(struct dkim_header));
06387               return DKIM_STAT_NORESOURCE;
06388        }
06389 
06390        if ((dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_FIXCRLF) != 0)
06391        {
06392               u_char prev = '\0';
06393               u_char *p;
06394               struct dkim_dstring *tmphdr;
06395 
06396               tmphdr = dkim_dstring_new(dkim, BUFRSZ, MAXBUFRSZ);
06397               if (tmphdr == NULL)
06398               {
06399                      DKIM_FREE(dkim, h);
06400                      return DKIM_STAT_NORESOURCE;
06401               }
06402 
06403               for (p = hdr; *p != '\0'; p++)
06404               {
06405                      if (*p == '\n' && prev != '\r')           /* bare LF */
06406                      {
06407                             dkim_dstring_catn(tmphdr, CRLF, 2);
06408                      }
06409                      else if (prev == '\r' && *p != '\n')      /* bare CR */
06410                      {
06411                             dkim_dstring_cat1(tmphdr, '\n');
06412                             dkim_dstring_cat1(tmphdr, *p);
06413                      }
06414                      else                               /* other */
06415                      {
06416                             dkim_dstring_cat1(tmphdr, *p);
06417                      }
06418 
06419                      prev = *p;
06420               }
06421 
06422               if (prev == '\r')                         /* end CR */
06423                      dkim_dstring_cat1(tmphdr, '\n');
06424 
06425               h->hdr_text = dkim_strdup(dkim, dkim_dstring_get(tmphdr),
06426                                         dkim_dstring_len(tmphdr));
06427 
06428               dkim_dstring_free(tmphdr);
06429        }
06430        else
06431        {
06432               h->hdr_text = dkim_strdup(dkim, hdr, len);
06433        }
06434 
06435        if (h->hdr_text == NULL)
06436        {
06437               DKIM_FREE(dkim, h);
06438               return DKIM_STAT_NORESOURCE;
06439        }
06440 
06441        h->hdr_namelen = end != NULL ? end - hdr : len;
06442        h->hdr_textlen = len;
06443        if (colon == NULL)
06444               h->hdr_colon = NULL;
06445        else
06446               h->hdr_colon = h->hdr_text + (colon - hdr);
06447        h->hdr_flags = 0;
06448        h->hdr_next = NULL;
06449 
06450        if (dkim->dkim_hhead == NULL)
06451        {
06452               dkim->dkim_hhead = h;
06453               dkim->dkim_htail = h;
06454        }
06455        else
06456        {
06457               dkim->dkim_htail->hdr_next = h;
06458               dkim->dkim_htail = h;
06459        }
06460 
06461        dkim->dkim_hdrcnt++;
06462 
06463        if (h->hdr_colon != NULL)
06464        {
06465               if (h->hdr_namelen == DKIM_SIGNHEADER_LEN &&
06466                   strncasecmp((char *) hdr, DKIM_SIGNHEADER,
06467                               DKIM_SIGNHEADER_LEN) == 0)
06468               {
06469                      DKIM_STAT status;
06470                      size_t plen;
06471 
06472                      plen = len - (h->hdr_colon - h->hdr_text) - 1;
06473                      status = dkim_process_set(dkim, DKIM_SETTYPE_SIGNATURE,
06474                                                h->hdr_colon + 1, plen, h,
06475                                                FALSE, NULL);
06476 
06477                      if (status != DKIM_STAT_OK)
06478                             return status;
06479               }
06480        }
06481 
06482        return DKIM_STAT_OK;
06483 }
06484 
06485 /*
06486 **  DKIM_EOH -- declare end-of-headers
06487 ** 
06488 **  Parameters:
06489 **     dkim -- DKIM handle
06490 **
06491 **  Return value:
06492 **     A DKIM_STAT_* constant.
06493 */
06494 
06495 DKIM_STAT
06496 dkim_eoh(DKIM *dkim)
06497 {
06498        assert(dkim != NULL);
06499 
06500        if (dkim->dkim_mode == DKIM_MODE_VERIFY)
06501               return dkim_eoh_verify(dkim);
06502        else
06503               return dkim_eoh_sign(dkim);
06504 }
06505 
06506 /*
06507 **  DKIM_BODY -- pass a body chunk in for processing
06508 **
06509 **  Parameters:
06510 **     dkim -- DKIM handle
06511 **     buf -- body chunk
06512 **     buflen -- number of bytes at "buf"
06513 **
06514 **  Return value:
06515 **     A DKIM_STAT_* constant.
06516 */
06517 
06518 DKIM_STAT
06519 dkim_body(DKIM *dkim, u_char *buf, size_t buflen)
06520 {
06521        assert(dkim != NULL);
06522        assert(buf != NULL);
06523 
06524 #ifdef _FFR_RESIGN
06525        if (dkim->dkim_resign != NULL)
06526               return DKIM_STAT_INVALID;
06527 #endif /* _FFR_RESIGN */
06528 
06529        if (dkim->dkim_state > DKIM_STATE_BODY ||
06530            dkim->dkim_state < DKIM_STATE_EOH1)
06531               return DKIM_STAT_INVALID;
06532        dkim->dkim_state = DKIM_STATE_BODY;
06533 
06534        if (dkim->dkim_skipbody)
06535               return DKIM_STAT_OK;
06536 
06537        return dkim_canon_bodychunk(dkim, buf, buflen);
06538 }
06539 
06540 /*
06541 **  DKIM_EOM -- declare end-of-body; conduct verification or signing
06542 **
06543 **  Parameters:
06544 **     dkim -- DKIM handle
06545 **     testkey -- TRUE iff the a matching key was found but is marked as a
06546 **                test key (returned)
06547 **
06548 **  Return value:
06549 **     A DKIM_STAT_* constant.
06550 */
06551 
06552 DKIM_STAT
06553 dkim_eom(DKIM *dkim, _Bool *testkey)
06554 {
06555        assert(dkim != NULL);
06556 
06557        if (dkim->dkim_mode == DKIM_MODE_SIGN)
06558               return dkim_eom_sign(dkim);
06559        else
06560               return dkim_eom_verify(dkim, testkey);
06561 }
06562 
06563 /*
06564 **  DKIM_CHUNK -- process a message chunk
06565 **
06566 **  Parameters:
06567 **     dkim -- DKIM handle
06568 **     buf -- data to process
06569 **     buflen -- number of bytes at "buf" to process
06570 **
06571 **  Return value:
06572 **     A DKIM_STAT_* constant.
06573 */
06574 
06575 DKIM_STAT
06576 dkim_chunk(DKIM *dkim, u_char *buf, size_t buflen)
06577 {
06578        _Bool bso;
06579        DKIM_STAT status;
06580        unsigned char *p;
06581        unsigned char *end;
06582 
06583        assert(dkim != NULL);
06584 
06585        bso = ((dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_BADSIGHANDLES) != 0);
06586 
06587        if ((dkim->dkim_libhandle->dkiml_flags & DKIM_LIBFLAGS_FIXCRLF) == 0)
06588               dkim->dkim_chunkcrlf = DKIM_CRLF_CRLF;
06589 
06590        /* verify chunking state */
06591        if (dkim->dkim_chunkstate >= DKIM_CHUNKSTATE_DONE)
06592        {
06593               return DKIM_STAT_INVALID;
06594        }
06595        else if (dkim->dkim_chunkstate == DKIM_CHUNKSTATE_INIT)
06596        {
06597               if (dkim->dkim_hdrbuf == NULL)
06598               {
06599                      dkim->dkim_hdrbuf = dkim_dstring_new(dkim, BUFRSZ,
06600                                                           MAXBUFRSZ);
06601                      if (dkim->dkim_hdrbuf == NULL)
06602                             return DKIM_STAT_NORESOURCE;
06603               }
06604               else
06605               {
06606                      dkim_dstring_blank(dkim->dkim_hdrbuf);
06607               }
06608 
06609               dkim->dkim_chunkstate = DKIM_CHUNKSTATE_HEADER;
06610               dkim->dkim_chunksm = 0;
06611        }
06612 
06613        /* process an "end" call */
06614        if (buf == NULL || buflen == 0)
06615        {
06616               if (dkim->dkim_chunkstate == DKIM_CHUNKSTATE_HEADER)
06617               {
06618                      if (dkim_dstring_len(dkim->dkim_hdrbuf) > 0)
06619                      {
06620                             status = dkim_header(dkim,
06621                                                  dkim_dstring_get(dkim->dkim_hdrbuf),
06622                                                  dkim_dstring_len(dkim->dkim_hdrbuf));
06623                             if (status != DKIM_STAT_OK &&
06624                                 !(status == DKIM_STAT_SYNTAX && bso))
06625                                    return status;
06626                      }
06627 
06628                      status = dkim_eoh(dkim);
06629                      if (status != DKIM_STAT_OK)
06630                             return status;
06631               }
06632 
06633               dkim->dkim_chunkstate = DKIM_CHUNKSTATE_DONE;
06634 
06635               return DKIM_STAT_OK;
06636        }
06637 
06638        /* if we're in body state, just call dkim_body() */
06639        if (dkim->dkim_chunkstate == DKIM_CHUNKSTATE_BODY)
06640               return dkim_body(dkim, buf, buflen);
06641 
06642        assert(dkim->dkim_chunkstate == DKIM_CHUNKSTATE_HEADER);
06643 
06644        end = buf + buflen - 1;
06645 
06646        /* process headers */
06647        for (p = buf; p <= end; p++)
06648        {
06649               switch (dkim->dkim_chunksm)
06650               {
06651                 case 0:
06652                      if (*p == '\n' &&
06653                          dkim->dkim_chunkcrlf != DKIM_CRLF_CRLF)
06654                      {
06655                             dkim->dkim_chunkcrlf = DKIM_CRLF_LF;
06656 
06657                             /*
06658                             **  If this is a CRLF up front, change state
06659                             **  and write the rest as part of the body.
06660                             */
06661 
06662                             if (dkim->dkim_hhead == NULL &&
06663                                 dkim_dstring_len(dkim->dkim_hdrbuf) == 2)
06664                             {
06665                                    status = dkim_eoh(dkim);
06666                                    if (status != DKIM_STAT_OK)
06667                                           return status;
06668 
06669                                    dkim->dkim_chunkstate = DKIM_CHUNKSTATE_BODY;
06670                                    if (p < end)
06671                                    {
06672                                           return dkim_body(dkim, p + 1,
06673                                                            end - p);
06674                                    }
06675                                    else
06676                                    {
06677                                           return DKIM_STAT_OK;
06678                                    }
06679                             }
06680 
06681                             dkim_dstring_catn(dkim->dkim_hdrbuf, CRLF, 2);
06682                             dkim->dkim_chunksm = 2;
06683                      }
06684                      else
06685                      {
06686                             dkim_dstring_cat1(dkim->dkim_hdrbuf, *p);
06687                             if (*p == '\r')
06688                                    dkim->dkim_chunksm = 1;
06689                      }
06690                      break;
06691 
06692                 case 1:
06693                      dkim_dstring_cat1(dkim->dkim_hdrbuf, *p);
06694                      if (*p == '\n')
06695                      {
06696                             if (dkim->dkim_chunkcrlf == DKIM_CRLF_UNKNOWN)
06697                                    dkim->dkim_chunkcrlf = DKIM_CRLF_CRLF;
06698 
06699                             /*
06700                             **  If this is a CRLF up front, change state
06701                             **  and write the rest as part of the body.
06702                             */
06703 
06704                             if (dkim->dkim_hhead == NULL &&
06705                                 dkim_dstring_len(dkim->dkim_hdrbuf) == 2)
06706                             {
06707                                    status = dkim_eoh(dkim);
06708                                    if (status != DKIM_STAT_OK)
06709                                           return status;
06710 
06711                                    dkim->dkim_chunkstate = DKIM_CHUNKSTATE_BODY;
06712                                    if (p < end)
06713                                    {
06714                                           return dkim_body(dkim, p + 1,
06715                                                            end - p);
06716                                    }
06717                                    else
06718                                    {
06719                                           return DKIM_STAT_OK;
06720                                    }
06721                             }
06722 
06723                             dkim->dkim_chunksm = 2;
06724                      }
06725                      else if (*p != '\r')
06726                      {
06727                             dkim->dkim_chunksm = 0;
06728                      }
06729                      break;
06730                      
06731                 case 2:
06732                      if (DKIM_ISLWSP(*p))
06733                      {
06734                             dkim_dstring_cat1(dkim->dkim_hdrbuf, *p);
06735                             dkim->dkim_chunksm = 0;
06736                             break;
06737                      }
06738                      else if (*p == '\r' &&
06739                               dkim->dkim_chunkcrlf == DKIM_CRLF_CRLF)
06740                      {
06741                             dkim->dkim_chunksm = 3;
06742                             break;
06743                      }
06744                      else if (*p != '\n' ||
06745                               dkim->dkim_chunkcrlf != DKIM_CRLF_LF)
06746                      {
06747                             status = dkim_header(dkim,
06748                                                  dkim_dstring_get(dkim->dkim_hdrbuf),
06749                                                  dkim_dstring_len(dkim->dkim_hdrbuf) - 2);
06750                             if (status != DKIM_STAT_OK &&
06751                                 !(status == DKIM_STAT_SYNTAX && bso))
06752                                    return status;
06753 
06754                             dkim_dstring_blank(dkim->dkim_hdrbuf);
06755                             dkim_dstring_cat1(dkim->dkim_hdrbuf, *p);
06756                             dkim->dkim_chunksm = 0;
06757                             break;
06758                      }
06759                      /* FALLTHROUGH */
06760                             
06761                 case 3:
06762                      if (*p == '\n')
06763                      {
06764                             if (dkim_dstring_len(dkim->dkim_hdrbuf) > 0)
06765                             {
06766                                    status = dkim_header(dkim,
06767                                                         dkim_dstring_get(dkim->dkim_hdrbuf),
06768                                                         dkim_dstring_len(dkim->dkim_hdrbuf) - 2);
06769                                    if (status != DKIM_STAT_OK &&
06770                                        !(status == DKIM_STAT_SYNTAX &&
06771                                          bso))
06772                                           return status;
06773                             }
06774 
06775                             status = dkim_eoh(dkim);
06776                             if (status != DKIM_STAT_OK)
06777                                    return status;
06778 
06779                             dkim->dkim_chunkstate = DKIM_CHUNKSTATE_BODY;
06780 
06781                             if (p < end)
06782                                    return dkim_body(dkim, p + 1, end - p);
06783                             else
06784                                    return DKIM_STAT_OK;
06785                      }
06786                      else
06787                      {
06788                             status = dkim_header(dkim,
06789                                                  dkim_dstring_get(dkim->dkim_hdrbuf),
06790                                                  dkim_dstring_len(dkim->dkim_hdrbuf) - 2);
06791                             if (status != DKIM_STAT_OK &&
06792                                 !(status == DKIM_STAT_SYNTAX && bso))
06793                                    return status;
06794 
06795                             dkim_dstring_blank(dkim->dkim_hdrbuf);
06796                             dkim_dstring_cat1(dkim->dkim_hdrbuf, '\r');
06797                             dkim_dstring_cat1(dkim->dkim_hdrbuf, *p);
06798                             dkim->dkim_chunksm = 0;
06799                      }
06800                      break;
06801 
06802                 default:
06803                      assert(0);
06804                      /* NOTREACHED */
06805               }
06806        }
06807 
06808        return DKIM_STAT_OK;
06809 }
06810 
06811 /*
06812 **  DKIM_MINBODY -- return number of bytes still expected
06813 **
06814 **  Parameters:
06815 **     dkim -- DKIM handle
06816 **
06817 **  Return value:
06818 **     0 -- all canonicalizations satisfied
06819 **     ULONG_MAX -- at least one canonicalization wants the whole message
06820 **     other -- bytes required to satisfy all canonicalizations
06821 */
06822 
06823 u_long
06824 dkim_minbody(DKIM *dkim)
06825 {
06826        assert(dkim != NULL);
06827 
06828        return dkim_canon_minbody(dkim);
06829 }
06830 
06831 /*
06832 **  DKIM_KEY_SYNTAX -- process a key record parameter set for valid syntax
06833 **
06834 **  Parameters:
06835 **     dkim -- DKIM context in which this is performed
06836 **     str -- string to be scanned
06837 **     len -- number of bytes available at "str"
06838 **
06839 **  Return value:
06840 **     A DKIM_STAT constant.
06841 */
06842 
06843 DKIM_STAT
06844 dkim_key_syntax(DKIM *dkim, u_char *str, size_t len)
06845 {
06846        return dkim_process_set(dkim, DKIM_SETTYPE_KEY, str, len, NULL, TRUE,
06847                                NULL);
06848 }
06849 
06850 /*
06851 **  DKIM_POLICY_SYNTAX -- process a policy record parameter set
06852 **                        for valid syntax
06853 **
06854 **  Parameters:
06855 **     dkim -- DKIM context in which this is performed
06856 **     str -- string to be scanned
06857 **     len -- number of bytes available at "str"
06858 **
06859 **  Return value:
06860 **     A DKIM_STAT constant.
06861 */
06862 
06863 DKIM_STAT
06864 dkim_policy_syntax(DKIM *dkim, u_char *str, size_t len)
06865 {
06866        return dkim_process_set(dkim, DKIM_SETTYPE_POLICY, str, len,
06867                                NULL, TRUE, NULL);
06868 }
06869 
06870 /*
06871 **  DKIM_SIG_SYNTAX -- process a signature parameter set for valid syntax
06872 **
06873 **  Parameters:
06874 **     dkim -- DKIM context in which this is performed
06875 **     str -- string to be scanned
06876 **     len -- number of bytes available at "str"
06877 **
06878 **  Return value:
06879 **     A DKIM_STAT constant.
06880 */
06881 
06882 DKIM_STAT
06883 dkim_sig_syntax(DKIM *dkim, u_char *str, size_t len)
06884 {
06885        return dkim_process_set(dkim, DKIM_SETTYPE_SIGNATURE, str, len,
06886                                NULL, TRUE, NULL);
06887 }
06888 
06889 /*
06890 **  DKIM_GETID -- retrieve "id" pointer from a handle
06891 **
06892 **  Parameters:
06893 **     dkim -- DKIM handle
06894 **
06895 **  Return value:
06896 **     The "id" pointer from inside the handle, stored when it was created.
06897 */
06898 
06899 const char *
06900 dkim_getid(DKIM *dkim)
06901 {
06902        assert(dkim != NULL);
06903 
06904        return dkim->dkim_id;
06905 }
06906 
06907 /*
06908 **  DKIM_GETSIGLIST -- retrieve the list of signatures
06909 **
06910 **  Parameters:
06911 **     dkim -- DKIM handle
06912 **     sigs -- pointer to a vector of DKIM_SIGINFO pointers (updated)
06913 **     nsigs -- pointer to an integer to receive the pointer count (updated)
06914 **
06915 **  Return value:
06916 **     A DKIM_STAT_* constant.
06917 */
06918 
06919 DKIM_STAT
06920 dkim_getsiglist(DKIM *dkim, DKIM_SIGINFO ***sigs, int *nsigs)
06921 {
06922        assert(dkim != NULL);
06923        assert(sigs != NULL);
06924        assert(nsigs != NULL);
06925 
06926        if (dkim->dkim_state < DKIM_STATE_EOH2)
06927               return DKIM_STAT_INVALID;
06928 
06929        *sigs = dkim->dkim_siglist;
06930        *nsigs = dkim->dkim_sigcount;
06931 
06932        return DKIM_STAT_OK;
06933 }
06934 
06935 /*
06936 **  DKIM_GETSIGNATURE -- retrieve the "final" signature
06937 **
06938 **  Parameters:
06939 **     dkim -- DKIM handle
06940 **
06941 **  Return value:
06942 **     Pointer to a DKIM_SIGINFO handle which is the one libopendkim will
06943 **     use to return a "final" result; NULL if none could be determined.
06944 */
06945 
06946 DKIM_SIGINFO *
06947 dkim_getsignature(DKIM *dkim)
06948 {
06949        assert(dkim != NULL);
06950 
06951        return dkim->dkim_signature;
06952 }
06953 
06954 /*
06955 **  DKIM_GETSIGHDR_D -- for signing operations, retrieve the complete signature
06956 **                      header, doing so dynamically
06957 **
06958 **  Parameters:
06959 **     dkim -- DKIM handle
06960 **     initial -- initial line width
06961 **     buf -- pointer to buffer containing the signature (returned)
06962 **     buflen -- number of bytes at "buf" (returned)
06963 **
06964 **  Return value:
06965 **     A DKIM_STAT_* constant.
06966 **
06967 **  Notes:
06968 **     Per RFC6376 Section 3.7, the signature header returned here does
06969 **     not contain a trailing CRLF.
06970 */
06971 
06972 DKIM_STAT
06973 dkim_getsighdr_d(DKIM *dkim, size_t initial, u_char **buf, size_t *buflen)
06974 {
06975        size_t len;
06976        char *ctx;
06977        char *pv;
06978        DKIM_SIGINFO *sig;
06979        struct dkim_dstring *tmpbuf;
06980 
06981        assert(dkim != NULL);
06982        assert(buf != NULL);
06983        assert(buflen != NULL);
06984 
06985        if (dkim->dkim_state != DKIM_STATE_EOM2 ||
06986            dkim->dkim_mode != DKIM_MODE_SIGN)
06987               return DKIM_STAT_INVALID;
06988 
06989 #define       DELIMITER     "\001"
06990 
06991        sig = dkim->dkim_signature;
06992        if (sig == NULL)
06993               sig = dkim->dkim_siglist[0];
06994 
06995        if ((sig->sig_flags & DKIM_SIGFLAG_KEYLOADED) == 0)
06996        {
06997               dkim_error(dkim, "private key load failure");
06998               return DKIM_STAT_INVALID;
06999        }
07000 
07001        tmpbuf = dkim_dstring_new(dkim, BUFRSZ, MAXBUFRSZ);
07002        if (tmpbuf == NULL)
07003        {
07004               dkim_error(dkim, "failed to allocate dynamic string");
07005               return DKIM_STAT_NORESOURCE;
07006        }
07007 
07008        if (dkim->dkim_hdrbuf == NULL)
07009        {
07010               dkim->dkim_hdrbuf = dkim_dstring_new(dkim, BUFRSZ, MAXBUFRSZ);
07011               if (dkim->dkim_hdrbuf == NULL)
07012               {
07013                      dkim_dstring_free(tmpbuf);
07014                      dkim_error(dkim, "failed to allocate dynamic string");
07015                      return DKIM_STAT_NORESOURCE;
07016               }
07017        }
07018        else
07019        {
07020               dkim_dstring_blank(dkim->dkim_hdrbuf);
07021        }
07022 
07023        /* compute and extract the signature header */
07024        len = dkim_gensighdr(dkim, sig, tmpbuf, DELIMITER);
07025        if (len == 0)
07026               return DKIM_STAT_INVALID;
07027 
07028        if (dkim->dkim_b64sig != NULL)
07029               dkim_dstring_cat(tmpbuf, dkim->dkim_b64sig);
07030 
07031        if (dkim->dkim_margin == 0)
07032        {
07033               _Bool first = TRUE;
07034 
07035               for (pv = strtok_r((char *) dkim_dstring_get(tmpbuf),
07036                                  DELIMITER, &ctx);
07037                    pv != NULL;
07038                    pv = strtok_r(NULL, DELIMITER, &ctx))
07039               {
07040                      if (!first)
07041                             dkim_dstring_cat1(dkim->dkim_hdrbuf, ' ');
07042 
07043                      dkim_dstring_cat(dkim->dkim_hdrbuf, (u_char *) pv);
07044 
07045                      first = FALSE;
07046               }
07047        }
07048        else
07049        {
07050               _Bool first = TRUE;
07051               _Bool forcewrap;
07052               int pvlen;
07053               int whichlen;
07054               char *p;
07055               char *q;
07056               char *end;
07057               char which[MAXTAGNAME + 1];
07058 
07059               len = initial;
07060               end = which + MAXTAGNAME;
07061 
07062               for (pv = strtok_r((char *) dkim_dstring_get(tmpbuf),
07063                                  DELIMITER, &ctx);
07064                    pv != NULL;
07065                    pv = strtok_r(NULL, DELIMITER, &ctx))
07066               {
07067                      for (p = pv, q = which; *p != '=' && q <= end; p++, q++)
07068                      {
07069                             *q = *p;
07070                             *(q + 1) = '\0';
07071                      }
07072 
07073                      whichlen = strlen(which);
07074 
07075                      /* force wrapping of "b=" ? */
07076 
07077                      forcewrap = FALSE;
07078                      if (sig->sig_keytype == DKIM_KEYTYPE_RSA)
07079                      {
07080                             u_int siglen;
07081 
07082                             siglen = BASE64SIZE(sig->sig_keybits / 8);
07083                             if (strcmp(which, "b") == 0 &&
07084                                 len + whichlen + siglen + 1 >= dkim->dkim_margin)
07085                                    forcewrap = TRUE;
07086                      }
07087 
07088                      pvlen = strlen(pv);
07089 
07090                      if (len == 0 || first)
07091                      {
07092                             dkim_dstring_catn(dkim->dkim_hdrbuf,
07093                                               (u_char *) pv,
07094                                               pvlen);
07095                             len += pvlen;
07096                             first = FALSE;
07097                      }
07098                      else if (forcewrap || len + pvlen > dkim->dkim_margin)
07099                      {
07100                             forcewrap = FALSE;
07101                             dkim_dstring_catn(dkim->dkim_hdrbuf,
07102                                               (u_char *) "\r\n\t", 3);
07103                             len = 8;
07104 
07105                             if (strcmp(which, "h") == 0)
07106                             {                    /* break at colons */
07107                                    _Bool ifirst = TRUE;
07108                                    int tmplen;
07109                                    char *tmp;
07110                                    char *ctx2;
07111 
07112                                    for (tmp = strtok_r(pv, ":", &ctx2);
07113                                         tmp != NULL;
07114                                         tmp = strtok_r(NULL, ":", &ctx2))
07115                                    {
07116                                           tmplen = strlen(tmp);
07117 
07118                                           if (ifirst)
07119                                           {
07120                                                  dkim_dstring_catn(dkim->dkim_hdrbuf,
07121                                                                    (u_char *) tmp,
07122                                                                    tmplen);
07123                                                  len += tmplen;
07124                                                  ifirst = FALSE;
07125                                           }
07126                                           else if (len + tmplen + 1 > dkim->dkim_margin)
07127                                           {
07128                                                  dkim_dstring_cat1(dkim->dkim_hdrbuf,
07129                                                                    ':');
07130                                                  len += 1;
07131                                                  dkim_dstring_catn(dkim->dkim_hdrbuf,
07132                                                                    (u_char *) "\r\n\t ",
07133                                                                    4);
07134                                                  len = 9;
07135                                                  dkim_dstring_catn(dkim->dkim_hdrbuf,
07136                                                                    (u_char *) tmp,
07137                                                                    tmplen);
07138                                                  len += tmplen;
07139                                           }
07140                                           else
07141                                           {
07142                                                  dkim_dstring_cat1(dkim->dkim_hdrbuf,
07143                                                                    ':');
07144                                                  len += 1;
07145                                                  dkim_dstring_catn(dkim->dkim_hdrbuf,
07146                                                                    (u_char *) tmp,
07147                                                                    tmplen);
07148                                                  len += tmplen;
07149                                           }
07150                                    }
07151 
07152                             }
07153                             else if (strcmp(which, "b") == 0 ||
07154                                      strcmp(which, "bh") == 0 ||
07155                                      strcmp(which, "z") == 0)
07156                             {                    /* break at margins */
07157                                    int offset;
07158                                    int n;
07159                                    char *x;
07160                                    char *y;
07161 
07162                                    offset = whichlen + 1;
07163 
07164                                    dkim_dstring_catn(dkim->dkim_hdrbuf,
07165                                                      (u_char *) which,
07166                                                      whichlen);
07167                                    dkim_dstring_cat1(dkim->dkim_hdrbuf,
07168                                                      '=');
07169 
07170                                    len += offset;
07171 
07172                                    dkim_dstring_cat1(dkim->dkim_hdrbuf,
07173                                                      *(pv + offset));
07174                                    len++;
07175 
07176                                    x = pv + offset + 1;
07177                                    y = pv + pvlen;
07178 
07179                                    while (x < y)
07180                                    {
07181                                           if (dkim->dkim_margin - len == 0)
07182                                           {
07183                                                  dkim_dstring_catn(dkim->dkim_hdrbuf,
07184                                                                    (u_char *) "\r\n\t ",
07185                                                                    4);
07186                                                  len = 9;
07187                                           }
07188 
07189                                           n = MIN(dkim->dkim_margin - len,
07190                                                   y - x);
07191                                           dkim_dstring_catn(dkim->dkim_hdrbuf,
07192                                                             (u_char *) x,
07193                                                             n);
07194                                           x += n;
07195                                           len += n;
07196                                           
07197                                    }
07198                             }
07199                             else
07200                             {                    /* break at delimiter */
07201                                    dkim_dstring_catn(dkim->dkim_hdrbuf,
07202                                                      (u_char *) pv,
07203                                                      pvlen);
07204                                    len += pvlen;
07205                             }
07206                      }
07207                      else
07208                      {
07209                             if (!first)
07210                             {
07211                                    dkim_dstring_cat1(dkim->dkim_hdrbuf,
07212                                                      ' ');
07213                                    len += 1;
07214                             }
07215 
07216                             first = FALSE;
07217                             dkim_dstring_catn(dkim->dkim_hdrbuf,
07218                                               (u_char *) pv,
07219                                               pvlen);
07220                             len += pvlen;
07221                      }
07222               }
07223        }
07224 
07225        *buf = dkim_dstring_get(dkim->dkim_hdrbuf);
07226        *buflen = dkim_dstring_len(dkim->dkim_hdrbuf);
07227 
07228        dkim_dstring_free(tmpbuf);
07229 
07230        return DKIM_STAT_OK;
07231 }
07232 
07233 /*
07234 **  DKIM_GETSIGHDR -- retrieve signature header into a user-provided buffer
07235 **
07236 **  Parameters:
07237 **     dkim -- libopendkim handle
07238 **     buf -- buffer into which to write
07239 **     buflen -- bytes available at "buf"
07240 **     initial -- width aleady consumed for the first line
07241 **
07242 **  Return value:
07243 **     A DKIM_STAT_* constant.
07244 */
07245 
07246 DKIM_STAT
07247 dkim_getsighdr(DKIM *dkim, u_char *buf, size_t buflen, size_t initial)
07248 {
07249        u_char *p;
07250        size_t len;
07251        DKIM_STAT status;
07252 
07253        assert(dkim != NULL);
07254        assert(buf != NULL);
07255        assert(buflen > 0);
07256 
07257        status = dkim_getsighdr_d(dkim, initial, &p, &len);
07258        if (status != DKIM_STAT_OK)
07259               return status;
07260 
07261        if (len > buflen)
07262        {
07263               dkim_error(dkim, "generated signature header too large");
07264               return DKIM_STAT_NORESOURCE;
07265        }
07266 
07267        strlcpy((char *) buf, (char *) p, buflen);
07268 
07269        return DKIM_STAT_OK;
07270 }
07271 
07272 /*
07273 **  DKIM_SIG_HDRSIGNED -- retrieve the header list from a signature
07274 **
07275 **  Parameters:
07276 **     sig -- DKIM_SIGINFO handle
07277 **     hdr -- header name to find
07278 **
07279 **  Return value:
07280 **     TRUE iff "sig" had a header list in it and the header "hdr"
07281 **     appeared in that list.
07282 */
07283 
07284 _Bool
07285 dkim_sig_hdrsigned(DKIM_SIGINFO *sig, u_char *hdr)
07286 {
07287        size_t len;
07288        u_char *c1 = NULL;
07289        u_char *c2 = NULL;
07290        u_char *start;
07291        u_char *p;
07292        u_char *hdrlist;
07293 
07294        assert(sig != NULL);
07295        assert(hdr != NULL);
07296 
07297        hdrlist = dkim_param_get(sig->sig_taglist, (u_char *) "h");
07298        if (hdrlist == NULL)
07299               return FALSE;
07300 
07301        for (p = hdrlist; ; p++)
07302        {
07303               len = -1;
07304 
07305               if (*p == ':')
07306               {
07307                      c1 = c2;
07308                      c2 = p;
07309 
07310                      if (c1 == NULL)
07311                      {
07312                             start = hdrlist;
07313                             len = c2 - start; 
07314                      }
07315                      else
07316                      {
07317                             start = c1 + 1;
07318                             len = c2 - c1 - 1;
07319                      }
07320               }
07321               else if (*p == '\0')
07322               {
07323                      if (c2 != NULL)
07324                      {
07325                             start = c2 + 1;
07326                             len = p - c2 - 1;
07327 
07328                             if (strncasecmp((char *) hdr, (char *) start,
07329                                             len) == 0)
07330                                    return TRUE;
07331                      }
07332                      else
07333                      {
07334                             if (strcasecmp((char *) hdr,
07335                                            (char *) hdrlist) == 0)
07336                                    return TRUE;
07337                      }
07338 
07339                      break;
07340               }
07341 
07342               if (len != -1)
07343               {
07344                      if (strncasecmp((char *) hdr, (char *) start,
07345                                      len) == 0)
07346                             return TRUE;
07347               }
07348        }
07349 
07350        return FALSE;
07351 }
07352 
07353 /*
07354 **  DKIM_SIG_GETDNSSEC -- retrieve DNSSEC results for a signature
07355 **
07356 **  Parameters:
07357 **     sig -- DKIM_SIGINFO handle
07358 **
07359 **  Return value:
07360 **     A DKIM_DNSSEC_* constant.
07361 */
07362 
07363 int
07364 dkim_sig_getdnssec(DKIM_SIGINFO *sig)
07365 {
07366        assert(sig != NULL);
07367 
07368        return sig->sig_dnssec_key;
07369 }
07370 
07371 /*
07372 **  DKIM_SIG_GETREPORTINFO -- retrieve reporting information for a signature
07373 **
07374 **  Parameters:
07375 **     dkim -- DKIM handle
07376 **     sig -- DKIM_SIGINFO handle
07377 **     hfd -- descriptor to canonicalized header (or NULL) (returned)
07378 **     bfd -- descriptor to canonicalized body (or NULL) (returned)
07379 **     addr -- address buffer (or NULL)
07380 **     addrlen -- size of addr
07381 **     opts -- options buffer (or NULL)
07382 **     optslen -- size of opts
07383 **     smtp -- SMTP reply text buffer (or NULL)
07384 **     smtplen -- size of smtp
07385 **     pct -- requested reporting percentage (or NULL)
07386 **
07387 **  Return value:
07388 **     A DKIM_STAT_* constant.
07389 */
07390 
07391 DKIM_STAT
07392 dkim_sig_getreportinfo(DKIM *dkim, DKIM_SIGINFO *sig,
07393                        int *hfd, int *bfd,
07394                        u_char *addr, size_t addrlen,
07395                        u_char *opts, size_t optslen,
07396                        u_char *smtp, size_t smtplen,
07397                        u_int *pct)
07398 {
07399        DKIM_STAT status;
07400        u_char *p;
07401        char *sdomain;
07402        DKIM_SET *set;
07403        struct timeval timeout;
07404        unsigned char buf[BUFRSZ];
07405 
07406        assert(dkim != NULL);
07407        assert(sig != NULL);
07408 
07409        if (dkim->dkim_state != DKIM_STATE_EOM2 ||
07410            dkim->dkim_mode != DKIM_MODE_VERIFY)
07411               return DKIM_STAT_INVALID;
07412 
07413        sdomain = dkim_sig_getdomain(sig);
07414 
07415        /* see if the signature had an "r=y" tag */
07416        set = sig->sig_taglist;
07417        if (set == NULL)
07418               return DKIM_STAT_INTERNAL;
07419 
07420        p = dkim_param_get(set, (u_char *) "r");
07421        if (p == NULL || p[0] != 'y' || p[1] != '\0')
07422        {
07423               if (addr != NULL)
07424                      addr[0] = '\0';
07425               if (opts != NULL)
07426                      opts[0] = '\0';
07427               if (smtp != NULL)
07428                      smtp[0] = '\0';
07429               if (pct != NULL)
07430                      *pct = (u_int) -1;
07431 
07432               return DKIM_STAT_OK;
07433        }
07434 
07435        /* see if we've grabbed this set already */
07436        for (set = dkim_set_first(dkim, DKIM_SETTYPE_SIGREPORT);
07437             set != NULL;
07438             set = dkim_set_next(set, DKIM_SETTYPE_SIGREPORT))
07439        {
07440               if (set->set_name != NULL &&
07441                   strcasecmp(set->set_name, sdomain) == 0)
07442                      break;
07443        }
07444 
07445        /* guess not; go to the DNS to get reporting parameters */
07446        if (set == NULL)
07447        {
07448               timeout.tv_sec = dkim->dkim_timeout;
07449               timeout.tv_usec = 0;
07450 
07451               memset(buf, '\0', sizeof buf);
07452               status = dkim_repinfo(dkim, sig, &timeout, buf, sizeof buf);
07453               if (status != DKIM_STAT_OK)
07454                      return status;
07455               if (buf[0] == '\0')
07456                      return DKIM_STAT_OK;
07457 
07458               status = dkim_process_set(dkim, DKIM_SETTYPE_SIGREPORT,
07459                                         buf, strlen(buf), NULL, FALSE,
07460                                         sdomain);
07461               if (status != DKIM_STAT_OK)
07462                      return status;
07463 
07464               for (set = dkim_set_first(dkim, DKIM_SETTYPE_SIGREPORT);
07465                    set != NULL;
07466                    set = dkim_set_next(set, DKIM_SETTYPE_SIGREPORT))
07467               {
07468                      if (set->set_name != NULL &&
07469                          strcasecmp(set->set_name, sdomain) == 0)
07470                             break;
07471               }
07472 
07473               assert(set != NULL);
07474        }
07475 
07476        if (addr != NULL)
07477        {
07478               p = dkim_param_get(set, (u_char *) "ra");
07479               if (p != NULL)
07480               {
07481                      memset(addr, '\0', addrlen);
07482                      (void) dkim_qp_decode(p, addr, addrlen - 1);
07483                      p = (u_char *) strchr((char *) addr, '@');
07484                      if (p != NULL)
07485                             *p = '\0';
07486               }
07487        }
07488 
07489        if (opts != NULL)
07490        {
07491               p = dkim_param_get(set, (u_char *) "ro");
07492               if (p != NULL)
07493                      strlcpy((char *) opts, (char *) p, optslen);
07494        }
07495 
07496        if (smtp != NULL)
07497        {
07498               p = dkim_param_get(set, (u_char *) "rs");
07499               if (p != NULL)
07500               {
07501                      memset(smtp, '\0', smtplen);
07502                      (void) dkim_qp_decode(p, smtp, smtplen - 1);
07503               }
07504        }
07505 
07506        if (pct != NULL)
07507        {
07508               p = dkim_param_get(set, (u_char *) "rp");
07509               if (p != NULL)
07510               {
07511                      u_int out;
07512                      char *q;
07513 
07514                      out = strtoul((char *) p, &q, 10);
07515                      if (*q == '\0')
07516                             *pct = out;
07517               }
07518        }
07519 
07520        if (sig->sig_hdrcanon != NULL)
07521        {
07522               switch (sig->sig_hashtype)
07523               {
07524 #ifdef USE_GNUTLS
07525                 case DKIM_HASHTYPE_SHA1:
07526                 case DKIM_HASHTYPE_SHA256:
07527                 {
07528                      struct dkim_sha *sha;
07529 
07530                      sha = (struct dkim_sha *) sig->sig_hdrcanon->canon_hash;
07531                      if (hfd != NULL)
07532                             *hfd = sha->sha_tmpfd;
07533 
07534                      if (bfd != NULL)
07535                      {
07536                             sha = (struct dkim_sha *) sig->sig_bodycanon->canon_hash;
07537                             *bfd = sha->sha_tmpfd;
07538                      }
07539 
07540                      break;
07541                 }
07542 #else /* USE_GNUTLS */
07543                 case DKIM_HASHTYPE_SHA1:
07544                 {
07545                      struct dkim_sha1 *sha1;
07546 
07547                      sha1 = (struct dkim_sha1 *) sig->sig_hdrcanon->canon_hash;
07548                      if (hfd != NULL)
07549                             *hfd = sha1->sha1_tmpfd;
07550 
07551                      if (bfd != NULL)
07552                      {
07553                             sha1 = (struct dkim_sha1 *) sig->sig_bodycanon->canon_hash;
07554                             *bfd = sha1->sha1_tmpfd;
07555                      }
07556 
07557                      break;
07558                 }
07559 
07560 # ifdef HAVE_SHA256
07561                 case DKIM_HASHTYPE_SHA256:
07562                 {
07563                      struct dkim_sha256 *sha256;
07564 
07565                      sha256 = (struct dkim_sha256 *) sig->sig_hdrcanon->canon_hash;
07566                      if (hfd != NULL)
07567                             *hfd = sha256->sha256_tmpfd;
07568 
07569                      if (bfd != NULL)
07570                      {
07571                             sha256 = (struct dkim_sha256 *) sig->sig_bodycanon->canon_hash;
07572                             *bfd = sha256->sha256_tmpfd;
07573                      }
07574 
07575                      break;
07576                 }
07577 # endif /* HAVE_SHA256 */
07578 #endif /* USE_GNUTLS */
07579 
07580                 default:
07581                      assert(0);
07582               }
07583        }
07584 
07585        return DKIM_STAT_OK;
07586 }
07587 
07588 /*
07589 **  DKIM_SIG_GETIDENTITY -- retrieve identity of the signer
07590 **
07591 **  Parameters:
07592 **     dkim -- DKIM handle
07593 **     sig -- DKIM_SIGINFO handle (or NULL to choose final one)
07594 **     val -- destination buffer
07595 **     vallen -- size of destination buffer
07596 **
07597 **  Return value:
07598 **     A DKIM_STAT_* constant.
07599 */
07600 
07601 DKIM_STAT
07602 dkim_sig_getidentity(DKIM *dkim, DKIM_SIGINFO *sig, u_char *val, size_t vallen)
07603 {
07604        int len;
07605        char *param;
07606        struct dkim_set *set;
07607 
07608        assert(val != NULL);
07609        assert(vallen != 0);
07610 
07611        if (sig == NULL)
07612        {
07613               if (dkim == NULL)
07614                      return DKIM_STAT_INVALID;
07615 
07616               sig = dkim->dkim_signature;
07617               if (sig == NULL)
07618                      return DKIM_STAT_INVALID;
07619        }
07620 
07621        set = sig->sig_taglist;
07622 
07623        param = (char *) dkim_param_get(set, (u_char *) "i");
07624        if (param == NULL)
07625        {
07626               param = (char *) dkim_param_get(set, (u_char *) "d");
07627               if (param == NULL)
07628                      return DKIM_STAT_INTERNAL;
07629 
07630               len = snprintf((char *) val, vallen, "@%s", param);
07631 
07632               return (len < vallen ? DKIM_STAT_OK : DKIM_STAT_NORESOURCE);
07633        }
07634        else
07635        {
07636               len = dkim_qp_decode((u_char *) param, (u_char *) val,
07637                                    vallen - 1);
07638 
07639               if (len == -1)
07640               {
07641                      return DKIM_STAT_SYNTAX;
07642               }
07643               else if (len >= vallen)
07644               {
07645                      return DKIM_STAT_NORESOURCE;
07646               }
07647               else
07648               {
07649                      val[len] = '\0';
07650                      return DKIM_STAT_OK;
07651               }
07652        }
07653 }
07654 
07655 /*
07656 **  DKIM_SIG_GETCANONLEN -- return canonicalized and total body lengths
07657 **
07658 **  Parameters:
07659 **     dkim -- DKIM handle
07660 **     sig -- DKIM_SIGINFO handle
07661 **     msglen -- total body length (returned)
07662 **     canonlen -- total canonicalized length (returned)
07663 **     signlen -- maximum signed length (returned)
07664 **
07665 **  Return value:
07666 **     A DKIM_STAT_* constant.
07667 */
07668 
07669 DKIM_STAT
07670 dkim_sig_getcanonlen(DKIM *dkim, DKIM_SIGINFO *sig, ssize_t *msglen,
07671                      ssize_t *canonlen, ssize_t *signlen)
07672 {
07673        assert(dkim != NULL);
07674        assert(sig != NULL);
07675 
07676        if (msglen != NULL)
07677               *msglen = dkim->dkim_bodylen;
07678 
07679        if (canonlen != NULL)
07680        {
07681               if (sig->sig_bodycanon == NULL)
07682                      return DKIM_STAT_INTERNAL;
07683               *canonlen = sig->sig_bodycanon->canon_wrote;
07684        }
07685 
07686        if (signlen != NULL)
07687        {
07688               if (sig->sig_bodycanon == NULL)
07689                      return DKIM_STAT_INTERNAL;
07690               *signlen = sig->sig_bodycanon->canon_length;
07691        }
07692 
07693        return DKIM_STAT_OK;
07694 }
07695 
07696 /*
07697 **  DKIM_SIG_GETFLAGS -- retreive signature handle flags
07698 **
07699 **  Parameters:
07700 **     sig -- DKIM_SIGINFO handle
07701 **
07702 **  Return value:
07703 **     An unsigned integer which is a bitwise-OR of the DKIM_SIGFLAG_*
07704 **     constants currently set in the provided handle.
07705 */
07706 
07707 unsigned int
07708 dkim_sig_getflags(DKIM_SIGINFO *sig)
07709 {
07710        assert(sig != NULL);
07711 
07712        return sig->sig_flags;
07713 }
07714 
07715 /*
07716 **  DKIM_SIG_GETBH -- retreive signature handle "bh" test state
07717 **
07718 **  Parameters:
07719 **     sig -- DKIM_SIGINFO handle
07720 **
07721 **  Return value:
07722 **     An integer that is one of the DKIM_SIGBH_* constants
07723 **     indicating the current state of "bh" evaluation of the signature.
07724 */
07725 
07726 int
07727 dkim_sig_getbh(DKIM_SIGINFO *sig)
07728 {
07729        assert(sig != NULL);
07730 
07731        return sig->sig_bh;
07732 }
07733 
07734 /*
07735 **  DKIM_SIG_GETKEYSIZE -- retrieve key size (in bits) when verifying
07736 **
07737 **  Parameters:
07738 **     sig -- DKIM_SIGINFO handle
07739 **     bits -- number of bits in the key (returned)
07740 **
07741 **  Return value:
07742 **     A DKIM_STAT_* constant.
07743 */
07744 
07745 DKIM_STAT
07746 dkim_sig_getkeysize(DKIM_SIGINFO *sig, unsigned int *bits)
07747 {
07748        assert(sig != NULL);
07749        assert(bits != NULL);
07750 
07751        if (sig->sig_keybits == 0)
07752               return DKIM_STAT_INVALID;
07753 
07754        *bits = sig->sig_keybits;
07755 
07756        return DKIM_STAT_OK;
07757 }
07758 
07759 /*
07760 **  DKIM_SIG_GETSIGNALG -- retrieve signature algorithm when verifying
07761 **
07762 **  Parameters:
07763 **     sig -- DKIM_SIGINFO handle
07764 **     alg -- signature algorithm used (returned)
07765 **
07766 **  Return value:
07767 **     A DKIM_STAT_* constant.
07768 */
07769 
07770 DKIM_STAT
07771 dkim_sig_getsignalg(DKIM_SIGINFO *sig, dkim_alg_t *alg)
07772 {
07773        assert(sig != NULL);
07774        assert(alg != NULL);
07775 
07776        *alg = sig->sig_signalg;
07777 
07778        return DKIM_STAT_OK;
07779 }
07780 
07781 /*
07782 **  DKIM_SIG_GETSIGNTIME -- retrieve signature timestamp
07783 **
07784 **  Parameters:
07785 **     sig -- DKIM_SIGINFO handle
07786 **     when -- signature timestamp (returned)
07787 **
07788 **  Return value:
07789 **     A DKIM_STAT_* constant.
07790 */
07791 
07792 DKIM_STAT
07793 dkim_sig_getsigntime(DKIM_SIGINFO *sig, uint64_t *when)
07794 {
07795        assert(sig != NULL);
07796        assert(when != NULL);
07797 
07798        if (sig->sig_timestamp == 0)
07799               return DKIM_STAT_INVALID;
07800 
07801        *when = sig->sig_timestamp;
07802 
07803        return DKIM_STAT_OK;
07804 }
07805 
07806 /*
07807 **  DKIM_SIG_GETCANONS -- retrieve canonicalizations used when signing
07808 **
07809 **  Parameters:
07810 **     sig -- DKIM_SIGINFO handle from which to retrieve canonicalizations
07811 **     hdr -- Pointer to a dkim_canon_t where the header canonicalization
07812 **             should be stored
07813 **     body -- Pointer to a dkim_canon_t where the body canonicalization
07814 **              should be stored
07815 **
07816 **  Return value:
07817 **     A DKIM_STAT_* constant.
07818 */
07819 
07820 DKIM_STAT
07821 dkim_sig_getcanons(DKIM_SIGINFO *sig, dkim_canon_t *hdr, dkim_canon_t *body)
07822 {
07823        assert(sig != NULL);
07824 
07825        if (hdr != NULL)
07826               *hdr = sig->sig_hdrcanonalg;
07827        if (body != NULL)
07828               *body = sig->sig_bodycanonalg;
07829 
07830        return DKIM_STAT_OK;
07831 }
07832 
07833 /*
07834 **  DKIM_GET_SIGNER -- get DKIM signature's signer
07835 **
07836 **  Parameters:
07837 **     dkim -- DKIM signing handle
07838 **
07839 **  Parameters:
07840 **     Pointer to a buffer containing the signer previously requested,
07841 **     or NULL if none.
07842 */
07843 
07844 const unsigned char *
07845 dkim_get_signer(DKIM *dkim)
07846 {
07847        assert(dkim != NULL);
07848 
07849        return dkim->dkim_signer;
07850 }
07851 
07852 /*
07853 **  DKIM_SET_SIGNER -- set DKIM signature's signer
07854 **
07855 **  Parameters:
07856 **     dkim -- DKIM signing handle
07857 **     signer -- signer to store
07858 **
07859 **  Parameters:
07860 **     A DKIM_STAT_* constant.
07861 */
07862 
07863 DKIM_STAT
07864 dkim_set_signer(DKIM *dkim, const unsigned char *signer)
07865 {
07866        assert(dkim != NULL);
07867        assert(signer != NULL);
07868 
07869        if (dkim->dkim_mode != DKIM_MODE_SIGN)
07870               return DKIM_STAT_INVALID;
07871 
07872        if (dkim->dkim_signer == NULL)
07873        {
07874               dkim->dkim_signer = DKIM_MALLOC(dkim, MAXADDRESS + 1);
07875               if (dkim->dkim_signer == NULL)
07876               {
07877                      dkim_error(dkim, "unable to allocate %d byte(s)",
07878                                 MAXADDRESS + 1);
07879                      return DKIM_STAT_NORESOURCE;
07880               }
07881        }
07882 
07883        strlcpy((char *) dkim->dkim_signer, (char *) signer, MAXADDRESS + 1);
07884 
07885        return DKIM_STAT_OK;
07886 }
07887 
07888 /*
07889 **  DKIM_GETERROR -- return any stored error string from within the DKIM
07890 **                   context handle
07891 **
07892 **  Parameters:
07893 **     dkim -- DKIM handle from which to retrieve an error string
07894 **
07895 **  Return value:
07896 **     A pointer to the stored string, or NULL if none was stored.
07897 */
07898 
07899 const char *
07900 dkim_geterror(DKIM *dkim)
07901 {
07902        assert(dkim != NULL);
07903 
07904        return (const char *) dkim->dkim_error;
07905 }
07906 
07907 /*
07908 **  DKIM_GETPARTIAL -- return if the DKIM handle is to be signed using
07909 **                     the bodylength tag (l=)
07910 **
07911 **  Parameters:
07912 **      dkim -- DKIM handle
07913 **
07914 **  Return value:
07915 **      True iff the signature is to include a body length tag
07916 */
07917 
07918 _Bool
07919 dkim_getpartial(DKIM *dkim)
07920 {
07921        assert(dkim != NULL);
07922 
07923        return dkim->dkim_partial;
07924 }
07925 
07926 /*
07927 **  DKIM_SETPARTIAL -- set the DKIM handle to sign using the DKIM body length
07928 **                     tag (l=)
07929 **
07930 **  Parameters:
07931 **      dkim -- DKIM handle
07932 **      value -- new Boolean value
07933 **
07934 **  Return value:
07935 **      DKIM_STAT_INVALID -- "dkim" referenced a verification handle
07936 **      DKIM_STAT_OK -- otherwise
07937 */
07938 
07939 DKIM_STAT
07940 dkim_setpartial(DKIM *dkim, _Bool value)
07941 {
07942        assert(dkim != NULL);
07943 
07944        if (dkim->dkim_mode != DKIM_MODE_SIGN)
07945               return DKIM_STAT_INVALID;
07946 
07947        dkim->dkim_partial = value;
07948 
07949        return DKIM_STAT_OK;
07950 }
07951 
07952 /*
07953 **  DKIM_SET_MARGIN -- set the margin to use when generating signatures
07954 **
07955 **  Parameters:
07956 **      dkim -- DKIM handle
07957 **      value -- new margin value
07958 **
07959 **  Return value:
07960 **      DKIM_STAT_INVALID -- "dkim" referenced a verification handle,
07961 **                          "value" was negative, or this is being called
07962 **                          after dkim_eom() completed
07963 **      DKIM_STAT_OK -- otherwise
07964 */
07965 
07966 DKIM_STAT
07967 dkim_set_margin(DKIM *dkim, int value)
07968 {
07969        assert(dkim != NULL);
07970 
07971        if (dkim->dkim_mode != DKIM_MODE_SIGN || value < 0 ||
07972            dkim->dkim_state >= DKIM_STATE_EOM2)
07973               return DKIM_STAT_INVALID;
07974 
07975        dkim->dkim_margin = (size_t) value;
07976 
07977        return DKIM_STAT_OK;
07978 }
07979 
07980 /*
07981 **  DKIM_GETRESULTSTR -- translate a DKIM_STAT_* constant to a string
07982 **
07983 **  Parameters:
07984 **     result -- DKIM_STAT_* constant to translate
07985 **
07986 **  Return value:
07987 **     Pointer to a text describing "result", or NULL if none exists
07988 */
07989 
07990 const char *
07991 dkim_getresultstr(DKIM_STAT result)
07992 {
07993        return dkim_code_to_name(results, result);
07994 }
07995 
07996 /*
07997 **  DKIM_GETPRESULT -- retrieve policy result
07998 **
07999 **  Parameters:
08000 **     dkim -- DKIM handle from which to get policy result
08001 **
08002 **  Return value:
08003 **     DKIM policy check result.
08004 */
08005 
08006 int
08007 dkim_getpresult(DKIM *dkim)
08008 {
08009        assert(dkim != NULL);
08010 
08011        return dkim->dkim_presult;
08012 }
08013 
08014 /*
08015 **  DKIM_GETPRESULTSTR -- retrieve policy result string
08016 **
08017 **  Parameters:
08018 **     presult -- policy result code to translate
08019 **
08020 **  Return value:
08021 **     Pointer to text that describes "presult".
08022 */
08023 
08024 const char *
08025 dkim_getpresultstr(int presult)
08026 {
08027        return dkim_code_to_name(policyresults, presult);
08028 }
08029 
08030 /*
08031 **  DKIM_GETPOLICYSTR -- retrieve policy string
08032 **
08033 **  Parameters:
08034 **     policy -- policy code to translate
08035 **
08036 **  Return value:
08037 **     Pointer to text that describes "policy".
08038 */
08039 
08040 const char *
08041 dkim_getpolicystr(int policy)
08042 {
08043        return dkim_code_to_name(policies, policy);
08044 }
08045 
08046 /*
08047 **  DKIM_SET_DNS_CALLBACK -- set the DNS wait callback
08048 **
08049 **  Parameters:
08050 **     libopendkim -- DKIM library handle
08051 **     func -- function to call; should take an opaque context pointer
08052 **     interval -- how often to call back
08053 **
08054 **  Return value:
08055 **     DKIM_STAT_OK -- success
08056 **     DKIM_STAT_INVALID -- invalid use
08057 **     DKIM_STAT_NOTIMPLEMENT -- underlying resolver doesn't support callbacks
08058 */
08059 
08060 DKIM_STAT
08061 dkim_set_dns_callback(DKIM_LIB *libopendkim, void (*func)(const void *context),
08062                       unsigned int interval)
08063 {
08064        assert(libopendkim != NULL);
08065 
08066        if (func != NULL && interval == 0)
08067               return DKIM_STAT_INVALID;
08068 
08069        libopendkim->dkiml_dns_callback = func;
08070        libopendkim->dkiml_callback_int = interval;
08071 
08072        return DKIM_STAT_OK;
08073 }
08074 
08075 /*
08076 **  DKIM_SET_USER_CONTEXT -- set user context pointer
08077 **
08078 **  Parameters:
08079 **     dkim -- DKIM handle
08080 **     ctx -- opaque context pointer
08081 **
08082 **  Return value:
08083 **     DKIM_STAT_OK
08084 */
08085 
08086 DKIM_STAT
08087 dkim_set_user_context(DKIM *dkim, void *ctx)
08088 {
08089        assert(dkim != NULL);
08090 
08091        dkim->dkim_user_context = (const void *) ctx;
08092 
08093        return DKIM_STAT_OK;
08094 }
08095 
08096 /*
08097 **  DKIM_GET_USER_CONTEXT -- get user context pointer
08098 **
08099 **  Parameters:
08100 **     dkim -- DKIM handle
08101 **
08102 **  Return value:
08103 **     User context associated with a DKIM handle
08104 */
08105 
08106 void *
08107 dkim_get_user_context(DKIM *dkim)
08108 {
08109        assert(dkim != NULL);
08110 
08111        return (void *) dkim->dkim_user_context;
08112 }
08113 
08114 /*
08115 **  DKIM_GETMODE -- return the mode (signing, verifying, etc.) of a handle
08116 **
08117 **  Parameters:
08118 **     dkim -- DKIM handle
08119 **
08120 **  Return value:
08121 **     A DKIM_MODE_* constant.
08122 */
08123 
08124 int
08125 dkim_getmode(DKIM *dkim)
08126 {
08127        assert(dkim != NULL);
08128 
08129        return dkim->dkim_mode;
08130 }
08131 
08132 /*
08133 **  DKIM_GETDOMAIN -- retrieve policy domain from a DKIM context
08134 **
08135 **  Parameters:
08136 **     dkim -- DKIM handle
08137 **
08138 **  Return value:
08139 **     Pointer to the domain used for policy checking or NULL if no domain
08140 **     could be determined.
08141 */
08142 
08143 u_char *
08144 dkim_getdomain(DKIM *dkim)
08145 {
08146        assert(dkim != NULL);
08147 
08148        return dkim->dkim_domain;
08149 }
08150 
08151 /*
08152 **  DKIM_GETUSER -- retrieve sending user (local-part) from a DKIM context
08153 **
08154 **  Parameters:
08155 **     dkim -- DKIM handle
08156 **
08157 **  Return value:
08158 **     Pointer to the apparent sending user (local-part) or NULL if not known.
08159 */
08160 
08161 u_char *
08162 dkim_getuser(DKIM *dkim)
08163 {
08164        assert(dkim != NULL);
08165 
08166        return dkim->dkim_user;
08167 }
08168 
08169 /*
08170 **  DKIM_SET_KEY_LOOKUP -- set the key lookup function
08171 **
08172 **  Parameters:
08173 **     libopendkim -- DKIM library handle
08174 **     func -- function to call
08175 **
08176 **  Return value:
08177 **     DKIM_STAT_OK
08178 */
08179 
08180 DKIM_STAT
08181 dkim_set_key_lookup(DKIM_LIB *libopendkim,
08182                     DKIM_STAT (*func)(DKIM *dkim, DKIM_SIGINFO *sig,
08183                                       u_char *buf, size_t buflen))
08184 {
08185        assert(libopendkim != NULL);
08186 
08187        libopendkim->dkiml_key_lookup = func;
08188 
08189        return DKIM_STAT_OK;
08190 }
08191 
08192 /*
08193 **  DKIM_SET_POLICY_LOOKUP -- set the policy lookup function
08194 **
08195 **  Parameters:
08196 **     libopendkim -- DKIM library handle
08197 **     func -- function to call
08198 **
08199 **  Return value:
08200 **     DKIM_STAT_OK
08201 */
08202 
08203 DKIM_STAT
08204 dkim_set_policy_lookup(DKIM_LIB *libopendkim,
08205                        int (*func)(DKIM *dkim, u_char *query, _Bool excheck,
08206                                    u_char *buf, size_t buflen, int *qstat))
08207 {
08208        assert(libopendkim != NULL);
08209 
08210        libopendkim->dkiml_policy_lookup = func;
08211 
08212        return DKIM_STAT_OK;
08213 }
08214 
08215 /*
08216 **  DKIM_SET_SIGNATURE_HANDLE -- set the user handle allocation function
08217 **
08218 **  Parameters:
08219 **     libopendkim -- DKIM library handle
08220 **     func -- function to call
08221 **
08222 **  Return value:
08223 **     DKIM_STAT_OK -- success
08224 */
08225 
08226 DKIM_STAT
08227 dkim_set_signature_handle(DKIM_LIB *libopendkim, void * (*func)(void *closure))
08228 {
08229        assert(libopendkim != NULL);
08230 
08231        libopendkim->dkiml_sig_handle = func;
08232 
08233        return DKIM_STAT_OK;
08234 }
08235 
08236 /*
08237 **  DKIM_SET_SIGNATURE_HANDLE_FREE -- set the user handle deallocation function
08238 **
08239 **  Parameters:
08240 **     libopendkim -- DKIM library handle
08241 **     func -- function to call
08242 **
08243 **  Return value:
08244 **     DKIM_STAT_OK
08245 */
08246 
08247 DKIM_STAT
08248 dkim_set_signature_handle_free(DKIM_LIB *libopendkim,
08249                                void (*func)(void *closure, void *user))
08250 {
08251        assert(libopendkim != NULL);
08252 
08253        libopendkim->dkiml_sig_handle_free = func;
08254 
08255        return DKIM_STAT_OK;
08256 }
08257 
08258 /*
08259 **  DKIM_SET_SIGNATURE_TAGVALUES -- set the user handle population function
08260 **
08261 **  Parameters:
08262 **     libopendkim -- DKIM library handle
08263 **     func -- function to call
08264 **
08265 **  Return value:
08266 **     DKIM_STAT_OK
08267 */
08268 
08269 DKIM_STAT
08270 dkim_set_signature_tagvalues(DKIM_LIB *libopendkim, void (*func)(void *user,
08271                                                                  dkim_param_t pcode,
08272                                                                  const u_char *param,
08273                                                                  const u_char *value))
08274 {
08275        assert(libopendkim != NULL);
08276 
08277        libopendkim->dkiml_sig_tagvalues = func;
08278 
08279        return DKIM_STAT_OK;
08280 }
08281 
08282 /*
08283 **  DKIM_SET_PRESCREEN -- set the user prescreen function
08284 **
08285 **  Parameters:
08286 **     libopendkim -- DKIM library handle
08287 **     func -- function to call
08288 **
08289 **  Return value:
08290 **     DKIM_STAT_OK
08291 */
08292 
08293 DKIM_STAT
08294 dkim_set_prescreen(DKIM_LIB *libopendkim, DKIM_CBSTAT (*func)(DKIM *dkim,
08295                                                               DKIM_SIGINFO **sigs,
08296                                                               int nsigs))
08297 {
08298        assert(libopendkim != NULL);
08299 
08300        libopendkim->dkiml_prescreen = func;
08301 
08302        return DKIM_STAT_OK;
08303 }
08304 
08305 /*
08306 **  DKIM_SET_FINAL -- set the user final scan function
08307 **
08308 **  Parameters:
08309 **     libopendkim -- DKIM library handle
08310 **     func -- function to call
08311 **
08312 **  Return value:
08313 **     DKIM_STAT_OK
08314 */
08315 
08316 DKIM_STAT
08317 dkim_set_final(DKIM_LIB *libopendkim, DKIM_CBSTAT (*func)(DKIM *dkim,
08318                                                           DKIM_SIGINFO **sigs,
08319                                                           int nsigs))
08320 {
08321        assert(libopendkim != NULL);
08322 
08323        libopendkim->dkiml_final = func;
08324 
08325        return DKIM_STAT_OK;
08326 }
08327 
08328 /*
08329 **  DKIM_SIG_GETCONTEXT -- retrieve user-provided context from a DKIM_SIGINFO
08330 **
08331 **  Parameters:
08332 **     siginfo -- pointer to a DKIM_SIGINFO from which to extract context
08333 **
08334 **  Return value:
08335 **     Pointer to the user context provided by an earlier call to the
08336 **     handle allocator (see above), or NULL if none was ever set.
08337 */
08338 
08339 void *
08340 dkim_sig_getcontext(DKIM_SIGINFO *siginfo)
08341 {
08342        assert(siginfo != NULL);
08343 
08344        return siginfo->sig_context;
08345 }
08346 
08347 /*
08348 **  DKIM_SIG_GETSELECTOR -- retrieve selector from a DKIM_SIGINFO
08349 **
08350 **  Parameters:
08351 **     siginfo -- pointer to a DKIM_SIGINFO from which to extract the selector
08352 **
08353 **  Return value:
08354 **     Pointer to the selector associated with the DKIM_SIGINFO.
08355 */
08356 
08357 unsigned char *
08358 dkim_sig_getselector(DKIM_SIGINFO *siginfo)
08359 {
08360        assert(siginfo != NULL);
08361 
08362        return siginfo->sig_selector;
08363 }
08364 
08365 /*
08366 **  DKIM_SIG_GETDOMAIN -- retrieve domain from a DKIM_SIGINFO
08367 **
08368 **  Parameters:
08369 **     siginfo -- pointer to a DKIM_SIGINFO from which to extract the domain
08370 **
08371 **  Return value:
08372 **     Pointer to the domain associated with the DKIM_SIGINFO.
08373 */
08374 
08375 unsigned char *
08376 dkim_sig_getdomain(DKIM_SIGINFO *siginfo)
08377 {
08378        assert(siginfo != NULL);
08379 
08380        return siginfo->sig_domain;
08381 }
08382 
08383 /*
08384 **  DKIM_SIG_GETERROR -- retrieve an error code from a DKIM_SIGINFO
08385 **
08386 **  Parameters:
08387 **     siginfo -- pointer to a DKIM_SIGINFO from which to extract context
08388 **
08389 **  Return value:
08390 **     A DKIM_SIGERROR_* constant.
08391 */
08392 
08393 int
08394 dkim_sig_geterror(DKIM_SIGINFO *siginfo)
08395 {
08396        assert(siginfo != NULL);
08397 
08398        return siginfo->sig_error;
08399 }
08400 
08401 /*
08402 **  DKIM_SIG_GETERRORSTR -- translate a DKIM_SIGERROR_* constant to a string
08403 **
08404 **  Parameters:
08405 **     sigerr -- DKIM_SIGERROR_* constant to translate
08406 **
08407 **  Return value:
08408 **     A pointer to a human-readable expression of "sigerr", or NULL if none
08409 **     exists.
08410 */
08411 
08412 const char *
08413 dkim_sig_geterrorstr(DKIM_SIGERROR sigerr)
08414 {
08415        return dkim_code_to_name(sigerrors, sigerr);
08416 }
08417 
08418 /*
08419 **  DKIM_SIG_IGNORE -- mark a signature referenced by a DKIM_SIGINFO with
08420 **                     an "ignore" flag
08421 **
08422 **  Parameters:
08423 **     siginfo -- pointer to a DKIM_SIGINFO to update
08424 **
08425 **  Return value:
08426 **     None.
08427 */
08428 
08429 void
08430 dkim_sig_ignore(DKIM_SIGINFO *siginfo)
08431 {
08432        assert(siginfo != NULL);
08433 
08434        siginfo->sig_flags |= DKIM_SIGFLAG_IGNORE;
08435 }
08436 
08437 /*
08438 **  DKIM_SSL_VERSION -- return version of OpenSSL that was used to build
08439 **                      the library
08440 **
08441 **  Parameters:
08442 **     None.
08443 **
08444 **  Return value:
08445 **     The constant OPENSSL_VERSION_NUMBER as defined by OpenSSL.
08446 */
08447 
08448 unsigned long
08449 dkim_ssl_version(void)
08450 {
08451 #ifdef USE_GNUTLS
08452        return (GNUTLS_VERSION_NUMBER << 8);
08453 #else /* USE_GNUTLS */
08454        return OPENSSL_VERSION_NUMBER;
08455 #endif /* USE_GNUTLS */
08456 }
08457 
08458 /*
08459 **  DKIM_FLUSH_CACHE -- purge expired records from the cache
08460 **
08461 **  Parameters:
08462 **     lib -- DKIM library handle, returned by dkim_init()
08463 **
08464 **  Return value:
08465 **     -1 -- caching is not in effect
08466 **     >= 0 -- number of purged records
08467 */
08468 
08469 int
08470 dkim_flush_cache(DKIM_LIB *lib)
08471 {
08472 #ifdef QUERY_CACHE
08473        int err;
08474 #endif /* QUERY_CACHE */
08475 
08476        assert(lib != NULL);
08477 
08478 #ifdef QUERY_CACHE
08479        if (lib->dkiml_cache == NULL)
08480               return -1;
08481 
08482        return dkim_cache_expire(lib->dkiml_cache, 0, &err);
08483 #else /* QUERY_CACHE */
08484        return -1;
08485 #endif /* QUERY_CACHE */
08486 }
08487 
08488 /*
08489 **  DKIM_GETCACHESTATS -- retrieve cache statistics
08490 **
08491 **  Parameters:
08492 **     queries -- number of queries handled (returned)
08493 **     hits -- number of cache hits (returned)
08494 **     expired -- number of expired hits (returned)
08495 **
08496 **  Return value:
08497 **     DKIM_STAT_OK -- request completed
08498 **     DKIM_STAT_NOTIMPLEMENT -- function not implemented
08499 **
08500 **  Notes:
08501 **     Any of the parameters may be NULL if the corresponding datum
08502 **     is not of interest.
08503 */
08504 
08505 DKIM_STAT
08506 dkim_getcachestats(u_int *queries, u_int *hits, u_int *expired)
08507 {
08508 #ifdef QUERY_CACHE
08509        dkim_cache_stats(queries, hits, expired);
08510        return DKIM_STAT_OK;
08511 #else /* QUERY_CACHE */
08512        return DKIM_STAT_NOTIMPLEMENT;
08513 #endif /* QUERY_CACHE */
08514 }
08515 
08516 /*
08517 **  DKIM_GET_REPUTATION -- query reputation service about a signature
08518 **                         (OBSOLETE; moved to libdkimrep)
08519 **  
08520 **  Parameters:
08521 **     dkim -- DKIM handle
08522 **     sig -- DKIM_SIGINFO handle
08523 **     qroot -- query root
08524 **     rep -- integer reputation (returned)
08525 **
08526 **  Return value:
08527 **     DKIM_STAT_NOTIMPLEMENT -- not implemented
08528 */
08529 
08530 DKIM_STAT
08531 dkim_get_reputation(DKIM *dkim, DKIM_SIGINFO *sig, char *qroot, int *rep)
08532 {
08533        return DKIM_STAT_NOTIMPLEMENT;
08534 }
08535 
08536 /*
08537 **  DKIM_GET_SIGSUBSTRING -- retrieve a minimal signature substring for
08538 **                           disambiguation
08539 **
08540 **  Parameters:
08541 **     dkim -- DKIM handle
08542 **     sig -- DKIM_SIGINFO handle
08543 **     buf -- buffer into which to put the substring
08544 **     buflen -- bytes available at "buf"
08545 **
08546 **  Return value:
08547 **     A DKIM_STAT_* constant.
08548 */
08549 
08550 DKIM_STAT
08551 dkim_get_sigsubstring(DKIM *dkim, DKIM_SIGINFO *sig, char *buf, size_t *buflen)
08552 {
08553        int c;
08554        int d;
08555        int x;
08556        int b1len;
08557        int b2len;
08558        int minlen;
08559        char *b1;
08560        char *b2;
08561 
08562        assert(dkim != NULL);
08563        assert(sig != NULL);
08564        assert(buf != NULL);
08565        assert(buflen != NULL);
08566 
08567        if (dkim->dkim_minsiglen == 0)
08568        {
08569               dkim->dkim_minsiglen = MINSIGLEN;
08570 
08571               for (c = 0; c < dkim->dkim_sigcount - 1; c++)
08572               {
08573                      b1 = (char *) dkim_param_get(dkim->dkim_siglist[c]->sig_taglist,
08574                                                   (u_char *) "b");
08575                      if (b1 == NULL)
08576                             continue;
08577 
08578                      b1len = strlen(b1);
08579 
08580                      for (d = c + 1; d < dkim->dkim_sigcount; d++)
08581                      {
08582                             b2 = (char *) dkim_param_get(dkim->dkim_siglist[d]->sig_taglist,
08583                                                          (u_char *) "b");
08584                             if (b2 == NULL)
08585                                    continue;
08586 
08587                             if (strncmp(b1, b2, dkim->dkim_minsiglen) != 0)
08588                                    continue;
08589 
08590                             b2len = strlen(b2);
08591 
08592                             minlen = MIN(strlen(b1), strlen(b2));
08593 
08594                             for (x = dkim->dkim_minsiglen; x < minlen; x++)
08595                             {
08596                                    if (b1[x] != b2[x])
08597                                           break;
08598                             }
08599 
08600                             dkim->dkim_minsiglen = x + 1;
08601                      }
08602               }
08603        }
08604 
08605        b1 = (char *) dkim_param_get(sig->sig_taglist, (u_char *) "b");
08606        if (b1 == NULL)
08607               return DKIM_STAT_SYNTAX;
08608 
08609        minlen = MIN(*buflen, dkim->dkim_minsiglen);
08610        strncpy(buf, b1, minlen);
08611        if (minlen < *buflen)
08612               buf[minlen] = '\0';
08613        *buflen = minlen;
08614 
08615        return DKIM_STAT_OK;
08616 }
08617 
08618 /*
08619 **  DKIM_LIBFEATURE -- determine whether or not a particular library feature
08620 **                     is actually available
08621 **
08622 **  Parameters:
08623 **     lib -- library handle
08624 **     fc -- feature code to check
08625 **
08626 **  Return value:
08627 **     TRUE iff the specified feature was compiled in
08628 */
08629 
08630 _Bool
08631 dkim_libfeature(DKIM_LIB *lib, u_int fc)
08632 {
08633        u_int idx;
08634        u_int offset;
08635 
08636        idx = fc / (8 * sizeof(int));
08637        offset = fc % (8 * sizeof(int));
08638 
08639        if (idx > lib->dkiml_flsize)
08640               return FALSE;
08641        return ((lib->dkiml_flist[idx] & (1 << offset)) != 0);
08642 }
08643 
08644 /*
08645 **  DKIM_LIBVERSION -- return version of libopendkim at runtime
08646 **
08647 **  Parameters:
08648 **     None.
08649 **
08650 **  Return value:
08651 **     Library version, i.e. value of the OPENDKIM_LIB_VERSION macro.
08652 */
08653 
08654 uint32_t
08655 dkim_libversion(void)
08656 {
08657        return OPENDKIM_LIB_VERSION;
08658 }
08659 
08660 /*
08661 **  DKIM_SIG_GETTAGVALUE -- retrieve a tag's value from a signature or its key
08662 **
08663 **  Parameters:
08664 **     sig -- DKIM_SIGINFO handle
08665 **     keytag -- TRUE iff we want a key's tag
08666 **     tag -- name of the tag of interest
08667 **
08668 **  Return value:
08669 **     Pointer to the string containing the value of the requested key,
08670 **     or NULL if not present.
08671 **
08672 **  Notes:
08673 **     This was added for use in determining whether or not a key or
08674 **     signature contained particular data, for gathering general statistics
08675 **     about DKIM use.  It is not intended to give applications direct access
08676 **     to unprocessed signature or key data.  The data returned has not
08677 **     necessarily been vetted in any way.  Caveat emptor.
08678 */
08679 
08680 u_char *
08681 dkim_sig_gettagvalue(DKIM_SIGINFO *sig, _Bool keytag, u_char *tag)
08682 {
08683        DKIM_SET *set;
08684 
08685        assert(sig != NULL);
08686        assert(tag != NULL);
08687 
08688        if (keytag)
08689               set = sig->sig_keytaglist;
08690        else
08691               set = sig->sig_taglist;
08692 
08693        if (set == NULL)
08694               return NULL;
08695        else
08696               return dkim_param_get(set, tag);
08697 }
08698 
08699 /*
08700 **  DKIM_SIG_GETSIGNEDHDRS -- retrieve the signed header fields covered by
08701 **                            a signature that passed
08702 **
08703 **  Parameters:
08704 **     dkim -- DKIM instance
08705 **     sig -- signature
08706 **     hdrs -- rectangular array of header field strings
08707 **     hdrlen -- length of each element of "hdrs"
08708 **     nhdrs -- size of "hdrs" array (updated)
08709 **
08710 **  Return value:
08711 **     A DKIM_STAT_* constant.
08712 */
08713 
08714 DKIM_STAT
08715 dkim_sig_getsignedhdrs(DKIM *dkim, DKIM_SIGINFO *sig,
08716                        u_char *hdrs, size_t hdrlen, u_int *nhdrs)
08717 {
08718        int status;
08719        u_int n;
08720        u_char *h;
08721        u_char *p;
08722        struct dkim_header **sighdrs;
08723 
08724        assert(dkim != NULL);
08725        assert(sig != NULL);
08726        assert(nhdrs != NULL);
08727 
08728        if ((sig->sig_flags & DKIM_SIGFLAG_PASSED) == 0 ||
08729            sig->sig_bh != DKIM_SIGBH_MATCH)
08730               return DKIM_STAT_INVALID;
08731 
08732        h = dkim_param_get(sig->sig_taglist, "h");
08733        assert(h != NULL);
08734 
08735        n = 1;
08736        for (p = h; *p != '\0'; p++)
08737        {
08738               if (*p == ':')
08739                      n++;
08740        }
08741 
08742        if (*nhdrs < n)
08743        {
08744               *nhdrs = n;
08745               return DKIM_STAT_NORESOURCE;
08746        }
08747 
08748        assert(hdrs != NULL);
08749 
08750        sighdrs = (struct dkim_header **) DKIM_MALLOC(dkim,
08751                                                      sizeof(struct dkim_header *) * n);
08752        if (sighdrs == NULL)
08753        {
08754               *nhdrs = 0;
08755               return DKIM_STAT_NORESOURCE;
08756        }
08757 
08758        status = dkim_canon_selecthdrs(dkim, h, sighdrs, n);
08759        if (status == -1)
08760        {
08761               DKIM_FREE(dkim, sighdrs);
08762               return DKIM_STAT_INTERNAL;
08763        }
08764 
08765        *nhdrs = status;
08766 
08767        for (n = 0; n < status; n++)
08768               strlcpy(&hdrs[n * hdrlen], sighdrs[n]->hdr_text, hdrlen);
08769 
08770        DKIM_FREE(dkim, sighdrs);
08771 
08772        return DKIM_STAT_OK;
08773 }
08774 
08775 /*
08776 **  DKIM_DNS_SET_QUERY_SERVICE -- stores a handle representing the DNS
08777 **                                query service to be used, returning any
08778 **                                previous handle
08779 **
08780 **  Parameters:
08781 **     lib -- DKIM library handle
08782 **     h -- handle to be used
08783 **
08784 **  Return value:
08785 **     Previously stored handle, or NULL if none.
08786 */
08787 
08788 void *
08789 dkim_dns_set_query_service(DKIM_LIB *lib, void *h)
08790 {
08791        void *old;
08792 
08793        old = lib->dkiml_dns_service;
08794 
08795        lib->dkiml_dns_service = h;
08796 
08797        return old;
08798 }
08799 
08800 /*
08801 **  DKIM_DNS_SET_QUERY_START -- stores a pointer to a query start function
08802 **
08803 **  Parameters:
08804 **     lib -- DKIM library handle
08805 **     func -- function to use to start queries
08806 **
08807 **  Return value:
08808 **     None.
08809 **
08810 **  Notes:
08811 **     "func" should match the following prototype:
08812 **            returns int (status)
08813 **            void *dns -- receives handle stored by
08814 **                         dkim_dns_set_query_service()
08815 **            int type -- DNS RR query type (C_IN assumed)
08816 **            char *query -- question to ask
08817 **            char *buf -- buffer into which to write reply
08818 **            size_t buflen -- size of buf
08819 **            void **qh -- returned query handle
08820 */
08821 
08822 void
08823 dkim_dns_set_query_start(DKIM_LIB *lib, int (*func)(void *, int,
08824                                                     unsigned char *,
08825                                                     unsigned char *,
08826                                                     size_t, void **))
08827 {
08828        assert(lib != NULL);
08829 
08830        if (func != NULL)
08831               lib->dkiml_dns_start = func;
08832        else
08833               lib->dkiml_dns_start = dkim_res_query;
08834 }
08835 
08836 /*
08837 **  DKIM_DNS_SET_QUERY_CANCEL -- stores a pointer to a query cancel function
08838 **
08839 **  Parameters:
08840 **     lib -- DKIM library handle
08841 **     func -- function to use to cancel running queries
08842 **
08843 **  Return value:
08844 **     None.
08845 **
08846 **  Notes:
08847 **     "func" should match the following prototype:
08848 **            returns int (status)
08849 **            void *dns -- DNS service handle
08850 **            void *qh -- query handle to be canceled
08851 */
08852 
08853 void
08854 dkim_dns_set_query_cancel(DKIM_LIB *lib, int (*func)(void *, void *))
08855 {
08856        assert(lib != NULL);
08857 
08858        if (func != NULL)
08859               lib->dkiml_dns_cancel = func;
08860        else
08861               lib->dkiml_dns_cancel = dkim_res_cancel;
08862 }
08863 
08864 /*
08865 **  DKIM_DNS_SET_QUERY_WAITREPLY -- stores a pointer to wait for a DNS reply
08866 **
08867 **  Parameters:
08868 **     lib -- DKIM library handle
08869 **     func -- function to use to wait for a reply
08870 **
08871 **  Return value:
08872 **     None.
08873 **
08874 **  Notes:
08875 **     "func" should match the following prototype:
08876 **            returns int (status)
08877 **            void *dns -- DNS service handle
08878 **            void *qh -- handle of query that has completed
08879 **            struct timeval *timeout -- how long to wait
08880 **            size_t *bytes -- bytes returned
08881 **            int *error -- error code returned
08882 **            int *dnssec -- DNSSEC status returned
08883 */
08884 
08885 void
08886 dkim_dns_set_query_waitreply(DKIM_LIB *lib, int (*func)(void *, void *,
08887                                                         struct timeval *,
08888                                                         size_t *, int *,
08889                                                         int *))
08890 {
08891        assert(lib != NULL);
08892 
08893        if (func != NULL)
08894               lib->dkiml_dns_waitreply = func;
08895        else
08896               lib->dkiml_dns_waitreply = dkim_res_waitreply;
08897 }
08898 
08899 /*
08900 **  DKIM_ADD_XTAG -- add an extension tag/value
08901 **
08902 **  Parameters:
08903 **     dkim -- DKIM signing handle to extend
08904 **     tag -- name of tag to add
08905 **     value -- value to include
08906 **
08907 **  Return value:
08908 **     A DKIM_STAT_* constant.
08909 **
08910 **  Notes:
08911 **     A value that contains spaces won't be wrapped nicely by the signature
08912 **     generation code.  Support for this should be added later.
08913 */
08914 
08915 DKIM_STAT
08916 dkim_add_xtag(DKIM *dkim, const char *tag, const char *value)
08917 {
08918        u_char last = '\0';
08919        dkim_param_t pcode;
08920        u_char *p;
08921        struct dkim_xtag *x;
08922 
08923        assert(dkim != NULL);
08924        assert(tag != NULL);
08925        assert(value != NULL);
08926 
08927        if (dkim->dkim_mode != DKIM_MODE_SIGN)
08928               return DKIM_STAT_INVALID;
08929 
08930        /* check that it's not in sigparams */
08931        if (tag[0] == '\0' || value[0] == '\0')
08932               return DKIM_STAT_INVALID;
08933        pcode = dkim_name_to_code(sigparams, tag);
08934        if (pcode != (dkim_param_t) -1)
08935               return DKIM_STAT_INVALID;
08936 
08937        /* confirm valid syntax, per RFC6376 */
08938        for (p = (u_char *) tag; *p != '\0'; p++)
08939        {
08940               if (!(isascii(*p) && (isalnum(*p) || *p == '_')))
08941                      return DKIM_STAT_INVALID;
08942        }
08943 
08944        if (value[0] == '\n' ||
08945            value[0] == '\r' ||
08946            value[0] == '\t' ||
08947            value[0] == ' ')
08948               return DKIM_STAT_INVALID;
08949 
08950        for (p = (u_char *) value; *p != '\0'; p++)
08951        {
08952               /* valid characters in general */
08953               if (!(*p == '\n' ||
08954                     *p == '\r' ||
08955                     *p == '\t' ||
08956                     *p == ' ' ||
08957                     (*p >= 0x21 && *p <= 0x7e && *p != 0x3b)))
08958                      return DKIM_STAT_INVALID;
08959 
08960               /* CR has to be followed by LF */
08961               if (last == '\r' && *p != '\n')
08962                      return DKIM_STAT_INVALID;
08963 
08964               /* LF has to be followed by space or tab */
08965               if (last == '\n' && *p != ' ' && *p != '\t')
08966                      return DKIM_STAT_INVALID;
08967 
08968               last = *p;
08969        }
08970 
08971        /* can't end with space */
08972        if (last == '\n' || last == '\r' ||
08973            last == '\t' || last == ' ')
08974               return DKIM_STAT_INVALID;
08975 
08976        /* check for dupicates */
08977        for (x = dkim->dkim_xtags; x != NULL; x = x->xt_next)
08978        {
08979               if (strcmp(x->xt_tag, tag) == 0)
08980                      return DKIM_STAT_INVALID;
08981        }
08982 
08983        x = (struct dkim_xtag *) DKIM_MALLOC(dkim, sizeof(struct dkim_xtag));
08984        if (x == NULL)
08985        {
08986               dkim_error(dkim, "unable to allocate %d byte(s)",
08987                          sizeof(struct dkim_xtag));
08988               return DKIM_STAT_NORESOURCE;
08989        }
08990 
08991        x->xt_tag = tag;
08992        x->xt_value = value;
08993        x->xt_next = dkim->dkim_xtags;
08994        dkim->dkim_xtags = x;
08995 
08996        return DKIM_STAT_OK;
08997 }
08998 
08999 /*
09000 **  DKIM_QI_GETNAME -- retrieve the DNS name from a DKIM_QUERYINFO object
09001 **
09002 **  Parameters:
09003 **     query -- DKIM_QUERYINFO handle
09004 **
09005 **  Return value:
09006 **     A pointer to a NULL-terminated string indicating the name to be
09007 **     queried, or NULL on error.
09008 */
09009 
09010 const char *
09011 dkim_qi_getname(DKIM_QUERYINFO *query)
09012 {
09013        assert(query != NULL);
09014 
09015        return query->dq_name;
09016 }
09017 
09018 /*
09019 **  DKIM_QI_GETTYPE -- retrieve the DNS RR type from a DKIM_QUERYINFO object
09020 **
09021 **  Parameters:
09022 **     query -- DKIM_QUERYINFO handle
09023 **
09024 **  Return value:
09025 **     The DNS RR type to be queried, or -1 on error.
09026 */
09027 
09028 int
09029 dkim_qi_gettype(DKIM_QUERYINFO *query)
09030 {
09031        assert(query != NULL);
09032 
09033        return query->dq_type;
09034 }
09035 
09036 /*
09037 **  DKIM_SIG_GETQUERIES -- retrieve the queries needed to validate a signature
09038 **
09039 **  Parameters:
09040 **     dkim -- DKIM handle
09041 **     sig -- DKIM_SIGINFO handle
09042 **     qi -- DKIM_QUERYINFO handle array (returned)
09043 **     nqi -- number of entries in the "qi" array
09044 **
09045 **  Return value:
09046 **     A DKIM_STAT_* constant.
09047 */
09048 
09049 DKIM_STAT
09050 dkim_sig_getqueries(DKIM *dkim, DKIM_SIGINFO *sig,
09051                     DKIM_QUERYINFO ***qi, unsigned int *nqi)
09052 {
09053        DKIM_QUERYINFO **new;
09054        DKIM_QUERYINFO *newp;
09055 
09056        assert(dkim != NULL);
09057        assert(sig != NULL);
09058        assert(qi != NULL);
09059        assert(nqi != NULL);
09060 
09061        new = DKIM_MALLOC(dkim, sizeof(struct dkim_queryinfo *));
09062        if (new == NULL)
09063               return DKIM_STAT_NORESOURCE;
09064 
09065        newp = DKIM_MALLOC(dkim, sizeof(struct dkim_queryinfo));
09066        if (newp == NULL)
09067        {
09068               DKIM_FREE(dkim, new);
09069               return DKIM_STAT_NORESOURCE;
09070        }
09071 
09072        memset(newp, '\0', sizeof(struct dkim_queryinfo));
09073 
09074        if (sig->sig_selector != NULL && sig->sig_domain != NULL)
09075        {
09076               newp->dq_type = T_TXT;
09077               snprintf((char *) newp->dq_name, sizeof newp->dq_name,
09078                        "%s.%s.%s",
09079                        sig->sig_selector, DKIM_DNSKEYNAME, sig->sig_domain);
09080        }
09081 
09082        new[0] = newp;
09083 
09084        *qi = new;
09085        *nqi = 1;
09086 
09087        return DKIM_STAT_OK;
09088 }
09089 
09090 /*
09091 **  DKIM_POLICY_GETQUERIES -- retrieve the queries needed to conduct ADSP
09092 **                            checks
09093 **
09094 **  Parameters:
09095 **     dkim -- DKIM handle
09096 **     qi -- DKIM_QUERYINFO handle array (returned)
09097 **     nqi -- number of entries in the "qi" array
09098 **
09099 **  Return value:
09100 **     A DKIM_STAT_* constant.
09101 */
09102 
09103 DKIM_STAT
09104 dkim_policy_getqueries(DKIM *dkim,
09105                        DKIM_QUERYINFO ***qi, unsigned int *nqi)
09106 {
09107        int c;
09108        DKIM_QUERYINFO **new;
09109 
09110        assert(dkim != NULL);
09111        assert(qi != NULL);
09112        assert(nqi != NULL);
09113 
09114        new = DKIM_MALLOC(dkim, 4 * sizeof(struct dkim_queryinfo *));
09115        if (new == NULL)
09116               return DKIM_STAT_NORESOURCE;
09117 
09118        memset(new, '\0', 4 * sizeof(struct dkim_queryinfo *));
09119 
09120        for (c = 0; c < 4; c++)
09121        {
09122               new[c] = DKIM_MALLOC(dkim, sizeof(struct dkim_queryinfo));
09123               if (new[c] == NULL)
09124               {
09125                      int d;
09126 
09127                      for (d = 0; d < c; d++)
09128                             free(new[d]);
09129 
09130                      free(new);
09131 
09132                      return DKIM_STAT_NORESOURCE;
09133               }
09134 
09135               memset(new[c], '\0', sizeof(struct dkim_queryinfo));
09136 
09137               switch (c)
09138               {
09139                 case 0:
09140                      new[c]->dq_type = T_A;
09141                      break;
09142 
09143                 case 1:
09144                      new[c]->dq_type = T_AAAA;
09145                      break;
09146 
09147                 case 2:
09148                      new[c]->dq_type = T_MX;
09149                      break;
09150 
09151                 case 3:
09152                      new[c]->dq_type = T_TXT;
09153                      break;
09154               }
09155 
09156               if (dkim->dkim_domain != NULL)
09157               {
09158                      if (c != 3)
09159                      {
09160                             strlcpy((char *) new[c]->dq_name,
09161                                     dkim->dkim_domain,
09162                                      sizeof new[c]->dq_name);
09163                      }
09164                      else
09165                      {
09166                             snprintf((char *) new[c]->dq_name,
09167                                      sizeof new[c]->dq_name,
09168                                      "%s.%s.%s",
09169                                      DKIM_DNSPOLICYNAME, DKIM_DNSKEYNAME,
09170                                      dkim->dkim_domain);
09171                      }
09172               }
09173        }
09174 
09175        *qi = new;
09176        *nqi = 4;
09177 
09178        return DKIM_STAT_OK;
09179 }
09180 
09181 /*
09182 **  DKIM_SIG_GETHASHES -- retrieve hashes
09183 **
09184 **  Parameters:
09185 **     sig -- signature from which to get completed hashes
09186 **     hh -- pointer to header hash buffer (returned)
09187 **     hhlen -- bytes used at hh (returned)
09188 **     bh -- pointer to body hash buffer (returned)
09189 **     bhlen -- bytes used at bh (returned)
09190 **
09191 **  Return value:
09192 **     DKIM_STAT_OK -- successful completion
09193 **     DKIM_STAT_INVALID -- hashing hasn't been completed
09194 */
09195 
09196 DKIM_STAT
09197 dkim_sig_gethashes(DKIM_SIGINFO *sig, void **hh, size_t *hhlen,
09198                    void **bh, size_t *bhlen)
09199 {
09200        return dkim_canon_gethashes(sig, hh, hhlen, bh, bhlen);
09201 }