isc_result_t isccc_cc_lookupstring(isccc_sexpr_t *alist, const char *key, char **strp) { isccc_sexpr_t *kv, *v; kv = isccc_alist_assq(alist, key); if (kv != NULL) { v = ISCCC_SEXPR_CDR(kv); if (isccc_sexpr_binaryp(v)) { if (strp != NULL) *strp = isccc_sexpr_tostring(v); return (ISC_R_SUCCESS); } else return (ISC_R_EXISTS); } return (ISC_R_NOTFOUND); }
isc_result_t isccc_alist_lookupbinary(isccc_sexpr_t *alist, const char *key, isccc_region_t **r) { isccc_sexpr_t *kv, *v; kv = isccc_alist_assq(alist, key); if (kv != NULL) { v = CDR(kv); if (isccc_sexpr_binaryp(v)) { if (r != NULL) *r = isccc_sexpr_tobinary(v); return (ISC_R_SUCCESS); } else return (ISC_R_EXISTS); } return (ISC_R_NOTFOUND); }
isc_result_t isccc_cc_lookupuint32(isccc_sexpr_t *alist, const char *key, isc_uint32_t *uintp) { isccc_sexpr_t *kv, *v; kv = isccc_alist_assq(alist, key); if (kv != NULL) { v = ISCCC_SEXPR_CDR(kv); if (isccc_sexpr_binaryp(v)) { if (uintp != NULL) *uintp = (isc_uint32_t) strtoul(isccc_sexpr_tostring(v), NULL, 10); return (ISC_R_SUCCESS); } else return (ISC_R_EXISTS); } return (ISC_R_NOTFOUND); }
static isc_result_t value_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_t verify(isccc_sexpr_t *alist, unsigned char *data, unsigned int length, isc_uint32_t algorithm, isccc_region_t *secret) { union { isc_hmacmd5_t hmd5; isc_hmacsha1_t hsha; isc_hmacsha224_t h224; isc_hmacsha256_t h256; isc_hmacsha384_t h384; isc_hmacsha512_t h512; } ctx; isccc_region_t source; isccc_region_t target; isc_result_t result; isccc_sexpr_t *_auth, *hmac; unsigned char digest[ISC_SHA512_DIGESTLENGTH]; unsigned char digestb64[HSHA_LENGTH * 4]; /* * Extract digest. */ _auth = isccc_alist_lookup(alist, "_auth"); if (!isccc_alist_alistp(_auth)) return (ISC_R_FAILURE); if (algorithm == ISCCC_ALG_HMACMD5) hmac = isccc_alist_lookup(_auth, "hmd5"); else hmac = isccc_alist_lookup(_auth, "hsha"); if (!isccc_sexpr_binaryp(hmac)) return (ISC_R_FAILURE); /* * Compute digest. */ source.rstart = digest; target.rstart = digestb64; switch (algorithm) { case ISCCC_ALG_HMACMD5: isc_hmacmd5_init(&ctx.hmd5, secret->rstart, REGION_SIZE(*secret)); isc_hmacmd5_update(&ctx.hmd5, data, length); isc_hmacmd5_sign(&ctx.hmd5, digest); source.rend = digest + ISC_MD5_DIGESTLENGTH; break; case ISCCC_ALG_HMACSHA1: isc_hmacsha1_init(&ctx.hsha, secret->rstart, REGION_SIZE(*secret)); isc_hmacsha1_update(&ctx.hsha, data, length); isc_hmacsha1_sign(&ctx.hsha, digest, ISC_SHA1_DIGESTLENGTH); source.rend = digest + ISC_SHA1_DIGESTLENGTH; break; case ISCCC_ALG_HMACSHA224: isc_hmacsha224_init(&ctx.h224, secret->rstart, REGION_SIZE(*secret)); isc_hmacsha224_update(&ctx.h224, data, length); isc_hmacsha224_sign(&ctx.h224, digest, ISC_SHA224_DIGESTLENGTH); source.rend = digest + ISC_SHA224_DIGESTLENGTH; break; case ISCCC_ALG_HMACSHA256: isc_hmacsha256_init(&ctx.h256, secret->rstart, REGION_SIZE(*secret)); isc_hmacsha256_update(&ctx.h256, data, length); isc_hmacsha256_sign(&ctx.h256, digest, ISC_SHA256_DIGESTLENGTH); source.rend = digest + ISC_SHA256_DIGESTLENGTH; break; case ISCCC_ALG_HMACSHA384: isc_hmacsha384_init(&ctx.h384, secret->rstart, REGION_SIZE(*secret)); isc_hmacsha384_update(&ctx.h384, data, length); isc_hmacsha384_sign(&ctx.h384, digest, ISC_SHA384_DIGESTLENGTH); source.rend = digest + ISC_SHA384_DIGESTLENGTH; break; case ISCCC_ALG_HMACSHA512: isc_hmacsha512_init(&ctx.h512, secret->rstart, REGION_SIZE(*secret)); isc_hmacsha512_update(&ctx.h512, data, length); isc_hmacsha512_sign(&ctx.h512, digest, ISC_SHA512_DIGESTLENGTH); source.rend = digest + ISC_SHA512_DIGESTLENGTH; break; default: return (ISC_R_FAILURE); } target.rstart = digestb64; target.rend = digestb64 + sizeof(digestb64); memset(digestb64, 0, sizeof(digestb64)); result = isccc_base64_encode(&source, 64, "", &target); if (result != ISC_R_SUCCESS) return (result); /* * Verify. */ if (algorithm == ISCCC_ALG_HMACMD5) { unsigned char *value; value = (unsigned char *) isccc_sexpr_tostring(hmac); if (!isc_safe_memequal(value, digestb64, HMD5_LENGTH)) return (ISCCC_R_BADAUTH); } else { unsigned char *value; isc_uint32_t valalg; value = (unsigned char *) isccc_sexpr_tostring(hmac); GET8(valalg, value); if ((valalg != algorithm) || !isc_safe_memequal(value, digestb64, HSHA_LENGTH)) return (ISCCC_R_BADAUTH); } return (ISC_R_SUCCESS); }