-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
- *
- * @APPLE_LICENSE_HEADER_END@
-
- Change History (most recent first):
-
-$Log: DNSDigest.c,v $
-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
extern "C" {
#endif
-#include "mDNSClientAPI.h"
+#include "mDNSEmbeddedAPI.h"
#include "DNSCommon.h"
// Disable certain benign warnings with Microsoft compilers
#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; \
})
* Time for some action:-)
*/
-int HASH_UPDATE (HASH_CTX *c, const void *data_, mDNSu32 len)
+int HASH_UPDATE (HASH_CTX *c, const void *data_, unsigned long len)
{
const unsigned char *data=(const unsigned char *)data_;
register HASH_LONG * p;
#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_OPAD 0x5c
#define MD5_LEN 16
-static domainname HMAC_MD5_AlgName = { { '\010', 'h', 'm', 'a', 'c', '-', 'm', 'd', '5',
- '\007', 's', 'i', 'g', '-', 'a', 'l', 'g',
- '\003', 'r', 'e', 'g',
- '\003', 'i', 'n', 't',
- '\0' } };
+#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, 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);
- rdata = tsig.resrec.rdata->u.data;
// key name
- mDNSPlatformStrCopy(info->keyname.c, tsig.resrec.name.c);
- MD5_Update(&c, info->keyname.c, mDNSPlatformStrLen(info->keyname.c)+1);
+ AssignDomainName(&tsig.namestorage, &info->keyname);
+ MD5_Update(&c, info->keyname.c, DomainNameLength(&info->keyname));
// class
tsig.resrec.rrclass = kDNSQClass_ANY;
MD5_Update(&c, (mDNSu8 *)&tsig.resrec.rroriginalttl, sizeof(tsig.resrec.rroriginalttl));
// alg name
- mDNSPlatformStrCopy(HMAC_MD5_AlgName.c, rdata);
- len = mDNSPlatformStrLen(HMAC_MD5_AlgName.c) + 1;
- rdata += len;
+ AssignDomainName(&tsig.resrec.rdata->u.name, &HMAC_MD5_AlgName);
+ len = DomainNameLength(&HMAC_MD5_AlgName);
+ rdata = tsig.resrec.rdata->u.data + len;
MD5_Update(&c, HMAC_MD5_AlgName.c, len);
// 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);
- // fudge
- buf = mDNSOpaque16fromIntVal(300); // 300 sec is fudge recommended in RFC 2485
- ((mDNSOpaque16 *)rdata)->NotAnInteger = buf.NotAnInteger;
+ // 300 sec is fudge recommended in RFC 2485
+ rdata[0] = (mDNSu8)((300 >> 8) & 0xff);
+ rdata[1] = (mDNSu8)( 300 & 0xff);
+ MD5_Update(&c, rdata, sizeof(mDNSOpaque16));
rdata += sizeof(mDNSOpaque16);
- 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;
+ // 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);
// set remaining rdata fields
- *(mDNSOpaque16 *)rdata = mDNSOpaque16fromIntVal(MD5_LEN); // MAC size
+ 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;
- ((mDNSOpaque16 *)rdata)->NotAnInteger = msg->h.id.NotAnInteger; // original ID
- rdata += sizeof(mDNSOpaque16);
- ((mDNSOpaque16 *)rdata)->NotAnInteger = 0; // no error
- rdata += sizeof(mDNSOpaque16);
- ((mDNSOpaque16 *)rdata)->NotAnInteger = 0; // other data len
- rdata += sizeof(mDNSOpaque16);
+ rdata[0] = msg->h.id.b[0]; // original ID
+ rdata[1] = msg->h.id.b[1];
+ 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 = PutResourceRecordTTL(msg, ptr, numAdditionals, &tsig.resrec, 0);
- if (!*end) { LogMsg("ERROR: DNSDigest_SignMessage - could not put TSIG"); return mDNSNULL; }
-
- // update num additionals
- countPtr = (mDNSu8 *)&msg->h.numAdditionals; // increment (network-byte ordered) header value
- *countPtr++ = (mDNSu8)(*numAdditionals >> 8);
- *countPtr++ = (mDNSu8)(*numAdditionals & 0xFF);
+ *end = PutResourceRecordTTLJumbo(msg, ptr, &numAdditionals, &tsig.resrec, 0);
+ if (!*end) { LogMsg("ERROR: DNSDigest_SignMessage - could not put TSIG"); *end = mDNSNULL; return; }
- return *end;
+ // 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);
+
+ // 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;
+ }
+
+ // 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
}