private static byte[] GetCanonicalRRData(DnsKeyRecord rec) { using (var ms = new MemoryStream()) { ms.Write(BitConverter.GetBytes(rec.Flags).Reverse(), 0, 2); ms.Write(new[] { rec.Protocol }, 0, 1); ms.Write(new[] { (byte)rec.Algorithm }, 0, 1); ms.Write(rec.PublicKey, 0, rec.PublicKey.Length); return(ms.ToArray()); } }
public static byte[] GetCanonicalFormatData(int ttl, DnsKeyRecord rec) { var rrdata = GetCanonicalRRData(rec); using (var ms = new MemoryStream()) { byte[] domainBytes = CanonicalFormatHelper.BuildUnpackedDomainInCanonicalForm(rec.Name); ms.Write(domainBytes, 0, domainBytes.Length); ms.Write(BitConverter.GetBytes((ushort)rec.RecordType).Reverse(), 0, 2); ms.Write(BitConverter.GetBytes((ushort)rec.RecordClass).Reverse(), 0, 2); ms.Write(BitConverter.GetBytes(ttl).Reverse(), 0, 4); ms.Write(BitConverter.GetBytes((ushort)rrdata.Length).Reverse(), 0, 2); ms.Write(rrdata, 0, rrdata.Length); return(ms.ToArray()); } }
static void Main(string[] args) { // PrintAlgorithms(); // EqualityCheck(); // TestKeyPair(); // https://www.cloudflare.com/dns/dnssec/how-dnssec-works/ // RRSIG - Contains a cryptographic signature // DNSKEY - Contains a public signing key // DS - Contains the hash of a DNSKEY record // NSEC and NSEC3 - For explicit denial-of-existence of a DNS record // CDNSKEY and CDS - For a child zone requesting updates to DS record(s) in the parent zone. // The first step towards securing a zone with DNSSEC // is to group all the records (on the same label?) with the same type into a resource record set(RRset). // It’s actually this full RRset that gets digitally signed, opposed to individual DNS records. // Of course, this also means that you must request and validate all of the AAAA records // from a zone with the same label instead of validating only one of them. // zone-signing key (ZSK)pair: // the private portion of the key digitally signs each RRset in the zone, // while the public portion verifies the signature. // a zone operator creates digital signatures for each RRset using the private ZSK // and stores them in their name server as RRSIG records. // The zone operator also needs to make their public ZSK available by adding it to their name server in a DNSKEY record. // the name server also returns the corresponding RRSIG. // The resolver can then pull the DNSKEY record containing the public ZSK from the name server. // Together, the RRset, RRSIG, and public ZSK can validate the response. // If we trust the zone - signing key in the DNSKEY record, we can trust all the records in the zone. // But, what if the zone - signing key was compromised? We need a way to validate the public ZSK. // Key-Signing Keys (KSK): // The KSK validates the DNSKEY record in exactly the same way as our ZSK secured the rest of our RRsets. // It signs the public ZSK (which is stored in a DNSKEY record), creating an RRSIG for the DNSKEY. // Just like the public ZSK, the name server publishes the public KSK in another DNSKEY record, // which gives us the DNSKEY RRset shown above. // Both the public KSK and public ZSK are signed by the private KSK. // Resolvers can then use the public KSK to validate the public ZSK. // Complicating things further, the key-signing key is signed by itself, which doesn’t provide any additional trust. // We need a way to connect the trust in our zone with its parent zone. // Delegation Signer Records // DNSSEC introduces a delegation signer(DS) record to allow the transfer of trust // from a parent zone to a child zone. A zone operator hashes the DNSKEY record // containing the public KSK and gives it to the parent zone to publish as a DS record. // This DS record is how resolvers know that the child zone is DNSSEC - enabled. // To check the validity of the child zone’s public KSK, // the resolver hashes it and compares it to the DS record from the parent. // If they match, the resolver can assume that the public KSK hasn’t been tampered with, // which means it can trust all of the records in the child zone. // This is how a chain of trust is established in DNSSEC. // System.Security.Cryptography.X509Certificates.X509Certificate2 cert2 = new System.Security.Cryptography.X509Certificates.X509Certificate2(byte[] rawData); // System.Security.Cryptography.X509Certificates.X509Certificate2 cert2 = DotNetUtilities.CreateX509Cert2("mycert"); // SecurityKey secKey = new X509SecurityKey(cert2); // https://tools.ietf.org/html/rfc4034 // https://www.dynu.com/Resources/DNS-Records/DNSKEY-Record AaaaRecord aaa = new AaaaRecord(ARSoft.Tools.Net.DomainName.Parse("example.com"), 0, System.Net.IPAddress.Parse("127.0.0.1")); string straaa = aaa.ToString(); System.Console.WriteLine(straaa); // DnsRecordBase drb = null; // DnsMessage msg = DnsMessage.Parse(new byte[] { }); // DnsKeyFlags flags = DnsKeyFlags.SecureEntryPoint; KeyPairRecord ZSK_key = CreateSigningKey(DnsSecAlgorithm.EccGost, DnsKeyFlags.Zone, 512); KeyPairRecord keyPair = CreateSigningKey(DnsSecAlgorithm.EccGost, DnsKeyFlags.SecureEntryPoint, 512); byte[] zsPub = Org.BouncyCastle.X509.SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(ZSK_key.KeyPair.Public).GetDerEncoded(); byte[] zsPriv = Org.BouncyCastle.Pkcs.PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.KeyPair.Private).GetDerEncoded(); bool bPub = System.Linq.Enumerable.SequenceEqual(ZSK_key.PublicKey, zsPub); bool bPriv = System.Linq.Enumerable.SequenceEqual(ZSK_key.PrivateKey, zsPriv); System.Console.WriteLine("Pub; {0}\t Priv: {1}", bPub, bPriv); // Private key only necessary when signing, now when publishing... DnsKeyRecord dnsKey = new DnsKeyRecord( ARSoft.Tools.Net.DomainName.Parse("example.com") // Name: It defines the hostname of a record and whether the hostname will be appended to the label. // Fully qualified hostnames terminated by a period will not append the origin. , RecordClass.Any , 60 // ttl The time-to-live in seconds. It specifies how long a resolver is supposed to cache or remember the DNS query // before the query expires and a new one needs to be done. , keyPair.Flags , 3 // Fixed value of 3 (for backwards compatibility) , keyPair.Algorithm // The public key's cryptographic algorithm. , keyPair.PublicKey // new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 } // Public key data. , keyPair.PrivateKey ); string strDNSKey = dnsKey.ToString(); // dnsKey.CalculateKeyTag() System.Console.WriteLine(strDNSKey); // example.com. 60 * DNSKEY 256 3 8 AQIDBAUGBwgJ System.Collections.Generic.List <DnsRecordBase> records = new System.Collections.Generic.List <DnsRecordBase>(); records.Add(aaa); RrSigRecord rrsig1 = RrSigRecord.SignRecord(records, dnsKey, System.DateTime.UtcNow, System.DateTime.UtcNow.AddDays(30)); string strRRsig = rrsig1.ToString(); // rrsig1.Signature System.Console.WriteLine(strRRsig); // example.com. 0 IN RRSIG AAAA 12 2 0 20200122193048 20191223193048 46296 example.com. 9aCosjMmgc1iL4jNavgPAA5NXRp5jukyKxb9vCA8PNoz1d4LjaTjfURxnKhX97KkkTdSW0tUoeYgBK7t/qjOFg== RrSigRecord rrsig = new RrSigRecord( ARSoft.Tools.Net.DomainName.Parse("example.com") // Name of the digitally signed RRs , RecordClass.Any , 60 // ttl The time-to-live in seconds. It specifies how long a resolver is supposed to cache or remember the DNS query // before the query expires and a new one needs to be done. , RecordType.A // Type Covered: DNS record type that this signature covers. , DnsSecAlgorithm.EccGost // Cryptographic algorithm used to create the signature. , 4 // Labels: Number of labels in the original RRSIG-record name (used to validate wildcards). , 0 // Original TTL: TTL value of the covered record set. , System.DateTime.Now.AddMinutes(1) // Signature Expiration: When the signature expires. , System.DateTime.Now // Signature Inception: When the signature was created. , 0 // Key Tag: A short numeric value which can help quickly identify the DNSKEY-record which can be used to validate this signature. // identifiziert den unterzeichnenden DNSKEY, um zwischen mehreren Signaturen zu unterscheiden (engl. key tag) , ARSoft.Tools.Net.DomainName.Parse("example.com") // Signer's Name: Name of the DNSKEY-record which can be used to validate this signature. , new byte[] { 1, 2, 3 } // Signature: Cryptographic signature. (Base64) ); DsRecord signedDsRec = new DsRecord(dnsKey, 0, keyPair.Digest); string strSignedDsRec = signedDsRec.ToString(); System.Console.WriteLine(strSignedDsRec); // signedDsRec.Digest // example.com. 0 * DS 24280 12 3 C453FBE75917C8A07BB767230463FA6C271E21D3D92F1ACCC538A194A7C41CC8 DsRecord dsRec = new DsRecord( ARSoft.Tools.Net.DomainName.Parse("example.com") // Name: It defines the hostname of a record and whether the hostname will be appended to the label. // Fully qualified hostnames terminated by a period will not append the origin. , RecordClass.Any , 60 // ttl The time-to-live in seconds. It specifies how long a resolver is supposed to cache or remember the DNS query // before the query expires and a new one needs to be done. , 0 // Key Tag: A short numeric value which can help quickly identify the referenced DNSKEY-record. , DnsSecAlgorithm.RsaSha256 // The algorithm of the referenced DNSKEY-record. , DnsSecDigestType.Sha256 // Digest Type: Cryptographic hash algorithm used to create the Digest value. , new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0xFF } // A cryptographic hash value of the referenced DNSKEY-record. ); // dsRec.Digest string strDsRec = dsRec.ToString(); System.Console.WriteLine(strDsRec); // example.com. 60 * DS 0 8 2 0102030405060708090AFF string strDS = dsRec.ToString(); System.Console.WriteLine(strDS); // . 0 IN AAAA 127.0.0.1 // aaa // example.com. 0 IN AAAA 127.0.0.1 // ds: // example.com. 60 * DS 0 8 2 010203 // example.com. 60 * DS 0 8 2 010203040506070809 // example.com. 60 * DS 0 8 2 0102030405060708090AFF // rec.Algorithm string key = @"AQPSKmynfzW4kyBv015MUG2DeIQ3 Cbl+BBZH4b/0PY1kxkmvHjcZc8no kfzj31GajIQKY+5CptLr3buXA10h WqTkF7H6RfoRqXQeogmMHfpftf6z Mv1LyBUgia7za6ZEzOJBOztyvhjL 742iU/TpPSEDhm2SNKLijfUppn1U aNvv4w== "; byte[] keyBytes = Base64ToByteArray(key); string signature = @"2BB183AF5F22588179A53B0A98631FAD1A292118"; // ArsoftTestServer.KeyConversion.fromPublicKey() PublicKey pk = ArsoftTestServer.KeyConversionTo.toPublicKey(keyBytes, DnsSecAlgorithm.RsaSha1); System.Console.WriteLine(pk); byte[] generatedKeyBytes = ArsoftTestServer.KeyConversion.fromPublicKey(pk, DnsSecAlgorithm.RsaSha1); // ArsoftTestServer.Resolvers.Test4(); // ArsoftTestServer.SimpleServer.Test(); System.Console.WriteLine(System.Environment.NewLine); System.Console.WriteLine(" --- Press any key to continue --- "); System.Console.ReadKey(); }