cc.c

Go to the documentation of this file.
00001 /*
00002  * Portions Copyright (C) 2004-2007, 2012-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Portions Copyright (C) 2001-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
00010  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
00011  * OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY
00012  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00013  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00014  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00015  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00016  *
00017  * Portions Copyright (C) 2001  Nominum, Inc.
00018  *
00019  * Permission to use, copy, modify, and/or distribute this software for any
00020  * purpose with or without fee is hereby granted, provided that the above
00021  * copyright notice and this permission notice appear in all copies.
00022  *
00023  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
00024  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
00025  * OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY
00026  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00027  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00028  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00029  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00030  */
00031 
00032 /* $Id: cc.c,v 1.18 2007/08/28 07:20:43 tbox Exp $ */
00033 
00034 /*! \file */
00035 
00036 #include <config.h>
00037 
00038 #include <stdio.h>
00039 #include <string.h>
00040 #include <errno.h>
00041 
00042 #include <isc/assertions.h>
00043 #include <isc/hmacmd5.h>
00044 #include <isc/hmacsha.h>
00045 #include <isc/print.h>
00046 #include <isc/safe.h>
00047 #include <isc/stdlib.h>
00048 
00049 #include <isccc/alist.h>
00050 #include <isccc/base64.h>
00051 #include <isccc/cc.h>
00052 #include <isccc/result.h>
00053 #include <isccc/sexpr.h>
00054 #include <isccc/symtab.h>
00055 #include <isccc/symtype.h>
00056 #include <isccc/util.h>
00057 
00058 #define MAX_TAGS                256
00059 #define DUP_LIFETIME            900
00060 
00061 typedef isccc_sexpr_t *sexpr_ptr;
00062 
00063 static unsigned char auth_hmd5[] = {
00064         0x05, 0x5f, 0x61, 0x75, 0x74, 0x68,             /*%< len + _auth */
00065         ISCCC_CCMSGTYPE_TABLE,                          /*%< message type */
00066         0x00, 0x00, 0x00, 0x20,                         /*%< length == 32 */
00067         0x04, 0x68, 0x6d, 0x64, 0x35,                   /*%< len + hmd5 */
00068         ISCCC_CCMSGTYPE_BINARYDATA,                     /*%< message type */
00069         0x00, 0x00, 0x00, 0x16,                         /*%< length == 22 */
00070         /*
00071          * The base64 encoding of one of our HMAC-MD5 signatures is
00072          * 22 bytes.
00073          */
00074         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00075         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00076         0x00, 0x00, 0x00, 0x00, 0x00, 0x00
00077 };
00078 
00079 #define HMD5_OFFSET     21              /*%< 21 = 6 + 1 + 4 + 5 + 1 + 4 */
00080 #define HMD5_LENGTH     22
00081 
00082 static unsigned char auth_hsha[] = {
00083         0x05, 0x5f, 0x61, 0x75, 0x74, 0x68,             /*%< len + _auth */
00084         ISCCC_CCMSGTYPE_TABLE,                          /*%< message type */
00085         0x00, 0x00, 0x00, 0x63,                         /*%< length == 99 */
00086         0x04, 0x68, 0x73, 0x68, 0x61,                   /*%< len + hsha */
00087         ISCCC_CCMSGTYPE_BINARYDATA,                     /*%< message type */
00088         0x00, 0x00, 0x00, 0x59,                         /*%< length == 89 */
00089         0x00,                                           /*%< algorithm */
00090         /*
00091          * The base64 encoding of one of our HMAC-SHA* signatures is
00092          * 88 bytes.
00093          */
00094         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00095         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00096         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00097         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00098         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00099         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00100         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00101         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00102         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00103         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00104         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
00105 };
00106 
00107 #define HSHA_OFFSET     22              /*%< 21 = 6 + 1 + 4 + 5 + 1 + 4 + 1 */
00108 #define HSHA_LENGTH     88
00109 
00110 static isc_result_t
00111 table_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer);
00112 
00113 static isc_result_t
00114 list_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer);
00115 
00116 static isc_result_t
00117 value_towire(isccc_sexpr_t *elt, isc_buffer_t **buffer)
00118 {
00119         unsigned int len;
00120         isccc_region_t *vr;
00121         isc_result_t result;
00122 
00123         if (isccc_sexpr_binaryp(elt)) {
00124                 vr = isccc_sexpr_tobinary(elt);
00125                 len = REGION_SIZE(*vr);
00126                 result = isc_buffer_reserve(buffer, 1 + 4);
00127                 if (result != ISC_R_SUCCESS)
00128                         return (ISC_R_NOSPACE);
00129                 isc_buffer_putuint8(*buffer, ISCCC_CCMSGTYPE_BINARYDATA);
00130                 isc_buffer_putuint32(*buffer, len);
00131 
00132                 result = isc_buffer_reserve(buffer, len);
00133                 if (result != ISC_R_SUCCESS)
00134                         return (ISC_R_NOSPACE);
00135                 isc_buffer_putmem(*buffer, vr->rstart, len);
00136         } else if (isccc_alist_alistp(elt)) {
00137                 unsigned int used;
00138                 isc_buffer_t b;
00139 
00140                 result = isc_buffer_reserve(buffer, 1 + 4);
00141                 if (result != ISC_R_SUCCESS)
00142                         return (ISC_R_NOSPACE);
00143                 isc_buffer_putuint8(*buffer, ISCCC_CCMSGTYPE_TABLE);
00144                 /*
00145                  * Emit a placeholder length.
00146                  */
00147                 used = (*buffer)->used;
00148                 isc_buffer_putuint32(*buffer, 0);
00149 
00150                 /*
00151                  * Emit the table.
00152                  */
00153                 result = table_towire(elt, buffer);
00154                 if (result != ISC_R_SUCCESS)
00155                         return (result);
00156 
00157                 len = (*buffer)->used - used;
00158                 /*
00159                  * 'len' is 4 bytes too big, since it counts
00160                  * the placeholder length too.  Adjust and
00161                  * emit.
00162                  */
00163                 INSIST(len >= 4U);
00164                 len -= 4;
00165 
00166                 isc_buffer_init(&b, (unsigned char *) (*buffer)->base + used, 4);
00167                 isc_buffer_putuint32(&b, len);
00168         } else if (isccc_sexpr_listp(elt)) {
00169                 unsigned int used;
00170                 isc_buffer_t b;
00171 
00172                 result = isc_buffer_reserve(buffer, 1 + 4);
00173                 if (result != ISC_R_SUCCESS)
00174                         return (ISC_R_NOSPACE);
00175                 isc_buffer_putuint8(*buffer, ISCCC_CCMSGTYPE_LIST);
00176                 /*
00177                  * Emit a placeholder length.
00178                  */
00179                 used = (*buffer)->used;
00180                 isc_buffer_putuint32(*buffer, 0);
00181 
00182                 /*
00183                  * Emit the list.
00184                  */
00185                 result = list_towire(elt, buffer);
00186                 if (result != ISC_R_SUCCESS)
00187                         return (result);
00188 
00189                 len = (*buffer)->used - used;
00190                 /*
00191                  * 'len' is 4 bytes too big, since it counts
00192                  * the placeholder length too.  Adjust and
00193                  * emit.
00194                  */
00195                 INSIST(len >= 4U);
00196                 len -= 4;
00197 
00198                 isc_buffer_init(&b, (unsigned char *) (*buffer)->base + used, 4);
00199                 isc_buffer_putuint32(&b, len);
00200         }
00201 
00202         return (ISC_R_SUCCESS);
00203 }
00204 
00205 static isc_result_t
00206 table_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer) {
00207         isccc_sexpr_t *kv, *elt, *k, *v;
00208         char *ks;
00209         isc_result_t result;
00210         unsigned int len;
00211 
00212         for (elt = isccc_alist_first(alist);
00213              elt != NULL;
00214              elt = ISCCC_SEXPR_CDR(elt)) {
00215                 kv = ISCCC_SEXPR_CAR(elt);
00216                 k = ISCCC_SEXPR_CAR(kv);
00217                 ks = isccc_sexpr_tostring(k);
00218                 v = ISCCC_SEXPR_CDR(kv);
00219                 len = (unsigned int)strlen(ks);
00220                 INSIST(len <= 255U);
00221                 /*
00222                  * Emit the key name.
00223                  */
00224                 result = isc_buffer_reserve(buffer, 1 + len);
00225                 if (result != ISC_R_SUCCESS)
00226                         return (ISC_R_NOSPACE);
00227                 isc_buffer_putuint8(*buffer, (isc_uint8_t)len);
00228                 isc_buffer_putmem(*buffer, (const unsigned char *) ks, len);
00229                 /*
00230                  * Emit the value.
00231                  */
00232                 result = value_towire(v, buffer);
00233                 if (result != ISC_R_SUCCESS)
00234                         return (result);
00235         }
00236 
00237         return (ISC_R_SUCCESS);
00238 }
00239 
00240 static isc_result_t
00241 list_towire(isccc_sexpr_t *list, isc_buffer_t **buffer) {
00242         isc_result_t result;
00243 
00244         while (list != NULL) {
00245                 result = value_towire(ISCCC_SEXPR_CAR(list), buffer);
00246                 if (result != ISC_R_SUCCESS)
00247                         return (result);
00248                 list = ISCCC_SEXPR_CDR(list);
00249         }
00250 
00251         return (ISC_R_SUCCESS);
00252 }
00253 
00254 static isc_result_t
00255 sign(unsigned char *data, unsigned int length, unsigned char *hmac,
00256      isc_uint32_t algorithm, isccc_region_t *secret)
00257 {
00258         union {
00259                 isc_hmacmd5_t hmd5;
00260                 isc_hmacsha1_t hsha;
00261                 isc_hmacsha224_t h224;
00262                 isc_hmacsha256_t h256;
00263                 isc_hmacsha384_t h384;
00264                 isc_hmacsha512_t h512;
00265         } ctx;
00266         isc_result_t result;
00267         isccc_region_t source, target;
00268         unsigned char digest[ISC_SHA512_DIGESTLENGTH];
00269         unsigned char digestb64[HSHA_LENGTH + 4];
00270 
00271         source.rstart = digest;
00272 
00273         switch (algorithm) {
00274         case ISCCC_ALG_HMACMD5:
00275                 isc_hmacmd5_init(&ctx.hmd5, secret->rstart,
00276                                  REGION_SIZE(*secret));
00277                 isc_hmacmd5_update(&ctx.hmd5, data, length);
00278                 isc_hmacmd5_sign(&ctx.hmd5, digest);
00279                 source.rend = digest + ISC_MD5_DIGESTLENGTH;
00280                 break;
00281 
00282         case ISCCC_ALG_HMACSHA1:
00283                 isc_hmacsha1_init(&ctx.hsha, secret->rstart,
00284                                     REGION_SIZE(*secret));
00285                 isc_hmacsha1_update(&ctx.hsha, data, length);
00286                 isc_hmacsha1_sign(&ctx.hsha, digest,
00287                                     ISC_SHA1_DIGESTLENGTH);
00288                 source.rend = digest + ISC_SHA1_DIGESTLENGTH;
00289                 break;
00290 
00291         case ISCCC_ALG_HMACSHA224:
00292                 isc_hmacsha224_init(&ctx.h224, secret->rstart,
00293                                     REGION_SIZE(*secret));
00294                 isc_hmacsha224_update(&ctx.h224, data, length);
00295                 isc_hmacsha224_sign(&ctx.h224, digest,
00296                                     ISC_SHA224_DIGESTLENGTH);
00297                 source.rend = digest + ISC_SHA224_DIGESTLENGTH;
00298                 break;
00299 
00300         case ISCCC_ALG_HMACSHA256:
00301                 isc_hmacsha256_init(&ctx.h256, secret->rstart,
00302                                     REGION_SIZE(*secret));
00303                 isc_hmacsha256_update(&ctx.h256, data, length);
00304                 isc_hmacsha256_sign(&ctx.h256, digest,
00305                                     ISC_SHA256_DIGESTLENGTH);
00306                 source.rend = digest + ISC_SHA256_DIGESTLENGTH;
00307                 break;
00308 
00309         case ISCCC_ALG_HMACSHA384:
00310                 isc_hmacsha384_init(&ctx.h384, secret->rstart,
00311                                     REGION_SIZE(*secret));
00312                 isc_hmacsha384_update(&ctx.h384, data, length);
00313                 isc_hmacsha384_sign(&ctx.h384, digest,
00314                                     ISC_SHA384_DIGESTLENGTH);
00315                 source.rend = digest + ISC_SHA384_DIGESTLENGTH;
00316                 break;
00317 
00318         case ISCCC_ALG_HMACSHA512:
00319                 isc_hmacsha512_init(&ctx.h512, secret->rstart,
00320                                     REGION_SIZE(*secret));
00321                 isc_hmacsha512_update(&ctx.h512, data, length);
00322                 isc_hmacsha512_sign(&ctx.h512, digest,
00323                                     ISC_SHA512_DIGESTLENGTH);
00324                 source.rend = digest + ISC_SHA512_DIGESTLENGTH;
00325                 break;
00326 
00327         default:
00328                 return (ISC_R_FAILURE);
00329         }
00330 
00331         memset(digestb64, 0, sizeof(digestb64));
00332         target.rstart = digestb64;
00333         target.rend = digestb64 + sizeof(digestb64);
00334         result = isccc_base64_encode(&source, 64, "", &target);
00335         if (result != ISC_R_SUCCESS)
00336                 return (result);
00337         if (algorithm == ISCCC_ALG_HMACMD5)
00338                 PUT_MEM(digestb64, HMD5_LENGTH, hmac);
00339         else
00340                 PUT_MEM(digestb64, HSHA_LENGTH, hmac);
00341         return (ISC_R_SUCCESS);
00342 }
00343 
00344 isc_result_t
00345 isccc_cc_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer,
00346                 isc_uint32_t algorithm, isccc_region_t *secret)
00347 {
00348         unsigned int hmac_size, signed_size;
00349         isc_result_t result;
00350 
00351         result = isc_buffer_reserve(buffer,
00352                                     4 + ((algorithm == ISCCC_ALG_HMACMD5) ?
00353                                          sizeof(auth_hmd5) :
00354                                          sizeof(auth_hsha)));
00355         if (result != ISC_R_SUCCESS)
00356                 return (ISC_R_NOSPACE);
00357 
00358         /*
00359          * Emit protocol version.
00360          */
00361         isc_buffer_putuint32(*buffer, 1);
00362 
00363         if (secret != NULL) {
00364                 /*
00365                  * Emit _auth section with zeroed HMAC signature.
00366                  * We'll replace the zeros with the real signature once
00367                  * we know what it is.
00368                  */
00369                 if (algorithm == ISCCC_ALG_HMACMD5) {
00370                         hmac_size = (*buffer)->used + HMD5_OFFSET;
00371                         isc_buffer_putmem(*buffer,
00372                                           auth_hmd5, sizeof(auth_hmd5));
00373                 } else {
00374                         unsigned char *hmac_alg;
00375 
00376                         hmac_size = (*buffer)->used + HSHA_OFFSET;
00377                         hmac_alg = (unsigned char *) isc_buffer_used(*buffer) + HSHA_OFFSET - 1;
00378                         isc_buffer_putmem(*buffer,
00379                                           auth_hsha, sizeof(auth_hsha));
00380                         *hmac_alg = algorithm;
00381                 }
00382         } else
00383                 hmac_size = 0;
00384         signed_size = (*buffer)->used;
00385         /*
00386          * Delete any existing _auth section so that we don't try
00387          * to encode it.
00388          */
00389         isccc_alist_delete(alist, "_auth");
00390         /*
00391          * Emit the message.
00392          */
00393         result = table_towire(alist, buffer);
00394         if (result != ISC_R_SUCCESS)
00395                 return (result);
00396         if (secret != NULL)
00397                 return (sign((unsigned char *) (*buffer)->base + signed_size,
00398                              (*buffer)->used - signed_size,
00399                              (hmac_size == 0 ? NULL :
00400                               (unsigned char *) (*buffer)->base + hmac_size),
00401                              algorithm, secret));
00402         return (ISC_R_SUCCESS);
00403 }
00404 
00405 static isc_result_t
00406 verify(isccc_sexpr_t *alist, unsigned char *data, unsigned int length,
00407        isc_uint32_t algorithm, isccc_region_t *secret)
00408 {
00409         union {
00410                 isc_hmacmd5_t hmd5;
00411                 isc_hmacsha1_t hsha;
00412                 isc_hmacsha224_t h224;
00413                 isc_hmacsha256_t h256;
00414                 isc_hmacsha384_t h384;
00415                 isc_hmacsha512_t h512;
00416         } ctx;
00417         isccc_region_t source;
00418         isccc_region_t target;
00419         isc_result_t result;
00420         isccc_sexpr_t *_auth, *hmac;
00421         unsigned char digest[ISC_SHA512_DIGESTLENGTH];
00422         unsigned char digestb64[HSHA_LENGTH * 4];
00423 
00424         /*
00425          * Extract digest.
00426          */
00427         _auth = isccc_alist_lookup(alist, "_auth");
00428         if (_auth == NULL)
00429                 return (ISC_R_FAILURE);
00430         if (algorithm == ISCCC_ALG_HMACMD5)
00431                 hmac = isccc_alist_lookup(_auth, "hmd5");
00432         else
00433                 hmac = isccc_alist_lookup(_auth, "hsha");
00434         if (hmac == NULL)
00435                 return (ISC_R_FAILURE);
00436         /*
00437          * Compute digest.
00438          */
00439         source.rstart = digest;
00440         target.rstart = digestb64;
00441         switch (algorithm) {
00442         case ISCCC_ALG_HMACMD5:
00443                 isc_hmacmd5_init(&ctx.hmd5, secret->rstart,
00444                                  REGION_SIZE(*secret));
00445                 isc_hmacmd5_update(&ctx.hmd5, data, length);
00446                 isc_hmacmd5_sign(&ctx.hmd5, digest);
00447                 source.rend = digest + ISC_MD5_DIGESTLENGTH;
00448                 break;
00449 
00450         case ISCCC_ALG_HMACSHA1:
00451                 isc_hmacsha1_init(&ctx.hsha, secret->rstart,
00452                                     REGION_SIZE(*secret));
00453                 isc_hmacsha1_update(&ctx.hsha, data, length);
00454                 isc_hmacsha1_sign(&ctx.hsha, digest,
00455                                     ISC_SHA1_DIGESTLENGTH);
00456                 source.rend = digest + ISC_SHA1_DIGESTLENGTH;
00457                 break;
00458 
00459         case ISCCC_ALG_HMACSHA224:
00460                 isc_hmacsha224_init(&ctx.h224, secret->rstart,
00461                                     REGION_SIZE(*secret));
00462                 isc_hmacsha224_update(&ctx.h224, data, length);
00463                 isc_hmacsha224_sign(&ctx.h224, digest,
00464                                     ISC_SHA224_DIGESTLENGTH);
00465                 source.rend = digest + ISC_SHA224_DIGESTLENGTH;
00466                 break;
00467 
00468         case ISCCC_ALG_HMACSHA256:
00469                 isc_hmacsha256_init(&ctx.h256, secret->rstart,
00470                                     REGION_SIZE(*secret));
00471                 isc_hmacsha256_update(&ctx.h256, data, length);
00472                 isc_hmacsha256_sign(&ctx.h256, digest,
00473                                     ISC_SHA256_DIGESTLENGTH);
00474                 source.rend = digest + ISC_SHA256_DIGESTLENGTH;
00475                 break;
00476 
00477         case ISCCC_ALG_HMACSHA384:
00478                 isc_hmacsha384_init(&ctx.h384, secret->rstart,
00479                                     REGION_SIZE(*secret));
00480                 isc_hmacsha384_update(&ctx.h384, data, length);
00481                 isc_hmacsha384_sign(&ctx.h384, digest,
00482                                     ISC_SHA384_DIGESTLENGTH);
00483                 source.rend = digest + ISC_SHA384_DIGESTLENGTH;
00484                 break;
00485 
00486         case ISCCC_ALG_HMACSHA512:
00487                 isc_hmacsha512_init(&ctx.h512, secret->rstart,
00488                                     REGION_SIZE(*secret));
00489                 isc_hmacsha512_update(&ctx.h512, data, length);
00490                 isc_hmacsha512_sign(&ctx.h512, digest,
00491                                     ISC_SHA512_DIGESTLENGTH);
00492                 source.rend = digest + ISC_SHA512_DIGESTLENGTH;
00493                 break;
00494 
00495         default:
00496                 return (ISC_R_FAILURE);
00497         }
00498         target.rstart = digestb64;
00499         target.rend = digestb64 + sizeof(digestb64);
00500         memset(digestb64, 0, sizeof(digestb64));
00501         result = isccc_base64_encode(&source, 64, "", &target);
00502         if (result != ISC_R_SUCCESS)
00503                 return (result);
00504 
00505         /*
00506          * Verify.
00507          */
00508         if (algorithm == ISCCC_ALG_HMACMD5) {
00509                 unsigned char *value;
00510 
00511                 value = (unsigned char *) isccc_sexpr_tostring(hmac);
00512                 if (!isc_safe_memcmp(value, digestb64, HMD5_LENGTH))
00513                         return (ISCCC_R_BADAUTH);
00514         } else {
00515                 unsigned char *value;
00516                 isc_uint32_t valalg;
00517 
00518                 value = (unsigned char *) isccc_sexpr_tostring(hmac);
00519                 GET8(valalg, value);
00520                 if ((valalg != algorithm) ||
00521                     (!isc_safe_memcmp(value, digestb64, HSHA_LENGTH)))
00522                         return (ISCCC_R_BADAUTH);
00523         }
00524 
00525         return (ISC_R_SUCCESS);
00526 }
00527 
00528 static isc_result_t
00529 table_fromwire(isccc_region_t *source, isccc_region_t *secret,
00530                isc_uint32_t algorithm, isccc_sexpr_t **alistp);
00531 
00532 static isc_result_t
00533 list_fromwire(isccc_region_t *source, isccc_sexpr_t **listp);
00534 
00535 static isc_result_t
00536 value_fromwire(isccc_region_t *source, isccc_sexpr_t **valuep)
00537 {
00538         unsigned int msgtype;
00539         isc_uint32_t len;
00540         isccc_sexpr_t *value;
00541         isccc_region_t active;
00542         isc_result_t result;
00543 
00544         if (REGION_SIZE(*source) < 1 + 4)
00545                 return (ISC_R_UNEXPECTEDEND);
00546         GET8(msgtype, source->rstart);
00547         GET32(len, source->rstart);
00548         if (REGION_SIZE(*source) < len)
00549                 return (ISC_R_UNEXPECTEDEND);
00550         active.rstart = source->rstart;
00551         active.rend = active.rstart + len;
00552         source->rstart = active.rend;
00553         if (msgtype == ISCCC_CCMSGTYPE_BINARYDATA) {
00554                 value = isccc_sexpr_frombinary(&active);
00555                 if (value != NULL) {
00556                         *valuep = value;
00557                         result = ISC_R_SUCCESS;
00558                 } else
00559                         result = ISC_R_NOMEMORY;
00560         } else if (msgtype == ISCCC_CCMSGTYPE_TABLE)
00561                 result = table_fromwire(&active, NULL, 0, valuep);
00562         else if (msgtype == ISCCC_CCMSGTYPE_LIST)
00563                 result = list_fromwire(&active, valuep);
00564         else
00565                 result = ISCCC_R_SYNTAX;
00566 
00567         return (result);
00568 }
00569 
00570 static isc_result_t
00571 table_fromwire(isccc_region_t *source, isccc_region_t *secret,
00572                isc_uint32_t algorithm, isccc_sexpr_t **alistp)
00573 {
00574         char key[256];
00575         isc_uint32_t len;
00576         isc_result_t result;
00577         isccc_sexpr_t *alist, *value;
00578         isc_boolean_t first_tag;
00579         unsigned char *checksum_rstart;
00580 
00581         REQUIRE(alistp != NULL && *alistp == NULL);
00582 
00583         checksum_rstart = NULL;
00584         first_tag = ISC_TRUE;
00585         alist = isccc_alist_create();
00586         if (alist == NULL)
00587                 return (ISC_R_NOMEMORY);
00588 
00589         while (!REGION_EMPTY(*source)) {
00590                 GET8(len, source->rstart);
00591                 if (REGION_SIZE(*source) < len) {
00592                         result = ISC_R_UNEXPECTEDEND;
00593                         goto bad;
00594                 }
00595                 GET_MEM(key, len, source->rstart);
00596                 key[len] = '\0';        /* Ensure NUL termination. */
00597                 value = NULL;
00598                 result = value_fromwire(source, &value);
00599                 if (result != ISC_R_SUCCESS)
00600                         goto bad;
00601                 if (isccc_alist_define(alist, key, value) == NULL) {
00602                         result = ISC_R_NOMEMORY;
00603                         goto bad;
00604                 }
00605                 if (first_tag && secret != NULL && strcmp(key, "_auth") == 0)
00606                         checksum_rstart = source->rstart;
00607                 first_tag = ISC_FALSE;
00608         }
00609 
00610         if (secret != NULL) {
00611                 if (checksum_rstart != NULL)
00612                         result = verify(alist, checksum_rstart,
00613                                         (unsigned int)
00614                                         (source->rend - checksum_rstart),
00615                                         algorithm, secret);
00616                 else
00617                         result = ISCCC_R_BADAUTH;
00618         } else
00619                 result = ISC_R_SUCCESS;
00620 
00621  bad:
00622         if (result == ISC_R_SUCCESS)
00623                 *alistp = alist;
00624         else
00625                 isccc_sexpr_free(&alist);
00626 
00627         return (result);
00628 }
00629 
00630 static isc_result_t
00631 list_fromwire(isccc_region_t *source, isccc_sexpr_t **listp)
00632 {
00633         isccc_sexpr_t *list, *value;
00634         isc_result_t result;
00635 
00636         list = NULL;
00637         while (!REGION_EMPTY(*source)) {
00638                 value = NULL;
00639                 result = value_fromwire(source, &value);
00640                 if (result != ISC_R_SUCCESS) {
00641                         isccc_sexpr_free(&list);
00642                         return (result);
00643                 }
00644                 if (isccc_sexpr_addtolist(&list, value) == NULL) {
00645                         isccc_sexpr_free(&value);
00646                         isccc_sexpr_free(&list);
00647                         return (result);
00648                 }
00649         }
00650 
00651         *listp = list;
00652 
00653         return (ISC_R_SUCCESS);
00654 }
00655 
00656 isc_result_t
00657 isccc_cc_fromwire(isccc_region_t *source, isccc_sexpr_t **alistp,
00658                   isc_uint32_t algorithm, isccc_region_t *secret)
00659 {
00660         unsigned int size;
00661         isc_uint32_t version;
00662 
00663         size = REGION_SIZE(*source);
00664         if (size < 4)
00665                 return (ISC_R_UNEXPECTEDEND);
00666         GET32(version, source->rstart);
00667         if (version != 1)
00668                 return (ISCCC_R_UNKNOWNVERSION);
00669 
00670         return (table_fromwire(source, secret, algorithm, alistp));
00671 }
00672 
00673 static isc_result_t
00674 createmessage(isc_uint32_t version, const char *from, const char *to,
00675               isc_uint32_t serial, isccc_time_t now,
00676               isccc_time_t expires, isccc_sexpr_t **alistp,
00677               isc_boolean_t want_expires)
00678 {
00679         isccc_sexpr_t *alist, *_ctrl, *_data;
00680         isc_result_t result;
00681 
00682         REQUIRE(alistp != NULL && *alistp == NULL);
00683 
00684         if (version != 1)
00685                 return (ISCCC_R_UNKNOWNVERSION);
00686 
00687         alist = isccc_alist_create();
00688         if (alist == NULL)
00689                 return (ISC_R_NOMEMORY);
00690 
00691         result = ISC_R_NOMEMORY;
00692 
00693         _ctrl = isccc_alist_create();
00694         if (_ctrl == NULL)
00695                 goto bad;
00696         if (isccc_alist_define(alist, "_ctrl", _ctrl) == NULL) {
00697                 isccc_sexpr_free(&_ctrl);
00698                 goto bad;
00699         }
00700 
00701         _data = isccc_alist_create();
00702         if (_data == NULL)
00703                 goto bad;
00704         if (isccc_alist_define(alist, "_data", _data) == NULL) {
00705                 isccc_sexpr_free(&_data);
00706                 goto bad;
00707         }
00708 
00709         if (isccc_cc_defineuint32(_ctrl, "_ser", serial) == NULL ||
00710             isccc_cc_defineuint32(_ctrl, "_tim", now) == NULL ||
00711             (want_expires &&
00712              isccc_cc_defineuint32(_ctrl, "_exp", expires) == NULL))
00713                 goto bad;
00714         if (from != NULL &&
00715             isccc_cc_definestring(_ctrl, "_frm", from) == NULL)
00716                 goto bad;
00717         if (to != NULL &&
00718             isccc_cc_definestring(_ctrl, "_to", to) == NULL)
00719                 goto bad;
00720 
00721         *alistp = alist;
00722 
00723         return (ISC_R_SUCCESS);
00724 
00725  bad:
00726         isccc_sexpr_free(&alist);
00727 
00728         return (result);
00729 }
00730 
00731 isc_result_t
00732 isccc_cc_createmessage(isc_uint32_t version, const char *from, const char *to,
00733                        isc_uint32_t serial, isccc_time_t now,
00734                        isccc_time_t expires, isccc_sexpr_t **alistp)
00735 {
00736         return (createmessage(version, from, to, serial, now, expires,
00737                               alistp, ISC_TRUE));
00738 }
00739 
00740 isc_result_t
00741 isccc_cc_createack(isccc_sexpr_t *message, isc_boolean_t ok,
00742                    isccc_sexpr_t **ackp)
00743 {
00744         char *_frm, *_to;
00745         isc_uint32_t serial;
00746         isccc_sexpr_t *ack, *_ctrl;
00747         isc_result_t result;
00748         isccc_time_t t;
00749 
00750         REQUIRE(ackp != NULL && *ackp == NULL);
00751 
00752         _ctrl = isccc_alist_lookup(message, "_ctrl");
00753         if (_ctrl == NULL ||
00754             isccc_cc_lookupuint32(_ctrl, "_ser", &serial) != ISC_R_SUCCESS ||
00755             isccc_cc_lookupuint32(_ctrl, "_tim", &t) != ISC_R_SUCCESS)
00756                 return (ISC_R_FAILURE);
00757         /*
00758          * _frm and _to are optional.
00759          */
00760         _frm = NULL;
00761         (void)isccc_cc_lookupstring(_ctrl, "_frm", &_frm);
00762         _to = NULL;
00763         (void)isccc_cc_lookupstring(_ctrl, "_to", &_to);
00764         /*
00765          * Create the ack.
00766          */
00767         ack = NULL;
00768         result = createmessage(1, _to, _frm, serial, t, 0, &ack, ISC_FALSE);
00769         if (result != ISC_R_SUCCESS)
00770                 return (result);
00771 
00772         _ctrl = isccc_alist_lookup(ack, "_ctrl");
00773         if (_ctrl == NULL) {
00774                 result = ISC_R_FAILURE;
00775                 goto bad;
00776         }
00777         if (isccc_cc_definestring(ack, "_ack", (ok) ? "1" : "0") == NULL) {
00778                 result = ISC_R_NOMEMORY;
00779                 goto bad;
00780         }
00781 
00782         *ackp = ack;
00783 
00784         return (ISC_R_SUCCESS);
00785 
00786  bad:
00787         isccc_sexpr_free(&ack);
00788 
00789         return (result);
00790 }
00791 
00792 isc_boolean_t
00793 isccc_cc_isack(isccc_sexpr_t *message)
00794 {
00795         isccc_sexpr_t *_ctrl;
00796 
00797         _ctrl = isccc_alist_lookup(message, "_ctrl");
00798         if (_ctrl == NULL)
00799                 return (ISC_FALSE);
00800         if (isccc_cc_lookupstring(_ctrl, "_ack", NULL) == ISC_R_SUCCESS)
00801                 return (ISC_TRUE);
00802         return (ISC_FALSE);
00803 }
00804 
00805 isc_boolean_t
00806 isccc_cc_isreply(isccc_sexpr_t *message)
00807 {
00808         isccc_sexpr_t *_ctrl;
00809 
00810         _ctrl = isccc_alist_lookup(message, "_ctrl");
00811         if (_ctrl == NULL)
00812                 return (ISC_FALSE);
00813         if (isccc_cc_lookupstring(_ctrl, "_rpl", NULL) == ISC_R_SUCCESS)
00814                 return (ISC_TRUE);
00815         return (ISC_FALSE);
00816 }
00817 
00818 isc_result_t
00819 isccc_cc_createresponse(isccc_sexpr_t *message, isccc_time_t now,
00820                         isccc_time_t expires, isccc_sexpr_t **alistp)
00821 {
00822         char *_frm, *_to, *type = NULL;
00823         isc_uint32_t serial;
00824         isccc_sexpr_t *alist, *_ctrl, *_data;
00825         isc_result_t result;
00826 
00827         REQUIRE(alistp != NULL && *alistp == NULL);
00828 
00829         _ctrl = isccc_alist_lookup(message, "_ctrl");
00830         _data = isccc_alist_lookup(message, "_data");
00831         if (_ctrl == NULL || _data == NULL ||
00832             isccc_cc_lookupuint32(_ctrl, "_ser", &serial) != ISC_R_SUCCESS ||
00833             isccc_cc_lookupstring(_data, "type", &type) != ISC_R_SUCCESS)
00834                 return (ISC_R_FAILURE);
00835         /*
00836          * _frm and _to are optional.
00837          */
00838         _frm = NULL;
00839         (void)isccc_cc_lookupstring(_ctrl, "_frm", &_frm);
00840         _to = NULL;
00841         (void)isccc_cc_lookupstring(_ctrl, "_to", &_to);
00842         /*
00843          * Create the response.
00844          */
00845         alist = NULL;
00846         result = isccc_cc_createmessage(1, _to, _frm, serial, now, expires,
00847                                          &alist);
00848         if (result != ISC_R_SUCCESS)
00849                 return (result);
00850 
00851         _ctrl = isccc_alist_lookup(alist, "_ctrl");
00852         if (_ctrl == NULL) {
00853                 result = ISC_R_FAILURE;
00854                 goto bad;
00855         }
00856 
00857         _data = isccc_alist_lookup(alist, "_data");
00858         if (_data == NULL) {
00859                 result = ISC_R_FAILURE;
00860                 goto bad;
00861         }
00862 
00863         if (isccc_cc_definestring(_ctrl, "_rpl", "1") == NULL ||
00864             isccc_cc_definestring(_data, "type", type) == NULL)
00865         {
00866                 result = ISC_R_NOMEMORY;
00867                 goto bad;
00868         }
00869 
00870         *alistp = alist;
00871 
00872         return (ISC_R_SUCCESS);
00873 
00874  bad:
00875         isccc_sexpr_free(&alist);
00876         return (result);
00877 }
00878 
00879 isccc_sexpr_t *
00880 isccc_cc_definestring(isccc_sexpr_t *alist, const char *key, const char *str)
00881 {
00882         size_t len;
00883         isccc_region_t r;
00884 
00885         len = strlen(str);
00886         DE_CONST(str, r.rstart);
00887         r.rend = r.rstart + len;
00888 
00889         return (isccc_alist_definebinary(alist, key, &r));
00890 }
00891 
00892 isccc_sexpr_t *
00893 isccc_cc_defineuint32(isccc_sexpr_t *alist, const char *key, isc_uint32_t i)
00894 {
00895         char b[100];
00896         size_t len;
00897         isccc_region_t r;
00898 
00899         snprintf(b, sizeof(b), "%u", i);
00900         len = strlen(b);
00901         r.rstart = (unsigned char *)b;
00902         r.rend = (unsigned char *)b + len;
00903 
00904         return (isccc_alist_definebinary(alist, key, &r));
00905 }
00906 
00907 isc_result_t
00908 isccc_cc_lookupstring(isccc_sexpr_t *alist, const char *key, char **strp)
00909 {
00910         isccc_sexpr_t *kv, *v;
00911 
00912         REQUIRE(strp == NULL || *strp == NULL);
00913 
00914         kv = isccc_alist_assq(alist, key);
00915         if (kv != NULL) {
00916                 v = ISCCC_SEXPR_CDR(kv);
00917                 if (isccc_sexpr_binaryp(v)) {
00918                         if (strp != NULL)
00919                                 *strp = isccc_sexpr_tostring(v);
00920                         return (ISC_R_SUCCESS);
00921                 } else
00922                         return (ISC_R_EXISTS);
00923         }
00924 
00925         return (ISC_R_NOTFOUND);
00926 }
00927 
00928 isc_result_t
00929 isccc_cc_lookupuint32(isccc_sexpr_t *alist, const char *key,
00930                       isc_uint32_t *uintp)
00931 {
00932         isccc_sexpr_t *kv, *v;
00933 
00934         kv = isccc_alist_assq(alist, key);
00935         if (kv != NULL) {
00936                 v = ISCCC_SEXPR_CDR(kv);
00937                 if (isccc_sexpr_binaryp(v)) {
00938                         if (uintp != NULL)
00939                                 *uintp = (isc_uint32_t)
00940                                         strtoul(isccc_sexpr_tostring(v),
00941                                                 NULL, 10);
00942                         return (ISC_R_SUCCESS);
00943                 } else
00944                         return (ISC_R_EXISTS);
00945         }
00946 
00947         return (ISC_R_NOTFOUND);
00948 }
00949 
00950 static void
00951 symtab_undefine(char *key, unsigned int type, isccc_symvalue_t value,
00952                 void *arg)
00953 {
00954         UNUSED(type);
00955         UNUSED(value);
00956         UNUSED(arg);
00957 
00958         free(key);
00959 }
00960 
00961 static isc_boolean_t
00962 symtab_clean(char *key, unsigned int type, isccc_symvalue_t value,
00963              void *arg)
00964 {
00965         isccc_time_t *now;
00966 
00967         UNUSED(key);
00968         UNUSED(type);
00969 
00970         now = arg;
00971 
00972         if (*now < value.as_uinteger)
00973                 return (ISC_FALSE);
00974         if ((*now - value.as_uinteger) < DUP_LIFETIME)
00975                 return (ISC_FALSE);
00976         return (ISC_TRUE);
00977 }
00978 
00979 isc_result_t
00980 isccc_cc_createsymtab(isccc_symtab_t **symtabp)
00981 {
00982         return (isccc_symtab_create(11897, symtab_undefine, NULL, ISC_FALSE,
00983                                   symtabp));
00984 }
00985 
00986 void
00987 isccc_cc_cleansymtab(isccc_symtab_t *symtab, isccc_time_t now)
00988 {
00989         isccc_symtab_foreach(symtab, symtab_clean, &now);
00990 }
00991 
00992 static isc_boolean_t
00993 has_whitespace(const char *str)
00994 {
00995         char c;
00996 
00997         if (str == NULL)
00998                 return (ISC_FALSE);
00999         while ((c = *str++) != '\0') {
01000                 if (c == ' ' || c == '\t' || c == '\n')
01001                         return (ISC_TRUE);
01002         }
01003         return (ISC_FALSE);
01004 }
01005 
01006 isc_result_t
01007 isccc_cc_checkdup(isccc_symtab_t *symtab, isccc_sexpr_t *message,
01008                   isccc_time_t now)
01009 {
01010         const char *_frm;
01011         const char *_to;
01012         char *_ser = NULL, *_tim = NULL, *tmp;
01013         isc_result_t result;
01014         char *key;
01015         size_t len;
01016         isccc_symvalue_t value;
01017         isccc_sexpr_t *_ctrl;
01018 
01019         _ctrl = isccc_alist_lookup(message, "_ctrl");
01020         if (_ctrl == NULL ||
01021             isccc_cc_lookupstring(_ctrl, "_ser", &_ser) != ISC_R_SUCCESS ||
01022             isccc_cc_lookupstring(_ctrl, "_tim", &_tim) != ISC_R_SUCCESS)
01023                 return (ISC_R_FAILURE);
01024 
01025         INSIST(_ser != NULL);
01026         INSIST(_tim != NULL);
01027 
01028         /*
01029          * _frm and _to are optional.
01030          */
01031         tmp = NULL;
01032         if (isccc_cc_lookupstring(_ctrl, "_frm", &tmp) != ISC_R_SUCCESS)
01033                 _frm = "";
01034         else
01035                 _frm = tmp;
01036         tmp = NULL;
01037         if (isccc_cc_lookupstring(_ctrl, "_to", &tmp) != ISC_R_SUCCESS)
01038                 _to = "";
01039         else
01040                 _to = tmp;
01041         /*
01042          * Ensure there is no newline in any of the strings.  This is so
01043          * we can write them to a file later.
01044          */
01045         if (has_whitespace(_frm) || has_whitespace(_to) ||
01046             has_whitespace(_ser) || has_whitespace(_tim))
01047                 return (ISC_R_FAILURE);
01048         len = strlen(_frm) + strlen(_to) + strlen(_ser) + strlen(_tim) + 4;
01049         key = malloc(len);
01050         if (key == NULL)
01051                 return (ISC_R_NOMEMORY);
01052         snprintf(key, len, "%s;%s;%s;%s", _frm, _to, _ser, _tim);
01053         value.as_uinteger = now;
01054         result = isccc_symtab_define(symtab, key, ISCCC_SYMTYPE_CCDUP, value,
01055                                    isccc_symexists_reject);
01056         if (result != ISC_R_SUCCESS) {
01057                 free(key);
01058                 return (result);
01059         }
01060 
01061         return (ISC_R_SUCCESS);
01062 }

Generated on Tue Apr 28 17:41:06 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha