alexreinert/ARSoft.Tools.Net

DnsSec Server Sample

ststeiger opened this issue ยท 8 comments

I'd like to have a sample of how to use DnsSec on the server side.

I have come as far as this
https://github.com/ststeiger/Arsoft/blob/master/ArsoftTestServer/Servers/DnsSecServer.cs

but I can't find any information anywhere about which algorithms are used, from what value the hash/signature is computed, in which encoding, which keys of what size, etc.
The RFCs are vague at best.

Since you have already added DnsSec stuff in your library, I presume you know more about the subject.
So any help by sample would be really useful.

+1 for this. Would be great to have a working example.

@ststeiger problem solved ? If you managed to solve this problem, would you help me?

I haven't yet had time.
It's not high priority for me.

But I've been coming back to it, as our application is going to be subjected to new security tests.
But haven't had time to look at it.
It seems like nowadays, there is more information available;
Also, I think you can get the required information in the source of bind-tools or some java variety of bind-tools.

Here are some of the links I have googled lately, and put on keep.google.com:

https://securityblog.switch.ch/2014/11/13/dnssec-signing-your-domain-with-bind-inline-signing/
https://sourceforge.net/p/gbdns/news/
https://www.gkg.net/ws/ds.html
https://www.internetsociety.org/resources/deploy360/2012/how-to-sign-your-domain-with-dnssec-using-gkg-net-5/
https://www.youtube.com/watch?v=RlPh6cDesxg
https://www.internetsociety.org/resources/deploy360/2012/step-by-step-how-to-use-a-dnssec-ds-record-to-link-a-registar-to-a-dns-hosting-provider-4/
https://thejimmahknows.com/creating-a-public-dns-server-advertising-an-authoritative-domain/
https://www.quora.com/How-can-I-have-my-own-Public-DNS-Server-like-8-8-8-8?share=1
https://csharp.hotexamples.com/examples/-/LocalCertificateSelectionCallback/-/php-localcertificateselectioncallback-class-examples.html
https://bornfromrage.blogspot.com/2016/02/dnssec-with-c-part-2-ds-generation.html
https://github.com/elear/GKGtools

DNSSEC signing your domain with BIND inline signing | SWITCH Security-Blog
DNSSEC Delegation Signer Webservice API
How To Sign Your Domain With DNSSEC Using GKG.Net | Internet Society
Step-By-Step: How To Use a DNSSEC DS Record to Link a Registar To A DNS Hosting Provider | Internet Society
DNSSEC Analyzer - dnssec-test-gkg.com
elear/GKGtools: Tools to manage DS records at GKG.NET
create dnssec record - Google Search
DNSSEC Zone Signing Tutorial - YouTube
Step-By-Step: How To Use a DNSSEC DS Record to Link a Registar To A DNS Hosting Provider | Internet Society
dnssec csharp - Google Search
Born from rage: DNSSEC with C# - Part 2, DS generation
ARSoft.Tools.Net - C#/.Net DNS client/server, SPF and SenderID Library - CodePlex Archive
GbDns / News
LocalCertificateSelectionCallback C# (CSharp) Code Examples - HotExamples
Creating a Public DNS Server and advertising an Authoritative Domain | thejimmahknows
How to have my own Public DNS Server (like 8.8.8.8) - Quora

altinsoft: There's a good example in DnsKeyRecord.CreateSigningKey

That's how to get the byte[] from the keys

        internal static void EncodeUShort(byte[] buffer, ref int currentPosition, ushort value)
        {
            if (System.BitConverter.IsLittleEndian)
            {
                buffer[currentPosition++] = (byte)((value >> 8) & 0xff);
                buffer[currentPosition++] = (byte)(value & 0xff);
            }
            else
            {
                buffer[currentPosition++] = (byte)(value & 0xff);
                buffer[currentPosition++] = (byte)((value >> 8) & 0xff);
            }
        }


        internal static void EncodeByteArray(byte[] messageData, ref int currentPosition, byte[] data, int length)
        {
            if ((data != null) && (length > 0))
            {
                System.Buffer.BlockCopy(data, 0, messageData, currentPosition, length);
                currentPosition += length;
            }
        }

        internal static void EncodeByteArray(byte[] messageData, ref int currentPosition, byte[] data)
        {
            if (data != null)
            {
                EncodeByteArray(messageData, ref currentPosition, data, data.Length);
            }
        }

        /// <summary>
		///   Creates a new signing key pair
		/// </summary>
		/// <param name="name">The name of the key or zone</param>
		/// <param name="recordClass">The record class of the DnsKeyRecord</param>
		/// <param name="timeToLive">The TTL in seconds to the DnsKeyRecord</param>
		/// <param name="flags">The Flags of the DnsKeyRecord</param>
		/// <param name="protocol">The protocol version</param>
		/// <param name="algorithm">The key algorithm</param>
		/// <param name="keyStrength">The key strength or 0 for default strength</param>
		/// <returns></returns>
		public static DnsKeyRecord CreateSigningKey(DomainName name, RecordClass recordClass, int timeToLive, DnsKeyFlags flags, byte protocol, DnsSecAlgorithm algorithm, int keyStrength = 0)
        {
            // Found in DnsKeyRecord.CreateSigningKey

            /*
	        internal override string RecordDataToString()
            {
	            return (ushort) Flags
			            + " " + Protocol
			            + " " + (byte) Algorithm
			            + " " + PublicKey.ToBase64String();
            }


    DnsRecordBase
		    internal abstract string RecordDataToString();

            public override string ToString()
            {
	            string recordData = RecordDataToString();
	            return Name + " " + TimeToLive + " " + RecordClass.ToShortString() + " " + RecordType.ToShortString() + (String.IsNullOrEmpty(recordData) ? "" : " " + recordData);
            }


    RrSigRecord.cs
            byte[] signBuffer;
            int signBufferLength;
            EncodeSigningBuffer(records, out signBuffer, out signBufferLength);

            Signature = key.Sign(signBuffer, signBufferLength);

             */


            Org.BouncyCastle.Security.SecureRandom _secureRandom =
                new Org.BouncyCastle.Security.SecureRandom(new Org.BouncyCastle.Crypto.Prng.CryptoApiRandomGenerator());


            // https://csharp.hotexamples.com/examples/Org.BouncyCastle.Crypto.Generators/DsaKeyPairGenerator/GenerateKeyPair/php-dsakeypairgenerator-generatekeypair-method-examples.html

            byte[] privateKey;
            byte[] publicKey;

            switch (algorithm)
            {
                case DnsSecAlgorithm.RsaSha1:
                case DnsSecAlgorithm.RsaSha1Nsec3Sha1:
                case DnsSecAlgorithm.RsaSha256:
                case DnsSecAlgorithm.RsaSha512:
                    if (keyStrength == 0)
                        keyStrength = (flags == (DnsKeyFlags.Zone | DnsKeyFlags.SecureEntryPoint)) ? 2048 : 1024;

                    Org.BouncyCastle.Crypto.Generators.RsaKeyPairGenerator rsaKeyGen = new Org.BouncyCastle.Crypto.Generators.RsaKeyPairGenerator();
                    rsaKeyGen.Init(new Org.BouncyCastle.Crypto.KeyGenerationParameters(_secureRandom, keyStrength));
                    var rsaKey = rsaKeyGen.GenerateKeyPair();
                    privateKey = Org.BouncyCastle.Pkcs.PrivateKeyInfoFactory.CreatePrivateKeyInfo(rsaKey.Private).GetDerEncoded();
                    var rsaPublicKey = (Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters)rsaKey.Public;
                    var rsaExponent = rsaPublicKey.Exponent.ToByteArrayUnsigned();
                    var rsaModulus = rsaPublicKey.Modulus.ToByteArrayUnsigned();

                    int offset = 1;
                    if (rsaExponent.Length > 255)
                    {
                        publicKey = new byte[3 + rsaExponent.Length + rsaModulus.Length];
                        EncodeUShort(publicKey, ref offset, (ushort)publicKey.Length);
                    }
                    else
                    {
                        publicKey = new byte[1 + rsaExponent.Length + rsaModulus.Length];
                        publicKey[0] = (byte)rsaExponent.Length;
                    }
                    EncodeByteArray(publicKey, ref offset, rsaExponent);
                    EncodeByteArray(publicKey, ref offset, rsaModulus);
                    break;

                case DnsSecAlgorithm.Dsa:
                case DnsSecAlgorithm.DsaNsec3Sha1:
                    if (keyStrength == 0)
                        keyStrength = 1024;

                    Org.BouncyCastle.Crypto.Generators.DsaParametersGenerator dsaParamsGen = new Org.BouncyCastle.Crypto.Generators.DsaParametersGenerator();
                    dsaParamsGen.Init(keyStrength, 12, _secureRandom);
                    Org.BouncyCastle.Crypto.Generators.DsaKeyPairGenerator dsaKeyGen = new Org.BouncyCastle.Crypto.Generators.DsaKeyPairGenerator();
                    dsaKeyGen.Init(new Org.BouncyCastle.Crypto.Parameters.DsaKeyGenerationParameters(_secureRandom, dsaParamsGen.GenerateParameters()));
                    Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair dsaKey = dsaKeyGen.GenerateKeyPair();
                    privateKey = Org.BouncyCastle.Pkcs.PrivateKeyInfoFactory.CreatePrivateKeyInfo(dsaKey.Private).GetDerEncoded();
                    var dsaPublicKey = (Org.BouncyCastle.Crypto.Parameters.DsaPublicKeyParameters)dsaKey.Public;

                    byte[] dsaY = dsaPublicKey.Y.ToByteArrayUnsigned();
                    byte[] dsaP = dsaPublicKey.Parameters.P.ToByteArrayUnsigned();
                    byte[] dsaQ = dsaPublicKey.Parameters.Q.ToByteArrayUnsigned();
                    byte[] dsaG = dsaPublicKey.Parameters.G.ToByteArrayUnsigned();
                    byte dsaT = (byte)((dsaY.Length - 64) / 8);

                    publicKey = new byte[21 + 3 * dsaY.Length];
                    publicKey[0] = dsaT;
                    dsaQ.CopyTo(publicKey, 1);
                    dsaP.CopyTo(publicKey, 21);
                    dsaG.CopyTo(publicKey, 21 + dsaY.Length);
                    dsaY.CopyTo(publicKey, 21 + 2 * dsaY.Length);
                    break;

                case DnsSecAlgorithm.EccGost:
                    Org.BouncyCastle.Crypto.Parameters.ECDomainParameters gostEcDomainParameters = Org.BouncyCastle.Asn1.CryptoPro.ECGost3410NamedCurves.GetByOid(Org.BouncyCastle.Asn1.CryptoPro.CryptoProObjectIdentifiers.GostR3410x2001CryptoProA);

                    var gostKeyGen = new Org.BouncyCastle.Crypto.Generators.ECKeyPairGenerator();
                    gostKeyGen.Init(new Org.BouncyCastle.Crypto.Parameters.ECKeyGenerationParameters(gostEcDomainParameters, _secureRandom));

                    var gostKey = gostKeyGen.GenerateKeyPair();
                    privateKey = Org.BouncyCastle.Pkcs.PrivateKeyInfoFactory.CreatePrivateKeyInfo(gostKey.Private).GetDerEncoded();
                    var gostPublicKey = (Org.BouncyCastle.Crypto.Parameters.ECPublicKeyParameters)gostKey.Public;

                    publicKey = new byte[64];

                    // gostPublicKey.Q.X.ToBigInteger().ToByteArrayUnsigned().CopyTo(publicKey, 32);
                    gostPublicKey.Q.AffineXCoord.ToBigInteger().ToByteArrayUnsigned().CopyTo(publicKey, 32);
                    // gostPublicKey.Q.Y.ToBigInteger().ToByteArrayUnsigned().CopyTo(publicKey, 0);
                    gostPublicKey.Q.AffineYCoord.ToBigInteger().ToByteArrayUnsigned().CopyTo(publicKey, 0);

                    System.Array.Reverse(publicKey);
                    break;

                case DnsSecAlgorithm.EcDsaP256Sha256:
                case DnsSecAlgorithm.EcDsaP384Sha384:
                    int ecDsaDigestSize;
                    Org.BouncyCastle.Asn1.X9.X9ECParameters ecDsaCurveParameter;

                    if (algorithm == DnsSecAlgorithm.EcDsaP256Sha256)
                    {
                        ecDsaDigestSize = new Org.BouncyCastle.Crypto.Digests.Sha256Digest().GetDigestSize();
                        ecDsaCurveParameter = Org.BouncyCastle.Asn1.Nist.NistNamedCurves.GetByOid(Org.BouncyCastle.Asn1.Sec.SecObjectIdentifiers.SecP256r1);
                    }
                    else
                    {
                        ecDsaDigestSize = new Org.BouncyCastle.Crypto.Digests.Sha384Digest().GetDigestSize();
                        ecDsaCurveParameter = Org.BouncyCastle.Asn1.Nist.NistNamedCurves.GetByOid(Org.BouncyCastle.Asn1.Sec.SecObjectIdentifiers.SecP384r1);
                    }

                    Org.BouncyCastle.Crypto.Parameters.ECDomainParameters ecDsaP384EcDomainParameters = new Org.BouncyCastle.Crypto.Parameters.ECDomainParameters(
                        ecDsaCurveParameter.Curve,
                        ecDsaCurveParameter.G,
                        ecDsaCurveParameter.N,
                        ecDsaCurveParameter.H,
                        ecDsaCurveParameter.GetSeed());

                    var ecDsaKeyGen = new Org.BouncyCastle.Crypto.Generators.ECKeyPairGenerator();
                    ecDsaKeyGen.Init(new Org.BouncyCastle.Crypto.Parameters.ECKeyGenerationParameters(ecDsaP384EcDomainParameters, _secureRandom));

                    var ecDsaKey = ecDsaKeyGen.GenerateKeyPair();
                    privateKey = Org.BouncyCastle.Pkcs.PrivateKeyInfoFactory.CreatePrivateKeyInfo(ecDsaKey.Private).GetDerEncoded();
                    var ecDsaPublicKey = (Org.BouncyCastle.Crypto.Parameters.ECPublicKeyParameters)ecDsaKey.Public;

                    publicKey = new byte[ecDsaDigestSize * 2];
                    // ecDsaPublicKey.Q.X.ToBigInteger().ToByteArrayUnsigned().CopyTo(publicKey, 0);
                    ecDsaPublicKey.Q.AffineXCoord.ToBigInteger().ToByteArrayUnsigned().CopyTo(publicKey, 0);
                    // ecDsaPublicKey.Q.Y.ToBigInteger().ToByteArrayUnsigned().CopyTo(publicKey, ecDsaDigestSize);
                    ecDsaPublicKey.Q.AffineYCoord.ToBigInteger().ToByteArrayUnsigned().CopyTo(publicKey, ecDsaDigestSize);
                    break;

                default:
                    throw new System.NotSupportedException();
            }

            return new DnsKeyRecord(name, recordClass, timeToLive, flags, protocol, algorithm, publicKey, privateKey);
        }

Now trying to figure out how to get data which is to sign.

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.

Done, know how it works.
Will send a pull-request with a sample medium-shortly.

Done, know how it works.
Will send a pull-request with a sample medium-shortly.

Thank you very much!

stale commented

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.