📄 cc.c
字号:
/* * Portions Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 2001-2003 Internet Software Consortium. * Portions Copyright (C) 2001 Nominum, Inc. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *//* $Id: cc.c,v 1.4.2.3.2.5 2004/08/28 06:25:23 marka Exp $ */#include <config.h>#include <stdio.h>#include <string.h>#include <errno.h>#include <isc/assertions.h>#include <isc/hmacmd5.h>#include <isc/print.h>#include <isc/stdlib.h>#include <isccc/alist.h>#include <isccc/base64.h>#include <isccc/cc.h>#include <isccc/result.h>#include <isccc/sexpr.h>#include <isccc/symtab.h>#include <isccc/symtype.h>#include <isccc/util.h>#define MAX_TAGS 256#define DUP_LIFETIME 900typedef isccc_sexpr_t *sexpr_ptr;static unsigned char auth_hmd5[] = { 0x05, 0x5f, 0x61, 0x75, 0x74, 0x68, /* len + _auth */ ISCCC_CCMSGTYPE_TABLE, /* message type */ 0x00, 0x00, 0x00, 0x20, /* length == 32 */ 0x04, 0x68, 0x6d, 0x64, 0x35, /* len + hmd5 */ ISCCC_CCMSGTYPE_BINARYDATA, /* message type */ 0x00, 0x00, 0x00, 0x16, /* length == 22 */ /* * The base64 encoding of one of our HMAC-MD5 signatures is * 22 bytes. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};#define HMD5_OFFSET 21 /* 6 + 1 + 4 + 5 + 1 + 4 */#define HMD5_LENGTH 22static isc_result_ttable_towire(isccc_sexpr_t *alist, isccc_region_t *target);static isc_result_tlist_towire(isccc_sexpr_t *alist, isccc_region_t *target);static isc_result_tvalue_towire(isccc_sexpr_t *elt, isccc_region_t *target){ size_t len; unsigned char *lenp; isccc_region_t *vr; isc_result_t result; if (isccc_sexpr_binaryp(elt)) { vr = isccc_sexpr_tobinary(elt); len = REGION_SIZE(*vr); if (REGION_SIZE(*target) < 1 + 4 + len) return (ISC_R_NOSPACE); PUT8(ISCCC_CCMSGTYPE_BINARYDATA, target->rstart); PUT32(len, target->rstart); if (REGION_SIZE(*target) < len) return (ISC_R_NOSPACE); PUT_MEM(vr->rstart, len, target->rstart); } else if (isccc_alist_alistp(elt)) { if (REGION_SIZE(*target) < 1 + 4) return (ISC_R_NOSPACE); PUT8(ISCCC_CCMSGTYPE_TABLE, target->rstart); /* * Emit a placeholder length. */ lenp = target->rstart; PUT32(0, target->rstart); /* * Emit the table. */ result = table_towire(elt, target); if (result != ISC_R_SUCCESS) return (result); len = (size_t)(target->rstart - lenp); /* * 'len' is 4 bytes too big, since it counts * the placeholder length too. Adjust and * emit. */ INSIST(len >= 4U); len -= 4; PUT32(len, lenp); } else if (isccc_sexpr_listp(elt)) { if (REGION_SIZE(*target) < 1 + 4) return (ISC_R_NOSPACE); PUT8(ISCCC_CCMSGTYPE_LIST, target->rstart); /* * Emit a placeholder length and count. */ lenp = target->rstart; PUT32(0, target->rstart); /* * Emit the list. */ result = list_towire(elt, target); if (result != ISC_R_SUCCESS) return (result); len = (size_t)(target->rstart - lenp); /* * 'len' is 4 bytes too big, since it counts * the placeholder length. Adjust and emit. */ INSIST(len >= 4U); len -= 4; PUT32(len, lenp); } return (ISC_R_SUCCESS);}static isc_result_ttable_towire(isccc_sexpr_t *alist, isccc_region_t *target){ isccc_sexpr_t *kv, *elt, *k, *v; char *ks; isc_result_t result; size_t len; for (elt = isccc_alist_first(alist); elt != NULL; elt = ISCCC_SEXPR_CDR(elt)) { kv = ISCCC_SEXPR_CAR(elt); k = ISCCC_SEXPR_CAR(kv); ks = isccc_sexpr_tostring(k); v = ISCCC_SEXPR_CDR(kv); len = strlen(ks); INSIST(len <= 255U); /* * Emit the key name. */ if (REGION_SIZE(*target) < 1 + len) return (ISC_R_NOSPACE); PUT8(len, target->rstart); PUT_MEM(ks, len, target->rstart); /* * Emit the value. */ result = value_towire(v, target); if (result != ISC_R_SUCCESS) return (result); } return (ISC_R_SUCCESS);}static isc_result_tlist_towire(isccc_sexpr_t *list, isccc_region_t *target){ isc_result_t result; while (list != NULL) { result = value_towire(ISCCC_SEXPR_CAR(list), target); if (result != ISC_R_SUCCESS) return (result); list = ISCCC_SEXPR_CDR(list); } return (ISC_R_SUCCESS);}static isc_result_tsign(unsigned char *data, unsigned int length, unsigned char *hmd5, isccc_region_t *secret){ isc_hmacmd5_t ctx; isc_result_t result; isccc_region_t source, target; unsigned char digest[ISC_MD5_DIGESTLENGTH]; unsigned char digestb64[ISC_MD5_DIGESTLENGTH * 4]; isc_hmacmd5_init(&ctx, secret->rstart, REGION_SIZE(*secret)); isc_hmacmd5_update(&ctx, data, length); isc_hmacmd5_sign(&ctx, digest); source.rstart = digest; source.rend = digest + ISC_MD5_DIGESTLENGTH; target.rstart = digestb64; target.rend = digestb64 + ISC_MD5_DIGESTLENGTH * 4; result = isccc_base64_encode(&source, 64, "", &target); if (result != ISC_R_SUCCESS) return (result); PUT_MEM(digestb64, HMD5_LENGTH, hmd5); return (ISC_R_SUCCESS);}isc_result_tisccc_cc_towire(isccc_sexpr_t *alist, isccc_region_t *target, isccc_region_t *secret){ unsigned char *hmd5_rstart, *signed_rstart; isc_result_t result; if (REGION_SIZE(*target) < 4 + sizeof(auth_hmd5)) return (ISC_R_NOSPACE); /* * Emit protocol version. */ PUT32(1, target->rstart); if (secret != NULL) { /* * Emit _auth section with zeroed HMAC-MD5 signature. * We'll replace the zeros with the real signature once * we know what it is. */ hmd5_rstart = target->rstart + HMD5_OFFSET; PUT_MEM(auth_hmd5, sizeof(auth_hmd5), target->rstart); } else hmd5_rstart = NULL; signed_rstart = target->rstart; /* * Delete any existing _auth section so that we don't try * to encode it. */ isccc_alist_delete(alist, "_auth"); /* * Emit the message. */ result = table_towire(alist, target); if (result != ISC_R_SUCCESS) return (result); if (secret != NULL) return (sign(signed_rstart, (target->rstart - signed_rstart), hmd5_rstart, secret)); return (ISC_R_SUCCESS);}static isc_result_tverify(isccc_sexpr_t *alist, unsigned char *data, unsigned int length, isccc_region_t *secret){ isc_hmacmd5_t ctx; isccc_region_t source; isccc_region_t target; isc_result_t result; isccc_sexpr_t *_auth, *hmd5; unsigned char digest[ISC_MD5_DIGESTLENGTH]; unsigned char digestb64[ISC_MD5_DIGESTLENGTH * 4]; /* * Extract digest. */ _auth = isccc_alist_lookup(alist, "_auth"); if (_auth == NULL) return (ISC_R_FAILURE); hmd5 = isccc_alist_lookup(_auth, "hmd5"); if (hmd5 == NULL) return (ISC_R_FAILURE); /* * Compute digest. */ isc_hmacmd5_init(&ctx, secret->rstart, REGION_SIZE(*secret)); isc_hmacmd5_update(&ctx, data, length); isc_hmacmd5_sign(&ctx, digest); source.rstart = digest; source.rend = digest + ISC_MD5_DIGESTLENGTH; target.rstart = digestb64; target.rend = digestb64 + ISC_MD5_DIGESTLENGTH * 4; result = isccc_base64_encode(&source, 64, "", &target); if (result != ISC_R_SUCCESS) return (result); /* * Strip trailing == and NUL terminate target. */ target.rstart -= 2; *target.rstart++ = '\0'; /* * Verify. */ if (strcmp((char *)digestb64, isccc_sexpr_tostring(hmd5)) != 0) return (ISCCC_R_BADAUTH); return (ISC_R_SUCCESS);}static isc_result_ttable_fromwire(isccc_region_t *source, isccc_region_t *secret, isccc_sexpr_t **alistp);static isc_result_tlist_fromwire(isccc_region_t *source, isccc_sexpr_t **listp);static isc_result_tvalue_fromwire(isccc_region_t *source, isccc_sexpr_t **valuep){ unsigned int msgtype; isc_uint32_t len; isccc_sexpr_t *value; isccc_region_t active; isc_result_t result; if (REGION_SIZE(*source) < 1 + 4) return (ISC_R_UNEXPECTEDEND); GET8(msgtype, source->rstart); GET32(len, source->rstart); if (REGION_SIZE(*source) < len) return (ISC_R_UNEXPECTEDEND); active.rstart = source->rstart; active.rend = active.rstart + len; source->rstart = active.rend; if (msgtype == ISCCC_CCMSGTYPE_BINARYDATA) { value = isccc_sexpr_frombinary(&active); if (value != NULL) { *valuep = value; result = ISC_R_SUCCESS; } else result = ISC_R_NOMEMORY; } else if (msgtype == ISCCC_CCMSGTYPE_TABLE) result = table_fromwire(&active, NULL, valuep); else if (msgtype == ISCCC_CCMSGTYPE_LIST) result = list_fromwire(&active, valuep); else result = ISCCC_R_SYNTAX; return (result);}static isc_result_ttable_fromwire(isccc_region_t *source, isccc_region_t *secret, isccc_sexpr_t **alistp){ char key[256]; isc_uint32_t len; isc_result_t result; isccc_sexpr_t *alist, *value; isc_boolean_t first_tag; unsigned char *checksum_rstart; REQUIRE(alistp != NULL && *alistp == NULL); checksum_rstart = NULL; first_tag = ISC_TRUE; alist = isccc_alist_create(); if (alist == NULL) return (ISC_R_NOMEMORY); while (!REGION_EMPTY(*source)) { GET8(len, source->rstart); if (REGION_SIZE(*source) < len) { result = ISC_R_UNEXPECTEDEND; goto bad; } GET_MEM(key, len, source->rstart); key[len] = '\0'; /* Ensure NUL termination. */ value = NULL; result = value_fromwire(source, &value); if (result != ISC_R_SUCCESS) goto bad; if (isccc_alist_define(alist, key, value) == NULL) { result = ISC_R_NOMEMORY; goto bad; } if (first_tag && secret != NULL && strcmp(key, "_auth") == 0) checksum_rstart = source->rstart; first_tag = ISC_FALSE; } *alistp = alist; if (secret != NULL) { if (checksum_rstart != NULL) return (verify(alist, checksum_rstart, (source->rend - checksum_rstart), secret)); return (ISCCC_R_BADAUTH); } return (ISC_R_SUCCESS); bad: isccc_sexpr_free(&alist); return (result);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -