Skip to content

Commit

Permalink
Some changes and cleanup to the TLSA and RRSig records (#86)
Browse files Browse the repository at this point in the history
Some changes and cleanup to the TLSA and RRSig records
  • Loading branch information
MichaCo committed Sep 12, 2020
1 parent 124a546 commit 7ba345b
Show file tree
Hide file tree
Showing 12 changed files with 164 additions and 122 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ var ip = record?.Address;

### Supported resource records

* A, AAAA, NS, CNAME, SOA, MB, MG, MR, WKS, HINFO, MINFO, MX, RP, TXT, AFSDB, URI, CAA, NULL, SSHFP
* A, AAAA, NS, CNAME, SOA, MB, MG, MR, WKS, HINFO, MINFO, MX, RP, TXT, AFSDB, URI, CAA, NULL, SSHFP, TLSA, RRSIG
* PTR for reverse lookups
* SRV for service discovery. `LookupClient` has some extensions to help with that.
* AXFR zone transfer (as per spec, LookupClient has to be set to TCP mode only for this type. Also, the result depends on if the DNS server trusts your current connection)
Expand Down
29 changes: 0 additions & 29 deletions src/DnsClient/DateTimeExtensions.cs

This file was deleted.

18 changes: 9 additions & 9 deletions src/DnsClient/DnsRecordFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,26 +169,26 @@ public DnsResourceRecord GetRecord(ResourceRecordInfo info)
private DnsResourceRecord ResolveRrsigRecord(ResourceRecordInfo info)
{
var startIndex = _reader.Index;
var type = _reader.ReadUInt16NetworkOrder(); // This is not stated in the RFC, but it should be in network order
var type = _reader.ReadUInt16NetworkOrder();
var algorithmNumber = _reader.ReadByte();
var labels = _reader.ReadByte();
var originalTtl = _reader.ReadUInt32NetworkOrder(); // This is not stated in the RFC, but it should be in network order
var originalTtl = _reader.ReadUInt32NetworkOrder();
var signatureExpiration = _reader.ReadUInt32NetworkOrder();
var signatureInception = _reader.ReadUInt32NetworkOrder();
var keyTag = _reader.ReadUInt16NetworkOrder();
var signersName = _reader.ReadDnsName();
var signature = Convert.ToBase64String(_reader.ReadBytesToEnd(startIndex, info.RawDataLength).ToArray());
return new RRSIGRecord(info, type, algorithmNumber, labels, originalTtl, signatureExpiration, signatureInception, keyTag, signersName, signature);
var signature = _reader.ReadBytesToEnd(startIndex, info.RawDataLength).ToArray();
return new RRSigRecord(info, type, algorithmNumber, labels, originalTtl, signatureExpiration, signatureInception, keyTag, signersName, signature);
}

private DnsResourceRecord ResolveTlsaRecord(ResourceRecordInfo info)
{
var startIndex = _reader.Index;
var certificateUsage = (ECertificateUsage)_reader.ReadByte();
var selector = (ESelector)_reader.ReadByte();
var matchingType = (EMatchingType)_reader.ReadByte();
var certificateAssociationData = Convert.ToBase64String(_reader.ReadBytesToEnd(startIndex, info.RawDataLength).ToArray());
return new TLSARecord(info, certificateUsage, selector, matchingType, certificateAssociationData);
var certificateUsage = _reader.ReadByte();
var selector = _reader.ReadByte();
var matchingType = _reader.ReadByte();
var certificateAssociationData = _reader.ReadBytesToEnd(startIndex, info.RawDataLength).ToArray();
return new TlsaRecord(info, certificateUsage, selector, matchingType, certificateAssociationData);
}

private DnsResourceRecord ResolveUriRecord(ResourceRecordInfo info)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;

namespace DnsClient.Protocol
{
Expand Down Expand Up @@ -35,17 +36,17 @@ namespace DnsClient.Protocol
ORIGINAL TTL: 4 octet field that specifies the TTL of the covered RRset as it
appears in the authoritative zone, in network byte order
SIGNATURE EXPIRATION: 4 octet field that specifies the expiration date of the
SIGNATURE EXPIRATION: 4 octet field that specifies the expiration date of the
signature in the form of a 32-bit unsigned number of seconds elapsed
since 1 January 1970 00:00:00 UTC, ignoring leap seconds, in network
byte order
SIGNATURE INCEPTION: 4 octet field that specifies the inception date of the
SIGNATURE INCEPTION: 4 octet field that specifies the inception date of the
signature in the form of a 32-bit unsigned number of seconds elapsed
since 1 January 1970 00:00:00 UTC, ignoring leap seconds, in network
byte order
KEY TAG: 2 octet field that contains the key tag value of the DNSKEY RR that
KEY TAG: 2 octet field that contains the key tag value of the DNSKEY RR that
validates this signature, in network byte order
SIGNER'S NAME FIELD: identifies the owner name of the DNSKEY
Expand All @@ -64,14 +65,12 @@ byte order
/// <seealso href="https://tools.ietf.org/html/rfc4033"/>
/// <seealso href="https://tools.ietf.org/html/rfc4034"/>
/// <seealso href="https://tools.ietf.org/html/rfc4035"/>
[CLSCompliant(false)]
public class RRSIGRecord : DnsResourceRecord
public class RRSigRecord : DnsResourceRecord
{

/// <summary>
/// Gets the type of the RRset that is covered by this RRSIG record.
/// </summary>
public ushort Type { get; }
public ResourceRecordType CoveredType { get; }

/// <summary>
/// Gets cryptographic algorithm used to create the signature
Expand All @@ -86,59 +85,75 @@ public class RRSIGRecord : DnsResourceRecord
/// <summary>
/// Gets TTL of the covered RRset as it appears in the authoritative zone
/// </summary>
public uint OriginalTtl { get; }
public long OriginalTtl { get; }

/// <summary>
/// Gets the expiration date of the signature
/// </summary>
public string SignatureExpiration { get; }
public DateTimeOffset SignatureExpiration { get; }

/// <summary>
/// Gets the inception date of the signature
/// </summary>
public string SignatureInception { get; }
public DateTimeOffset SignatureInception { get; }

/// <summary>
/// Gets the key tag value of the DNSKEY RR that validates this signature
/// </summary>
public ushort KeyTag { get; }
public int KeyTag { get; }

/// <summary>
/// Gets the owner name of the DNSKEY RR
/// </summary>
public DnsString SignersNameField { get; }
public DnsString SignersName { get; }

/// <summary>
/// Gets the cryptographic signature that covers the RRSIG RDATA(excluding the Signature field) and the RRset
/// </summary>
public string SignatureField { get; }
public IReadOnlyList<byte> Signature { get; }

/// <summary>
/// Initializes a new instance of the <see cref="RRSIGRecord"/> class
/// Gets the Base64 string representation of the <see cref="Signature"/>.
/// </summary>
public string SignatureAsString { get; }

/// <summary>
/// Initializes a new instance of the <see cref="RRSigRecord"/> class
/// </summary>
/// <param name="info"></param>
/// <param name="type"></param>
/// <param name="coveredType"></param>
/// <param name="algorithmNumber"></param>
/// <param name="labels"></param>
/// <param name="originalTtl"></param>
/// <param name="signatureExpiration">Stored as YYYYMMDDHHmmSS</param>
/// <param name="signatureInception">Stored as YYYYMMDDHHmmSS</param>
/// <param name="keyTag"></param>
/// <param name="signersNameField"></param>
/// <param name="signatureField">Base64 encoded</param>
public RRSIGRecord(ResourceRecordInfo info, ushort type, byte algorithmNumber, byte labels, uint originalTtl,
uint signatureExpiration, uint signatureInception, ushort keyTag, DnsString signersNameField, string signatureField)
/// <param name="signersName"></param>
/// <param name="signature">Base64 encoded</param>
/// <exception cref="ArgumentNullException">If <paramref name="info"/>, <paramref name="signersName"/> or <paramref name="signature"/> is null.</exception>
public RRSigRecord(
ResourceRecordInfo info,
int coveredType,
byte algorithmNumber,
byte labels,
long originalTtl,
long signatureExpiration,
long signatureInception,
int keyTag,
DnsString signersName,
byte[] signature)
: base(info)
{
Type = type;
CoveredType = (ResourceRecordType)coveredType;
AlgorithmNumber = algorithmNumber;
Labels = labels;
OriginalTtl = originalTtl;
SignatureExpiration = SignatureDateToDigFormat(signatureExpiration);
SignatureInception = SignatureDateToDigFormat(signatureInception);
SignatureExpiration = FromUnixTimeSeconds(signatureExpiration);
SignatureInception = FromUnixTimeSeconds(signatureInception);
KeyTag = keyTag;
SignersNameField = signersNameField;
SignatureField = signatureField;
SignersName = signersName ?? throw new ArgumentNullException(nameof(signersName));
Signature = signature ?? throw new ArgumentNullException(nameof(signature));
SignatureAsString = Convert.ToBase64String(signature);
}

/// <summary>
Expand All @@ -147,14 +162,24 @@ public class RRSIGRecord : DnsResourceRecord
/// <returns></returns>
private protected override string RecordToString()
{

return string.Format("{0} {1} {2} {3} {4} {5} {6} {7} {8}", (ResourceRecordType)Type, AlgorithmNumber, Labels,
OriginalTtl, SignatureExpiration, SignatureInception, KeyTag, SignersNameField, SignatureField);
return string.Format(
"{0} {1} {2} {3} {4} {5} {6} {7} {8}",
CoveredType,
AlgorithmNumber,
Labels,
OriginalTtl,
SignatureExpiration.ToString("yyyyMMddHHmmss"),
SignatureInception.ToString("yyyyMMddHHmmss"),
KeyTag,
SignersName,
SignatureAsString);
}

private string SignatureDateToDigFormat(uint signatureDate)
// DateTimeOffset does have that method build in .NET47+ but not .NET45 which we will support. TODO: delete this when we drop support for .NET 4.5
private static DateTimeOffset FromUnixTimeSeconds(long seconds)
{
return new DateTime(1970, 1, 1, 0, 0, 0).AddSeconds(signatureDate).ToRrsigDateString();
long ticks = seconds * TimeSpan.TicksPerSecond + new DateTime(1970, 1, 1, 0, 0, 0).Ticks;
return new DateTimeOffset(ticks, TimeSpan.Zero);
}
}
}
}
15 changes: 15 additions & 0 deletions src/DnsClient/Protocol/ResourceRecordType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,12 +180,27 @@ public enum ResourceRecordType : short
/// <seealso href="https://tools.ietf.org/html/rfc3755">RFC 3755</seealso>
RRSIG = 46,

/// <summary>
/// TODO
/// </summary>
NSEC = 47,

/// <summary>
/// TODO
/// </summary>
DNSKEY = 48,

/// <summary>
/// TLSA rfc6698
/// </summary>
/// <seealso href="https://https://tools.ietf.org/html/rfc6698">RFC 6698</seealso>
TLSA = 52,

/// <summary>
/// TODO
/// </summary>
SPF = 99,

/// <summary>
/// A Uniform Resource Identifier (URI) resource record.
/// </summary>
Expand Down

0 comments on commit 7ba345b

Please sign in to comment.