stl_string calc_mac (DnsRR &tsig_rr, message_buff msg, stl_string sign_key, message_buff *extra) { struct hmac_md5_ctx md5; unsigned char md5res [MD5_DIGEST_SIZE]; memset (&md5, 0, sizeof (hmac_md5_ctx)); unsigned char *digestpos = rr_getdata (tsig_rr.RDATA, DNS_TYPE_TSIG, 3); uint16_t digestlen = uint16_value (digestpos); // print_buff (sign_key.size(), (unsigned char*)sign_key.c_str()); hmac_md5_set_key(&md5, sign_key.size(), (uint8_t *)sign_key.c_str()); // printf ("Begin MAC calculation\n"); /* original MAC */ if (extra && extra->len) hmac_md5_update(&md5, extra->len, extra->msg); /* message */ hmac_md5_update(&md5, 10, msg.msg); hmac_md5_update(&md5, 2, uint16_buff (uint16_value (msg.msg + 10) - 1)); hmac_md5_update(&md5, msg.len - 12, msg.msg + 12); /* tsig rr */ stl_string canname = tsig_rr.NAME.canonical(); hmac_md5_update(&md5, canname.size(), (const uint8_t *)canname.c_str()); hmac_md5_update(&md5, 2, uint16_buff (QCLASS_ANY)); hmac_md5_update(&md5, 4, uint32_buff (0)); /* start of TSIG rrdata */ domainname dom = domainname (true, tsig_rr.RDATA); canname = dom.canonical(); hmac_md5_update (&md5, canname.size(), (const uint8_t*)canname.c_str()); hmac_md5_update(&md5, 8, digestpos - 8); /* rest, excluding original ID */ hmac_md5_update(&md5, tsig_rr.RDLENGTH - (digestpos - tsig_rr.RDATA) - digestlen - 4, digestpos + digestlen + 4); hmac_md5_digest(&md5, MD5_DIGEST_SIZE, md5res); // printf ("End MAC calculation\n"); // print_buff (MD5_DIGEST_SIZE, md5res); stl_string ret; ret.append ((char*)md5res, MD5_DIGEST_SIZE); return ret; }
bool disk_init(sd_disk *sd) { uint32_t pstart = 0; uint16_t psize = 0; // // Find MBR and First partition and get fat and root directory from them // if (sd_read_block(0, sd) && BLOCK_EQ(510,0x55) && BLOCK_EQ(511,0xAA) && BLOCK_EQ(P1_START+4,0x04)) { pstart = uint32_value(sd->buf+P1_START+8); if (pstart != 0 && sd_read_block(pstart, sd)) { // fat start = pstart + number reserved sectors sd->fat_start = pstart + uint16_value(sd->buf+14); sd->p_size = uint16_value(sd->buf+19); // root_dir start = <fat start> + <fat size> * <number of fats>; sd->root_dir = sd->fat_start + uint8_value(sd->buf+16) * uint16_value(sd->buf+22); // data_start = <root_dir start> + <num root entries> * 32 / 512 sd->data_start = sd->root_dir + (uint16_value(sd->buf+17) >> 4); return true; }
/// @brief verifies TSIG of received response /// /// Make sure that message_buff is trimmed down to not include TSIG /// record, as it must be passed in message_tsig. /// /// @param check_tsig TSIG RR from the original message /// @param message_tsig TSIR RR from the response message that we are validating /// @param key the key used for signing /// @param message received message (without TSIG record) void verify_signature (DnsRR *check_tsig, DnsRR *message_tsig, stl_string key, message_buff message) { if (!message_tsig) throw PException (true, "Unsigned answer to a signed message (key %s)", check_tsig->NAME.tocstr ()); unsigned char *errorptr = rr_getdata (check_tsig->RDATA, DNS_TYPE_TSIG, 5); domainname alg_name = rr_getdomain (check_tsig->RDATA, DNS_TYPE_TSIG), rr_alg_name = rr_getdomain (message_tsig->RDATA, DNS_TYPE_TSIG); if (rr_alg_name != alg_name || check_tsig->NAME != message_tsig->NAME) { memcpy (errorptr, uint16_buff (RCODE_BADKEY), 2); throw PException (true, "Key name/algorithm does not match: question signed with %s, answer " "signed with %s", check_tsig->NAME.tocstr(), message_tsig->NAME.tocstr()); } unsigned char *rr_macpos = rr_getdata (message_tsig->RDATA, DNS_TYPE_TSIG, 3), *macpos = rr_getdata (check_tsig->RDATA, DNS_TYPE_TSIG, 3); uint16_t rr_maclen = uint16_value (rr_macpos), maclen = uint16_value (macpos); if ((message.msg[3] & 15) == RCODE_NOTAUTH) { /* error! */ uint16_t err = rr_getshort (message_tsig->RDATA, DNS_TYPE_TSIG, 5); if (err == RCODE_BADSIG) throw PException (true, "Question signed with %s had bad signature", check_tsig->NAME.tocstr()); else if (err == RCODE_BADKEY) throw PException (true, "Question was signed with bad key (%s)", check_tsig->NAME.tocstr()); else if (err == RCODE_BADTIME) throw PException (true, "Question sign time invalid (query time %d, answer time %d)", uint48_value (rr_getdata (check_tsig->RDATA, DNS_TYPE_TSIG, 1)), uint48_value (rr_getdata (message_tsig->RDATA, DNS_TYPE_TSIG, 1))); else throw PException (true, "Unknown sign error: %d", err); } time_t clienttime = time (NULL); u_int48 servertime = uint48_value (rr_getdata (check_tsig->RDATA, DNS_TYPE_TSIG, 1)); uint16_t fudge = rr_getshort (check_tsig->RDATA, DNS_TYPE_TSIG, 2); if ( (clienttime > servertime && clienttime - servertime > fudge) || (servertime > clienttime && servertime - clienttime > fudge) ) { throw PException (true, "Answer sign time invalid (answer time %d, real time %d)", uint48_value (rr_getdata (message_tsig->RDATA, DNS_TYPE_TSIG, 1)), clienttime); // TODO: set TSIG error of check_tsig for servers } if (rr_maclen != MD5_DIGEST_SIZE) { memcpy (errorptr, uint16_buff (RCODE_BADSIG), 2); throw PException (true, "Incorrect MAC size: %d", rr_maclen); } /* calculate MAC */ message_buff ext; /* TODO: document: if this is from a message, it actually means that the message was unsigned, but we should still include the two length */ if (maclen) ext = message_buff (macpos, maclen + 2); stl_string mac = calc_mac (*message_tsig, message, key, &ext); if (memcmp (mac.c_str(), rr_macpos + 2, MD5_DIGEST_SIZE) != 0) { memcpy (errorptr, uint16_buff (RCODE_BADSIG), 2); throw PException (true, "Message signed with key %s has bad signature", message_tsig->NAME.tocstr ()); } }