source: rtems-libbsd/mDNSResponder/mDNSMacOSX/DNSSECSupport.c @ 9449f15

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 9449f15 was 9449f15, checked in by Sebastian Huber <sebastian.huber@…>, on 01/30/14 at 12:52:13

mDNS: Import

The sources can be obtained via:

http://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-544.tar.gz

  • Property mode set to 100644
File size: 20.5 KB
Line 
1/* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2012 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18// ***************************************************************************
19// DNSSECSupport.c: Platform specific support for DNSSEC like fetching root
20// trust anchor and dnssec probes etc.
21// ***************************************************************************
22
23#include "mDNSEmbeddedAPI.h"
24#include "DNSCommon.h"                  // For mDNS_Lock, mDNS_Random
25#include "dnssec.h"
26#include "DNSSECSupport.h"
27
28#include <CommonCrypto/CommonDigest.h>  // For Hash algorithms SHA1 etc.
29
30// Following are needed for fetching the root trust anchor dynamically
31#include <CoreFoundation/CoreFoundation.h>
32#include <libxml2/libxml/parser.h>
33#include <libxml2/libxml/tree.h>
34#include <libxml2/libxml/xmlmemory.h>
35#include <notify.h>
36
37// 30 days
38#define ROOT_TA_UPDATE_INTERVAL  (30 * 24 * 3600)   // seconds
39
40// After 100 days, the test anchors are not valid. Just an arbitrary number
41// to configure validUntil.
42#define TEST_TA_EXPIRE_INTERVAL  (100 * 24 * 4600)
43
44// When we can't fetch the root TA due to network errors etc., we start off a timer
45// to fire at 60 seconds and then keep doubling it till we fetch it
46#define InitialTAFetchInterval 60
47
48#if !TARGET_OS_IPHONE
49DNSQuestion DNSSECProbeQuestion;
50#endif
51
52mDNSlocal int RegisterNotification(mDNS *const m, unsigned int interval);
53
54mDNSlocal void LinkTrustAnchor(mDNS *const m, TrustAnchor *ta)
55{
56    int length = 0;
57    int i;
58    mDNSu8 *p;
59    TrustAnchor **t = &m->TrustAnchors;
60    char buffer[256];
61
62    while (*t)
63        t = &((*t)->next);
64    *t = ta;
65
66    buffer[0] = 0;
67    p = ta->rds.digest;
68    for (i = 0; i < ta->digestLen; i++)
69    {
70        length += mDNS_snprintf(buffer+length, sizeof(buffer)-1-length, "%x", p[i]);
71    }
72    LogInfo("LinkTrustAnchor: Zone %##s, keytag %d, alg %d, digestType %d, digestLen %d, digest %s", ta->zone.c, ta->rds.keyTag,
73        ta->rds.alg, ta->rds.digestType, ta->digestLen, buffer);
74}
75
76mDNSlocal void DelTrustAnchor(mDNS *const m, const domainname *zone)
77{
78    TrustAnchor **ta = &m->TrustAnchors;
79    TrustAnchor *tmp;
80
81    while (*ta && !SameDomainName(&(*ta)->zone, zone))
82        ta = &(*ta)->next;
83
84    // First time, we won't find the TrustAnchor in the list as it has
85    // not been added.
86    if (!(*ta))
87        return;
88
89    tmp = *ta;
90    *ta = (*ta)->next;                  // Cut this record from the list
91    tmp->next = mDNSNULL;
92    if (tmp->rds.digest)
93        mDNSPlatformMemFree(tmp->rds.digest);
94    mDNSPlatformMemFree(tmp);
95}
96
97mDNSlocal void AddTrustAnchor(mDNS *const m, const domainname *zone, mDNSu16 keytag, mDNSu8 alg, mDNSu8 digestType, int diglen,
98    mDNSu8 *digest)
99{
100    TrustAnchor *ta, *tmp;
101    mDNSu32 t = (mDNSu32) time(NULL);
102
103    // Check for duplicates
104    tmp = m->TrustAnchors;
105    while (tmp)
106    {
107        if (SameDomainName(zone, &tmp->zone) && tmp->rds.keyTag == keytag && tmp->rds.alg == alg && tmp->rds.digestType == digestType &&
108            !memcmp(tmp->rds.digest, digest, diglen))
109        {
110            LogMsg("AddTrustAnchors: Found a duplicate");
111            return;
112        }
113        tmp = tmp->next;
114    }
115
116    ta = (TrustAnchor *)mDNSPlatformMemAllocate(sizeof(TrustAnchor));
117    if (!ta)
118    {
119        LogMsg("AddTrustAnchor: malloc failure ta");
120        return;
121    }
122    ta->rds.keyTag = keytag;
123    ta->rds.alg = alg;
124    ta->rds.digestType = digestType;
125    ta->rds.digest = digest;
126    ta->digestLen = diglen;
127    ta->validFrom = t;
128    ta->validUntil = t + TEST_TA_EXPIRE_INTERVAL;
129    AssignDomainName(&ta->zone, zone);
130    ta->next = mDNSNULL;
131
132    LinkTrustAnchor(m, ta);
133}
134
135#define HexVal(X) ( ((X) >= '0' && (X) <= '9') ? ((X) - '0'     ) :   \
136                    ((X) >= 'A' && (X) <= 'F') ? ((X) - 'A' + 10) :   \
137                    ((X) >= 'a' && (X) <= 'f') ? ((X) - 'a' + 10) : -1)
138
139mDNSlocal mDNSu8 *ConvertDigest(char *digest, int digestType, int *diglen)
140{
141    int i, j;
142    mDNSu8 *dig;
143
144    switch (digestType)
145    {
146    case SHA1_DIGEST_TYPE:
147        *diglen = CC_SHA1_DIGEST_LENGTH;
148        break;
149    case SHA256_DIGEST_TYPE:
150        *diglen = CC_SHA256_DIGEST_LENGTH;
151        break;
152    default:
153        LogMsg("ConvertDigest: digest type %d not supported", digestType);
154        return mDNSNULL;
155    }
156    dig = mDNSPlatformMemAllocate(*diglen);
157    if (!dig)
158    {
159        LogMsg("ConvertDigest: malloc failure");
160        return mDNSNULL;
161    }
162
163    for (j=0,i=0; i<*diglen*2; i+=2)
164    {
165        int l, h;
166        l = HexVal(digest[i]);
167        h = HexVal(digest[i+1]);
168        if (l<0 || h<0) { LogMsg("ConvertDigest: Cannot convert digest"); return NULL;}
169        dig[j++] = (mDNSu8)((l << 4) | h);
170    }
171    return dig;
172}
173
174// All the children are in a linked list
175//
176// <TrustAnchor> has two children: <Zone> and <KeyDigest>
177// <KeyDigest> has four children <KeyTag> <Algorithm> <DigestType> <Digest>
178//
179// Returns false if failed to parse the element i.e., malformed xml document.
180// Validity of the actual values itself is done outside the function.
181mDNSlocal mDNSBool ParseElementChildren(xmlDocPtr tadoc, xmlNode *node, TrustAnchor *ta)
182{
183    xmlNode *cur_node;
184    xmlChar *val1, *val2, *val;
185    char *invalid = NULL;
186
187    val = val1 = val2 = NULL;
188
189    for (cur_node = node; cur_node; cur_node = cur_node->next)
190    {
191        invalid = NULL;
192        val1 = val2 = NULL;
193       
194        val = xmlNodeListGetString(tadoc, cur_node->xmlChildrenNode, 1);
195        if (!val)
196        {
197           LogInfo("ParseElementChildren: NULL value for %s", cur_node->name);
198           continue;
199        }
200        if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Zone"))
201        {
202            // MaeDomainNameFromDNSNameString does not work for "."
203            if (!xmlStrcmp(val, (const xmlChar *)"."))
204            {
205                ta->zone.c[0] = 0;
206            }
207            else if (!MakeDomainNameFromDNSNameString(&ta->zone, (char *)val))
208            {
209                LogMsg("ParseElementChildren: Cannot parse Zone %s", val);
210                goto error;
211            }
212            else
213            {
214                LogInfo("ParseElementChildren: Element %s, value %##s", cur_node->name, ta->zone.c);
215            }
216        }
217        else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"KeyTag"))
218        {
219            ta->rds.keyTag = strtol((const char *)val, &invalid, 10);
220            if (*invalid != '\0')
221            {
222                LogMsg("ParseElementChildren: KeyTag invalid character %d", *invalid);
223                goto error;
224            }
225            else
226            {
227                LogInfo("ParseElementChildren: Element %s, value %d", cur_node->name, ta->rds.keyTag);
228            }
229        }
230        else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Algorithm"))
231        {
232            ta->rds.alg = strtol((const char *)val, &invalid, 10);
233            if (*invalid != '\0')
234            {
235                LogMsg("ParseElementChildren: Algorithm invalid character %c", *invalid);
236                goto error;
237            }
238            else
239            {
240                LogInfo("ParseElementChildren: Element %s, value %d", cur_node->name, ta->rds.alg);
241            }
242        }
243        else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"DigestType"))
244        {
245            ta->rds.digestType = strtol((const char *)val, &invalid, 10);
246            if (*invalid != '\0')
247            {
248                LogMsg("ParseElementChildren: Algorithm invalid character %c", *invalid);
249                goto error;
250            }
251            else
252            {
253                LogInfo("ParseElementChildren: Element %s, value %d", cur_node->name, ta->rds.digestType);
254            }
255        }
256        else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Digest"))
257        {
258            int diglen;
259            mDNSu8 *dig = ConvertDigest((char *)val, ta->rds.digestType, &diglen);
260            if (dig)
261            {
262                LogInfo("ParseElementChildren: Element %s, digest %s", cur_node->name, val);
263                ta->digestLen = diglen;
264                ta->rds.digest = dig;
265            }
266            else
267            {
268                LogMsg("ParseElementChildren: Element %s, NULL digest", cur_node->name);
269                goto error;
270            }
271        }
272        else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"KeyDigest"))
273        {
274            struct tm tm;
275            val1 = xmlGetProp(cur_node, (const xmlChar *)"validFrom");
276            if (val1)
277            {
278                char *s = strptime((const char *)val1, "%Y-%m-%dT%H:%M:%S", &tm);
279                if (!s)
280                {
281                    LogMsg("ParseElementChildren: Parsing ValidFrom failed %s", val1);
282                    goto error;
283                }
284                else
285                {
286                    ta->validFrom = (mDNSu32)timegm(&tm);
287                }
288            }
289            val2 = xmlGetProp(cur_node, (const xmlChar *)"validUntil");
290            if (val2)
291            {
292                char *s = strptime((const char *)val2, "%Y-%m-%dT%H:%M:%S", &tm);
293                if (!s)
294                {
295                    LogMsg("ParseElementChildren: Parsing ValidFrom failed %s", val2);
296                    goto error;
297                }
298                else
299                {
300                    ta->validUntil = (mDNSu32)timegm(&tm);
301                }
302            }
303            else
304            {
305                // If there is no validUntil, set it to the next probing interval
306                mDNSu32 t = (mDNSu32) time(NULL);
307                ta->validUntil = t + ROOT_TA_UPDATE_INTERVAL;
308            }
309            LogInfo("ParseElementChildren: ValidFrom time %u, validUntil %u", (unsigned)ta->validFrom, (unsigned)ta->validUntil);
310        }
311        if (val1)
312            xmlFree(val1);
313        if (val2)
314            xmlFree(val2);
315        if (val)
316            xmlFree(val);
317    }
318    return mDNStrue;
319error:
320    if (val1)
321        xmlFree(val1);
322    if (val2)
323        xmlFree(val2);
324    if (val)
325        xmlFree(val);
326    return mDNSfalse;
327}
328
329mDNSlocal mDNSBool ValidateTrustAnchor(TrustAnchor *ta)
330{
331    time_t currTime = time(NULL);
332
333    // Currently only support trust anchor for root.
334    if (!SameDomainName(&ta->zone, (const domainname *)"\000"))
335    {
336        LogInfo("ParseElementChildren: Zone %##s not root", ta->zone.c);
337        return mDNSfalse;
338    }
339
340    switch (ta->rds.digestType)
341    {
342    case SHA1_DIGEST_TYPE:
343        if (ta->digestLen != CC_SHA1_DIGEST_LENGTH)
344        {
345            LogMsg("ValidateTrustAnchor: Invalid digest len %d for SHA1", ta->digestLen);
346            return mDNSfalse;
347        }
348        break;
349    case SHA256_DIGEST_TYPE:
350        if (ta->digestLen != CC_SHA256_DIGEST_LENGTH)
351        {
352            LogMsg("ValidateTrustAnchor: Invalid digest len %d for SHA256", ta->digestLen);
353            return mDNSfalse;
354        }
355        break;
356    default:
357        LogMsg("ValidateTrustAnchor: digest type %d not supported", ta->rds.digestType);
358        return mDNSfalse;
359    }
360    if (!ta->rds.digest)
361    {
362        LogMsg("ValidateTrustAnchor: digest NULL for %d", ta->rds.digestType);
363        return mDNSfalse;
364    }
365    switch (ta->rds.alg)
366    {
367    case CRYPTO_RSA_SHA512:
368    case CRYPTO_RSA_SHA256:
369    case CRYPTO_RSA_NSEC3_SHA1:
370    case CRYPTO_RSA_SHA1:
371        break;
372    default:
373        LogMsg("ValidateTrustAnchor: Algorithm %d not supported", ta->rds.alg);
374        return mDNSfalse;
375    }
376   
377    if (DNS_SERIAL_LT(currTime, ta->validFrom))
378    {
379        LogMsg("ValidateTrustAnchor: Invalid ValidFrom time %u, currtime %u", (unsigned)ta->validFrom, (unsigned)currTime);
380        return mDNSfalse;
381    }
382    if (DNS_SERIAL_LT(ta->validUntil, currTime))
383    {
384        LogMsg("ValidateTrustAnchor: Invalid ValidUntil time %u, currtime %u", (unsigned)ta->validUntil, (unsigned)currTime);
385        return mDNSfalse;
386    }
387    return mDNStrue;
388}
389
390mDNSlocal mDNSBool ParseElement(xmlDocPtr tadoc, xmlNode * a_node, TrustAnchor *ta)
391{
392    xmlNode *cur_node = NULL;
393
394    for (cur_node = a_node; cur_node; cur_node = cur_node->next)
395    {
396        if (cur_node->type == XML_ELEMENT_NODE)
397        {
398            // There could be multiple KeyDigests per TrustAnchor. We keep parsing till we
399            // reach the last one or we encounter an error in parsing the document.
400            if (!xmlStrcmp(cur_node->name, (const xmlChar *)"KeyDigest"))
401            {
402                if (ta->rds.digest)
403                    mDNSPlatformMemFree(ta->rds.digest);
404                ta->rds.digestType = 0;
405                ta->digestLen = 0;
406            }
407            if (!ParseElementChildren(tadoc, cur_node->children, ta))
408                return mDNSfalse;
409            if (!ParseElement(tadoc, cur_node->children, ta))
410                return mDNSfalse;
411        }
412    }
413    return mDNStrue;
414}
415
416mDNSlocal void TAComplete(mDNS *const m, void *context)
417{
418    TrustAnchor *ta = (TrustAnchor *)context;
419
420    DelTrustAnchor(m, &ta->zone);
421    LinkTrustAnchor(m, ta);
422}
423
424mDNSlocal void FetchRootTA(mDNS *const m)
425{
426    CFStringRef urlString = CFSTR("https://data.iana.org/root-anchors/root-anchors.xml");
427    CFDataRef xmlData;
428    CFStringRef fileRef = NULL;
429    const char *xmlFileName = NULL;
430    char buf[512];
431    CFURLRef url = NULL;
432    static unsigned int RootTAFetchInterval = InitialTAFetchInterval;
433
434    (void) m;
435
436    TrustAnchor *ta = (TrustAnchor *)mDNSPlatformMemAllocate(sizeof(TrustAnchor));
437    if (!ta)
438    {
439        LogMsg("FetchRootTA: TrustAnchor alloc failed");
440        return;
441    }
442    memset(ta, 0, sizeof(TrustAnchor));
443
444    url = CFURLCreateWithString(NULL, urlString, NULL);
445    if (!url)
446    {
447        LogMsg("FetchRootTA: CFURLCreateWithString error");
448        mDNSPlatformMemFree(ta);
449        return;
450    }
451
452    // If we can't fetch the XML file e.g., network problems, trigger a timer. All other failures
453    // should hardly happen in practice for which schedule the normal interval to refetch the TA.
454    if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, url, &xmlData, NULL, NULL, NULL))
455    {
456        LogInfo("FetchRootTA: CFURLCreateDataAndPropertiesFromResource error");
457        CFRelease(url);
458        mDNSPlatformMemFree(ta);
459        RegisterNotification(m, RootTAFetchInterval);
460        RootTAFetchInterval *= 2 + 1;
461        return;
462    }
463
464    // get the name of the last component from the url, libxml will use it if
465    // it has to report an error
466    fileRef = CFURLCopyLastPathComponent(url);
467    if (fileRef)
468    {
469        xmlFileName = CFStringGetCStringPtr(fileRef, kCFStringEncodingUTF8);
470        if (!xmlFileName)
471        {
472            if (!CFStringGetCString(fileRef, buf, sizeof(buf), kCFStringEncodingUTF8) )
473                strlcpy(buf, "nofile.xml", sizeof(buf));
474            xmlFileName = (const char *)buf;
475        }
476    }
477
478    // Parse the XML and get the CFXMLTree.
479    xmlDocPtr tadoc = xmlReadMemory((const char*)CFDataGetBytePtr(xmlData),
480        (int)CFDataGetLength(xmlData), xmlFileName, NULL, 0);       
481
482    CFRelease(fileRef);
483    CFRelease(url);
484    CFRelease(xmlData);
485
486    if (!tadoc)
487    {
488        LogMsg("FetchRootTA: xmlReadMemory failed");
489        goto done;
490    }
491
492    xmlNodePtr root = xmlDocGetRootElement(tadoc);
493    if (!root)
494    {
495        LogMsg("FetchRootTA: Cannot get root element");
496        goto done;
497    }
498
499    if (ParseElement(tadoc, root, ta) && ValidateTrustAnchor(ta))
500    {
501        // Do the actual addition of TA on the main queue.
502        mDNSPlatformDispatchAsync(m, ta, TAComplete);
503    }
504    else
505    {
506        if (ta->rds.digest)
507            mDNSPlatformMemFree(ta->rds.digest);
508        mDNSPlatformMemFree(ta);
509    }
510done:
511    if (tadoc)
512        xmlFreeDoc(tadoc);
513    RegisterNotification(m, ROOT_TA_UPDATE_INTERVAL);
514    RootTAFetchInterval = InitialTAFetchInterval;
515    return;
516}
517
518
519#if APPLE_OSX_mDNSResponder && !TARGET_OS_IPHONE
520mDNSlocal void DNSSECProbeCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
521{
522    if (!AddRecord)
523        return;
524
525    mDNS_Lock(m);
526    if ((m->timenow - question->StopTime) >= 0)
527    {
528        mDNS_Unlock(m);
529        LogDNSSEC("DNSSECProbeCallback: Question %##s (%s) timed out", question->qname.c, DNSTypeName(question->qtype));
530        mDNS_StopQuery(m, question);
531        return;
532    }
533    mDNS_Unlock(m);
534
535    // Wait till we get the DNSSEC results. If we get a negative response e.g., no DNS servers, the
536    // question will be restarted by the core and we should have the DNSSEC results eventually.
537    if (AddRecord != QC_dnssec)
538    {
539        LogDNSSEC("DNSSECProbeCallback: Question %##s (%s)", question->qname.c, DNSTypeName(question->qtype), RRDisplayString(m, answer));
540        return;
541    }
542
543    LogDNSSEC("DNSSECProbeCallback: Question %##s (%s), DNSSEC status %s", question->qname.c, DNSTypeName(question->qtype),
544            DNSSECStatusName(question->ValidationStatus));
545
546    mDNS_StopQuery(m, question);
547}
548
549// Send a DNSSEC probe just for the sake of collecting DNSSEC statistics.
550mDNSexport void DNSSECProbe(mDNS *const m)
551{
552    mDNSu32 rand;
553
554    if (DNSSECProbeQuestion.ThisQInterval != -1)
555        return;
556   
557    rand = mDNSRandom(0x3FFFFFFF) % 100;
558    // Probe 5% of the time
559    if (rand > 5)
560        return;
561   
562    mDNS_DropLockBeforeCallback();
563    InitializeQuestion(m, &DNSSECProbeQuestion, mDNSInterface_Any, (const domainname *)"\003com", kDNSType_DS, DNSSECProbeCallback, mDNSNULL);
564    DNSSECProbeQuestion.ValidatingResponse = 0;
565    DNSSECProbeQuestion.ValidationRequired = DNSSEC_VALIDATION_SECURE;
566
567    BumpDNSSECStats(m, kStatsActionIncrement, kStatsTypeProbe, 1);
568    mDNS_StartQuery(m, &DNSSECProbeQuestion);
569    mDNS_ReclaimLockAfterCallback();
570}
571#endif // APPLE_OSX_mDNSResponder && !TARGET_OS_IPHONE
572
573// For now we fetch the root trust anchor and update the local copy
574mDNSexport void UpdateTrustAnchors(mDNS *const m)
575{
576    // Register for a notification to fire immediately which in turn will update
577    // the trust anchor
578    if (RegisterNotification(m, 1))
579    {
580        LogMsg("UpdateTrustAnchors: ERROR!! failed to register for notification");
581    }
582}
583
584mDNSlocal int RegisterNotification(mDNS *const m, unsigned int interval)
585{
586    int len = strlen("com.apple.system.notify.service.timer:+") + 21; // 21 bytes to accomodate the interval
587    char buffer[len];
588    unsigned int blen;
589    int status;
590
591    // Starting "interval" second from now (+ below indicates relative) register for a notification
592    blen = mDNS_snprintf(buffer, sizeof(buffer), "com.apple.system.notify.service.timer:+%us", interval);
593    if (blen >= sizeof(buffer))
594    {
595        LogMsg("RegisterNotification: Buffer too small blen %d, buffer size %d", blen, sizeof(buffer));
596        return -1;
597    }
598    LogInfo("RegisterNotification: buffer %s", buffer);
599    if (m->notifyToken)
600    {
601        notify_cancel(m->notifyToken);
602        m->notifyToken = 0;
603    }
604    status = notify_register_dispatch(buffer, &m->notifyToken,
605                dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
606                ^(int t) { (void) t; FetchRootTA(m); });
607
608    if (status != NOTIFY_STATUS_OK)
609    {
610        LogMsg("RegisterNotification: notify_register_dispatch failed");
611        return -1;
612    }
613    return 0;
614}
615
616mDNSexport mStatus DNSSECPlatformInit(mDNS *const m)
617{
618    int diglen;
619
620    m->TrustAnchors = mDNSNULL;
621    m->notifyToken  = 0;
622
623    // Add a couple of trust anchors for testing purposes.
624    mDNSlocal const domainname *testZone  = (const domainname*)"\007example";
625
626    char *digest = "F122E47B5B7D2B6A5CC0A21EADA11D96BB9CC927";
627    mDNSu8 *dig = ConvertDigest(digest, 1, &diglen);
628    AddTrustAnchor(m, testZone, 23044, 5, 1, diglen, dig);
629
630    char *digest1 = "D795AE5E1AFB200C6139474199B70EAD3F3484553FD97BE5A43704B8A4791F21";
631    dig = ConvertDigest(digest1, 2, &diglen);
632    AddTrustAnchor(m, testZone, 23044, 5, 2, diglen, dig);
633
634    // Add the TA for root zone manually here. We will dynamically fetch the root TA and
635    // update it shortly. If that fails e.g., disconnected from the network, we still
636    // have something to work with.
637    char *digest2 = "49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5";
638    dig = ConvertDigest(digest2, 2, &diglen);
639    AddTrustAnchor(m, (const domainname *)"\000", 19036, 8, 2, diglen, dig);
640
641#if !TARGET_OS_IPHONE
642    DNSSECProbeQuestion.ThisQInterval = -1;
643#endif
644    return mStatus_NoError;
645}
Note: See TracBrowser for help on using the repository browser.