/* -*- Mode: C; tab-width: 4 -*- * * Copyright (c) 2011-2013 Apple Inc. All rights reserved. * * 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 * * http://www.apache.org/licenses/LICENSE-2.0 * * 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. */ #ifndef __DNSSEC_H #define __DNSSEC_H #include "CryptoAlg.h" #include "mDNSDebug.h" typedef enum { RRVS_rr, RRVS_rrsig, RRVS_key, RRVS_rrsig_key, RRVS_ds, RRVS_done, } RRVerifierSet; typedef struct RRVerifier_struct RRVerifier; typedef struct DNSSECVerifier_struct DNSSECVerifier; typedef struct AuthChain_struct AuthChain; typedef struct InsecureContext_struct InsecureContext; struct RRVerifier_struct { RRVerifier *next; mDNSu16 rrtype; mDNSu16 rrclass; mDNSu32 rroriginalttl; mDNSu16 rdlength; mDNSu16 found; mDNSu32 namehash; mDNSu32 rdatahash; domainname name; mDNSu8 *rdata; }; // Each AuthChain element has one rrset (with multiple resource records of same type), rrsig and key // that validates the rrset. struct AuthChain_struct { AuthChain *next; // Next element in the chain RRVerifier *rrset; // RRSET that is authenticated RRVerifier *rrsig; // Signature for that RRSET RRVerifier *key; // Public key for that RRSET }; #define ResetAuthChain(dv) { \ (dv)->ac = mDNSNULL; \ (dv)->actail = &((dv)->ac); \ } typedef void DNSSECVerifierCallback (mDNS *const m, DNSSECVerifier *dv, DNSSECStatus status); // // When we do a validation for a question, there might be additional validations that needs to be done e.g., // wildcard expanded answer. It is also possible that in the case of nsec we need to prove both that a wildcard // does not apply and the closest encloser proves that name does not exist. We identify these with the following // flags. // // Note: In the following, by "marking the validation", we mean that as part of validation we need to prove // the ones that are marked with. // // A wildcard may be used to answer a question. In that case, we need to verify that the right wildcard was // used in answering the question. This is done by marking the validation with WILDCARD_PROVES_ANSWER_EXPANDED. // // Sometimes we get a NXDOMAIN response. In this case, we may have a wildcard where we need to prove // that the wildcard proves that the name does not exist. This is done by marking the validation with // WILDCARD_PROVES_NONAME_EXISTS. // // In the case of NODATA error, sometimes the name may exist but the query type does not exist. This is done by // marking the validation with NSEC_PROVES_NOTYPE_EXISTS. // // In both NXDOMAIN and NODATA proofs, we may have to prove that the NAME does not exist. This is done by marking // the validation with NSEC_PROVES_NONAME_EXISTS. // #define WILDCARD_PROVES_ANSWER_EXPANDED 0x00000001 #define WILDCARD_PROVES_NONAME_EXISTS 0x00000002 #define NSEC_PROVES_NOTYPE_EXISTS 0x00000004 #define NSEC_PROVES_NONAME_EXISTS 0x00000008 #define NSEC3_OPT_OUT 0x00000010 // OptOut was set in NSEC3 struct DNSSECVerifier_struct { domainname origName; // Original question name that needs verification mDNSu16 origType; // Original question type corresponding to origName mDNSu16 currQtype; // Current question type that is being verified mDNSInterfaceID InterfaceID; // InterfaceID of the question DNSQuestion q; mDNSu8 recursed; // Number of times recursed during validation mDNSu8 ValidationRequired; // Copy of the question's ValidationRequired status mDNSu8 InsecureProofDone; mDNSu8 NumPackets; // Number of packets that we send on the wire for DNSSEC verification. mDNSs32 StartTime; // Time the DNSSEC verification starts mDNSu32 flags; RRVerifierSet next; domainname *wildcardName; // set if the answer is wildcard expanded RRVerifier *pendingNSEC; DNSSECVerifierCallback *DVCallback; DNSSECVerifier *parent; RRVerifier *rrset; // rrset for which we have to verify RRVerifier *rrsig; // RRSIG for rrset RRVerifier *key; // DNSKEY for rrset RRVerifier *rrsigKey; // RRSIG for DNSKEY RRVerifier *ds; // DS for DNSKEY set in parent zone AuthChain *saveac; AuthChain *ac; AuthChain **actail; AlgContext *ctx; }; struct InsecureContext_struct { DNSSECVerifier *dv; // dv for which we are doing the insecure proof mDNSu8 skip; // labels to skip for forming the name from origName DNSSECStatus status; // status to deliver when done mDNSu8 triggerLabelCount; // Label count of the name that triggered the insecure proof DNSQuestion q; }; #define LogDNSSEC LogOperation #define DNS_SERIAL_GT(a, b) ((int)((a) - (b)) > 0) #define DNS_SERIAL_LT(a, b) ((int)((a) - (b)) < 0) extern void StartDNSSECVerification(mDNS *const m, void *context); extern RRVerifier* AllocateRRVerifier(const ResourceRecord *const rr, mStatus *status); extern mStatus AddRRSetToVerifier(DNSSECVerifier *dv, const ResourceRecord *const rr, RRVerifier *rv, RRVerifierSet set); extern void VerifySignature(mDNS *const m, DNSSECVerifier *dv, DNSQuestion *q); extern void FreeDNSSECVerifier(mDNS *const m, DNSSECVerifier *dv); extern DNSSECVerifier *AllocateDNSSECVerifier(mDNS *const m, const domainname *name, mDNSu16 rrtype, mDNSInterfaceID InterfaceID, mDNSu8 ValidationRequired, DNSSECVerifierCallback dvcallback, mDNSQuestionCallback qcallback); extern void InitializeQuestion(mDNS *const m, DNSQuestion *question, mDNSInterfaceID InterfaceID, const domainname *qname, mDNSu16 qtype, mDNSQuestionCallback *callback, void *context); extern void ValidateRRSIG(DNSSECVerifier *dv, RRVerifierSet type, const ResourceRecord *const rr); extern void AuthChainLink(DNSSECVerifier *dv, AuthChain *ae); extern mStatus DNSNameToLowerCase(domainname *d, domainname *result); extern int DNSMemCmp(const mDNSu8 *const m1, const mDNSu8 *const m2, int len); extern int DNSSECCanonicalOrder(const domainname *const d1, const domainname *const d2, int *subdomain); extern void ProveInsecure(mDNS *const m, DNSSECVerifier *dv, InsecureContext *ic, domainname *trigger); extern void BumpDNSSECStats(mDNS *const m, DNSSECStatsAction action, DNSSECStatsType type, mDNSu32 value); extern char *DNSSECStatusName(DNSSECStatus status); // DNSSECProbe belongs in DNSSECSupport.h but then we don't want to expose yet another plaform specific dnssec file // to other platforms where dnssec is not supported. extern void DNSSECProbe(mDNS *const m); #endif // __DNSSEC_H