Back to index

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