* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
-
- Change History (most recent first):
-
-$Log: DNSDigest.c,v $
-Revision 1.15.2.1 2006/08/29 06:24:22 cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.15 2006/06/20 04:12:30 cheshire
-<rdar://problem/4490961> DNS Update broken
-
-Revision 1.14 2006/02/25 23:12:07 cheshire
-<rdar://problem/4427969> Fix to avoid code generation warning/error on FreeBSD 7
-
-Revision 1.13 2004/12/16 20:12:59 cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.12 2004/12/03 07:20:50 ksekar
-<rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
-
-Revision 1.11 2004/12/02 01:10:27 cheshire
-Fix to compile cleanly on 64-bit x86
-
-Revision 1.10 2004/11/01 20:36:04 ksekar
-<rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
-
-Revision 1.9 2004/10/26 09:00:12 cheshire
-Save a few bytes by creating HMAC_MD5_AlgName as a C string instead of a 256-byte object
-
-Revision 1.8 2004/09/17 01:08:48 cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
- The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
- declared in that file are ONLY appropriate to single-address-space embedded applications.
- For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.7 2004/08/15 18:36:38 cheshire
-Don't use strcpy() and strlen() on "struct domainname" objects;
-use AssignDomainName() and DomainNameLength() instead
-(A "struct domainname" is a collection of packed pascal strings, not a C string.)
-
-Revision 1.6 2004/06/02 00:17:46 ksekar
-Referenced original OpenSSL license headers in source file description.
-
-Revision 1.5 2004/05/20 18:37:37 cheshire
-Fix compiler warnings
-
-Revision 1.4 2004/04/22 20:28:20 cheshire
-Use existing facility of PutResourceRecordTTL() to update count field for us
-
-Revision 1.3 2004/04/22 03:05:28 cheshire
-kDNSClass_ANY should be kDNSQClass_ANY
-
-Revision 1.2 2004/04/15 00:51:28 bradley
-Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers.
-Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers.
-
-Revision 1.1 2004/04/14 23:09:28 ksekar
-Support for TSIG signed dynamic updates.
-
-
-
-*/
+ */
#ifdef __cplusplus
#pragma warning(disable:4127)
#endif
+
+ // ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Byte Swapping Functions
+#endif
+
+mDNSlocal mDNSu16 NToH16(mDNSu8 * bytes)
+ {
+ return (mDNSu16)((mDNSu16)bytes[0] << 8 | (mDNSu16)bytes[1]);
+ }
+
+mDNSlocal mDNSu32 NToH32(mDNSu8 * bytes)
+ {
+ return (mDNSu32)((mDNSu32) bytes[0] << 24 | (mDNSu32) bytes[1] << 16 | (mDNSu32) bytes[2] << 8 | (mDNSu32)bytes[3]);
+ }
+
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark - MD5 Hash Functions
* Note: machine archetecure specific conditionals from the original sources are turned off, but are left in the code
* to aid in platform-specific optimizations and debugging.
* Sources originally distributed under the following license headers:
- * CommonDigest.c - APSL
+ * CommonDigest.h - APSL
*
* md32_Common.h
* ====================================================================
# define ROTATE(a,n) (unsigned MD32_REG_T)__rlwinm((int)a,n,0,31)
# elif defined(__MC68K__)
/* Motorola specific tweak. <appro@fy.chalmers.se> */
-# define ROTATE(a,n) ( n<24 ? __rol(a,n) : __ror(a,32-n) )
+# define ROTATE(a,n) (n<24 ? __rol(a,n) : __ror(a,32-n))
# else
# define ROTATE(a,n) __rol(a,n)
# endif
*
* <appro@fy.chalmers.se>
*/
+ /*
+ * LLVM is more strict about compatibility of types between input & output constraints,
+ * but we want these to be rotations of 32 bits, not 64, so we explicitly drop the
+ * most significant bytes by casting to an unsigned int.
+ */
# if defined(__i386) || defined(__i386__) || defined(__x86_64) || defined(__x86_64__)
# define ROTATE(a,n) ({ register unsigned int ret; \
asm ( \
"roll %1,%0" \
: "=r"(ret) \
- : "I"(n), "0"(a) \
+ : "I"(n), "0"((unsigned int)a) \
: "cc"); \
ret; \
})
#if !defined(HASH_BLOCK_DATA_ORDER)
while (sw--)
{
- memcpy (p=c->data,data,HASH_CBLOCK);
+ mDNSPlatformMemCopy(p=c->data,data,HASH_CBLOCK);
HASH_BLOCK_DATA_ORDER_ALIGNED(c,p,1);
data+=HASH_CBLOCK;
len-=HASH_CBLOCK;
else
#if !defined(HASH_BLOCK_DATA_ORDER)
{
- memcpy (c->data,data,HASH_CBLOCK);
+ mDNSPlatformMemCopy(c->data,data,HASH_CBLOCK);
HASH_BLOCK_DATA_ORDER_ALIGNED (c,c->data,1);
}
#endif
#endif
-
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark - base64 -> binary conversion
#endif
-static const char Base64[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char Pad64 = '=';
#define mDNSisspace(x) (x == '\t' || x == '\n' || x == '\v' || x == '\f' || x == '\r' || x == ' ')
-static const char *mDNSstrchr(const char *s, int c)
+mDNSlocal const char *mDNSstrchr(const char *s, int c)
{
while (1)
{
// it returns the number of data bytes stored at the target, or -1 on error.
// adapted from BIND sources
-mDNSexport mDNSs32 DNSDigest_Base64ToBin(const char *src, mDNSu8 *target, mDNSu32 targsize)
+mDNSlocal mDNSs32 DNSDigest_Base64ToBin(const char *src, mDNSu8 *target, mDNSu32 targsize)
{
int tarindex, state, ch;
const char *pos;
#define HMAC_MD5_AlgName (*(const domainname*) "\010" "hmac-md5" "\007" "sig-alg" "\003" "reg" "\003" "int")
// Adapted from Appendix, RFC 2104
-mDNSexport void DNSDigest_ConstructHMACKey(uDNS_AuthInfo *info, const mDNSu8 *key, mDNSu32 len)
+mDNSlocal void DNSDigest_ConstructHMACKey(DomainAuthInfo *info, const mDNSu8 *key, mDNSu32 len)
{
MD5_CTX k;
mDNSu8 buf[MD5_LEN];
}
// store key in pads
- mDNSPlatformMemZero(info->key.ipad, HMAC_LEN);
- mDNSPlatformMemZero(info->key.opad, HMAC_LEN);
- mDNSPlatformMemCopy(key, info->key.ipad, len);
- mDNSPlatformMemCopy(key, info->key.opad, len);
+ mDNSPlatformMemZero(info->keydata_ipad, HMAC_LEN);
+ mDNSPlatformMemZero(info->keydata_opad, HMAC_LEN);
+ mDNSPlatformMemCopy(info->keydata_ipad, key, len);
+ mDNSPlatformMemCopy(info->keydata_opad, key, len);
// XOR key with ipad and opad values
for (i = 0; i < HMAC_LEN; i++)
{
- info->key.ipad[i] ^= HMAC_IPAD;
- info->key.opad[i] ^= HMAC_OPAD;
+ info->keydata_ipad[i] ^= HMAC_IPAD;
+ info->keydata_opad[i] ^= HMAC_OPAD;
}
}
-mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16 *numAdditionals, uDNS_AuthInfo *info)
+mDNSexport mDNSs32 DNSDigest_ConstructHMACKeyfromBase64(DomainAuthInfo *info, const char *b64key)
+ {
+ mDNSu8 keybuf[1024];
+ mDNSs32 keylen = DNSDigest_Base64ToBin(b64key, keybuf, sizeof(keybuf));
+ if (keylen < 0) return(keylen);
+ DNSDigest_ConstructHMACKey(info, keybuf, (mDNSu32)keylen);
+ return(keylen);
+ }
+
+mDNSexport void DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAuthInfo *info, mDNSu16 tcode)
{
AuthRecord tsig;
- mDNSu8 *countPtr, *rdata;
+ mDNSu8 *rdata, *const countPtr = (mDNSu8 *)&msg->h.numAdditionals; // Get existing numAdditionals value
mDNSu32 utc32;
mDNSu8 utc48[6];
mDNSu8 digest[MD5_LEN];
mDNSu32 len;
mDNSOpaque16 buf;
MD5_CTX c;
+ mDNSu16 numAdditionals = (mDNSu16)((mDNSu16)countPtr[0] << 8 | countPtr[1]);
// Init MD5 context, digest inner key pad and message
MD5_Init(&c);
- MD5_Update(&c, info->key.ipad, HMAC_LEN);
+ MD5_Update(&c, info->keydata_ipad, HMAC_LEN);
MD5_Update(&c, (mDNSu8 *)msg, (unsigned long)(*end - (mDNSu8 *)msg));
// Construct TSIG RR, digesting variables as apporpriate
- mDNSPlatformMemZero(&tsig, sizeof(AuthRecord));
mDNS_SetupResourceRecord(&tsig, mDNSNULL, 0, kDNSType_TSIG, 0, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
// key name
- AssignDomainName(tsig.resrec.name, &info->keyname);
+ AssignDomainName(&tsig.namestorage, &info->keyname);
MD5_Update(&c, info->keyname.c, DomainNameLength(&info->keyname));
// class
// time
// get UTC (universal time), convert to 48-bit unsigned in network byte order
utc32 = (mDNSu32)mDNSPlatformUTC();
- if (utc32 == (unsigned)-1) { LogMsg("ERROR: DNSDigest_SignMessage - mDNSPlatformUTC returned bad time -1"); return mDNSNULL; }
+ if (utc32 == (unsigned)-1) { LogMsg("ERROR: DNSDigest_SignMessage - mDNSPlatformUTC returned bad time -1"); *end = mDNSNULL; }
utc48[0] = 0;
utc48[1] = 0;
utc48[2] = (mDNSu8)((utc32 >> 24) & 0xff);
utc48[3] = (mDNSu8)((utc32 >> 16) & 0xff);
- utc48[4] = (mDNSu8)((utc32 >> 8) & 0xff);
+ utc48[4] = (mDNSu8)((utc32 >> 8) & 0xff);
utc48[5] = (mDNSu8)( utc32 & 0xff);
- mDNSPlatformMemCopy(utc48, rdata, 6);
+ mDNSPlatformMemCopy(rdata, utc48, 6);
rdata += 6;
MD5_Update(&c, utc48, 6);
MD5_Update(&c, rdata, sizeof(mDNSOpaque16));
rdata += sizeof(mDNSOpaque16);
- // digest error and other data len (both zero) - we'll add them to the rdata later
- buf.NotAnInteger = 0;
+ // digest error (tcode) and other data len (zero) - we'll add them to the rdata later
+ buf.b[0] = (mDNSu8)((tcode >> 8) & 0xff);
+ buf.b[1] = (mDNSu8)( tcode & 0xff);
MD5_Update(&c, buf.b, sizeof(mDNSOpaque16)); // error
+ buf.NotAnInteger = 0;
MD5_Update(&c, buf.b, sizeof(mDNSOpaque16)); // other data len
// finish the message & tsig var hash
// perform outer MD5 (outer key pad, inner digest)
MD5_Init(&c);
- MD5_Update(&c, info->key.opad, HMAC_LEN);
+ MD5_Update(&c, info->keydata_opad, HMAC_LEN);
MD5_Update(&c, digest, MD5_LEN);
MD5_Final(digest, &c);
rdata[0] = (mDNSu8)((MD5_LEN >> 8) & 0xff);
rdata[1] = (mDNSu8)( MD5_LEN & 0xff);
rdata += sizeof(mDNSOpaque16);
- mDNSPlatformMemCopy(digest, rdata, MD5_LEN); // MAC
+ mDNSPlatformMemCopy(rdata, digest, MD5_LEN); // MAC
rdata += MD5_LEN;
rdata[0] = msg->h.id.b[0]; // original ID
rdata[1] = msg->h.id.b[1];
- rdata[2] = 0; // no error
- rdata[3] = 0;
+ rdata[2] = (mDNSu8)((tcode >> 8) & 0xff);
+ rdata[3] = (mDNSu8)( tcode & 0xff);
rdata[4] = 0; // other data len
rdata[5] = 0;
rdata += 6;
tsig.resrec.rdlength = (mDNSu16)(rdata - tsig.resrec.rdata->u.data);
- *end = PutResourceRecordTTLJumbo(msg, ptr, numAdditionals, &tsig.resrec, 0);
- if (!*end) { LogMsg("ERROR: DNSDigest_SignMessage - could not put TSIG"); return mDNSNULL; }
+ *end = PutResourceRecordTTLJumbo(msg, ptr, &numAdditionals, &tsig.resrec, 0);
+ if (!*end) { LogMsg("ERROR: DNSDigest_SignMessage - could not put TSIG"); *end = mDNSNULL; return; }
+
+ // Write back updated numAdditionals value
+ countPtr[0] = (mDNSu8)(numAdditionals >> 8);
+ countPtr[1] = (mDNSu8)(numAdditionals & 0xFF);
+ }
+
+mDNSexport mDNSBool DNSDigest_VerifyMessage(DNSMessage *msg, mDNSu8 *end, LargeCacheRecord * lcr, DomainAuthInfo *info, mDNSu16 * rcode, mDNSu16 * tcode)
+ {
+ mDNSu8 * ptr = (mDNSu8*) &lcr->r.resrec.rdata->u.data;
+ mDNSs32 now;
+ mDNSs32 then;
+ mDNSu8 thisDigest[MD5_LEN];
+ mDNSu8 thatDigest[MD5_LEN];
+ mDNSu32 macsize;
+ mDNSOpaque16 buf;
+ mDNSu8 utc48[6];
+ mDNSs32 delta;
+ mDNSu16 fudge;
+ domainname * algo;
+ MD5_CTX c;
+ mDNSBool ok = mDNSfalse;
+
+ // We only support HMAC-MD5 for now
+
+ algo = (domainname*) ptr;
+
+ if (!SameDomainName(algo, &HMAC_MD5_AlgName))
+ {
+ LogMsg("ERROR: DNSDigest_VerifyMessage - TSIG algorithm not supported: %##s", algo->c);
+ *rcode = kDNSFlag1_RC_NotAuth;
+ *tcode = TSIG_ErrBadKey;
+ ok = mDNSfalse;
+ goto exit;
+ }
+
+ ptr += DomainNameLength(algo);
- // update num additionals
- countPtr = (mDNSu8 *)&msg->h.numAdditionals; // increment (network-byte ordered) header value
- *countPtr++ = (mDNSu8)(*numAdditionals >> 8);
- *countPtr++ = (mDNSu8)(*numAdditionals & 0xFF);
+ // Check the times
+
+ now = mDNSPlatformUTC();
+ if (now == -1)
+ {
+ LogMsg("ERROR: DNSDigest_VerifyMessage - mDNSPlatformUTC returned bad time -1");
+ *rcode = kDNSFlag1_RC_NotAuth;
+ *tcode = TSIG_ErrBadTime;
+ ok = mDNSfalse;
+ goto exit;
+ }
- return *end;
+ // Get the 48 bit time field, skipping over the first word
+
+ utc48[0] = *ptr++;
+ utc48[1] = *ptr++;
+ utc48[2] = *ptr++;
+ utc48[3] = *ptr++;
+ utc48[4] = *ptr++;
+ utc48[5] = *ptr++;
+
+ then = (mDNSs32)NToH32(utc48 + sizeof(mDNSu16));
+
+ fudge = NToH16(ptr);
+
+ ptr += sizeof(mDNSu16);
+
+ delta = (now > then) ? now - then : then - now;
+
+ if (delta > fudge)
+ {
+ LogMsg("ERROR: DNSDigest_VerifyMessage - time skew > %d", fudge);
+ *rcode = kDNSFlag1_RC_NotAuth;
+ *tcode = TSIG_ErrBadTime;
+ ok = mDNSfalse;
+ goto exit;
+ }
+
+ // MAC size
+
+ macsize = (mDNSu32) NToH16(ptr);
+
+ ptr += sizeof(mDNSu16);
+
+ // MAC
+
+ mDNSPlatformMemCopy(thatDigest, ptr, MD5_LEN);
+
+ // Init MD5 context, digest inner key pad and message
+
+ MD5_Init(&c);
+ MD5_Update(&c, info->keydata_ipad, HMAC_LEN);
+ MD5_Update(&c, (mDNSu8*) msg, (unsigned long)(end - (mDNSu8*) msg));
+
+ // Key name
+
+ MD5_Update(&c, lcr->r.resrec.name->c, DomainNameLength(lcr->r.resrec.name));
+
+ // Class name
+
+ buf = mDNSOpaque16fromIntVal(lcr->r.resrec.rrclass);
+ MD5_Update(&c, buf.b, sizeof(mDNSOpaque16));
+
+ // TTL
+
+ MD5_Update(&c, (mDNSu8*) &lcr->r.resrec.rroriginalttl, sizeof(lcr->r.resrec.rroriginalttl));
+
+ // Algorithm
+
+ MD5_Update(&c, algo->c, DomainNameLength(algo));
+
+ // Time
+
+ MD5_Update(&c, utc48, 6);
+
+ // Fudge
+
+ buf = mDNSOpaque16fromIntVal(fudge);
+ MD5_Update(&c, buf.b, sizeof(mDNSOpaque16));
+
+ // Digest error and other data len (both zero) - we'll add them to the rdata later
+
+ buf.NotAnInteger = 0;
+ MD5_Update(&c, buf.b, sizeof(mDNSOpaque16)); // error
+ MD5_Update(&c, buf.b, sizeof(mDNSOpaque16)); // other data len
+
+ // Finish the message & tsig var hash
+
+ MD5_Final(thisDigest, &c);
+
+ // perform outer MD5 (outer key pad, inner digest)
+
+ MD5_Init(&c);
+ MD5_Update(&c, info->keydata_opad, HMAC_LEN);
+ MD5_Update(&c, thisDigest, MD5_LEN);
+ MD5_Final(thisDigest, &c);
+
+ if (!mDNSPlatformMemSame(thisDigest, thatDigest, MD5_LEN))
+ {
+ LogMsg("ERROR: DNSDigest_VerifyMessage - bad signature");
+ *rcode = kDNSFlag1_RC_NotAuth;
+ *tcode = TSIG_ErrBadSig;
+ ok = mDNSfalse;
+ goto exit;
+ }
+
+ // set remaining rdata fields
+ ok = mDNStrue;
+
+exit:
+
+ return ok;
}
+
#ifdef __cplusplus
}
#endif