Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c0904fb

Browse files
committedMar 7, 2025·
add asserts
1 parent ecf8260 commit c0904fb

File tree

1 file changed

+31
-10
lines changed

1 file changed

+31
-10
lines changed
 

‎Vpn.Service/Downloader.cs

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Diagnostics;
33
using System.Formats.Asn1;
44
using System.Net;
5+
using System.Runtime.CompilerServices;
56
using System.Security.Cryptography;
67
using System.Security.Cryptography.X509Certificates;
78
using Coder.Desktop.Vpn.Utilities;
@@ -109,9 +110,11 @@ private static bool IsExtendedValidationCertificate(X509Certificate2 cert)
109110

110111
// RFC 5280 4.2: "A certificate MUST NOT include more than one instance
111112
// of a particular extension."
112-
var certificatePoliciesExt = cert.Extensions.FirstOrDefault(e => e.Oid?.Value == CertificatePoliciesOid.Value);
113-
if (certificatePoliciesExt == null)
113+
var policyExtensions = cert.Extensions.Where(e => e.Oid?.Value == CertificatePoliciesOid.Value).ToList();
114+
if (policyExtensions.Count == 0)
114115
return false;
116+
Assert(policyExtensions.Count == 1, "certificate contains more than one CertificatePolicies extension");
117+
var certificatePoliciesExt = policyExtensions[0];
115118

116119
// RFC 5280 4.2.1.4
117120
// certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
@@ -122,25 +125,36 @@ private static bool IsExtendedValidationCertificate(X509Certificate2 cert)
122125
// }
123126
try
124127
{
125-
AsnDecoder.ReadSequence(certificatePoliciesExt.RawData, AsnEncodingRules.DER, out var contentOffset,
126-
out _, out var bytesConsumed);
127-
if (bytesConsumed != certificatePoliciesExt.RawData.Length)
128-
throw new Exception(
129-
$"Parsed Certificate Policies sequence length is incorrect: Consumed={bytesConsumed}, Expected={certificatePoliciesExt.RawData.Length}");
128+
AsnDecoder.ReadSequence(certificatePoliciesExt.RawData, AsnEncodingRules.DER, out var originalContentOffset,
129+
out var contentLength, out var bytesConsumed);
130+
Assert(bytesConsumed == certificatePoliciesExt.RawData.Length, "incorrect outer sequence length");
131+
Assert(originalContentOffset >= 0, "invalid outer sequence content offset");
132+
Assert(contentLength > 0, "invalid outer sequence content length");
133+
134+
var contentOffset = originalContentOffset;
135+
var endOffset = originalContentOffset + contentLength;
136+
Assert(endOffset <= certificatePoliciesExt.RawData.Length, "invalid outer sequence end offset");
130137

131138
// For each policy...
132-
while (contentOffset < certificatePoliciesExt.RawData.Length)
139+
while (contentOffset < endOffset)
133140
{
134141
// Parse a sequence from [contentOffset:].
135-
var slice = certificatePoliciesExt.RawData.AsSpan(contentOffset);
142+
var slice = certificatePoliciesExt.RawData.AsSpan(contentOffset, endOffset - contentOffset);
136143
AsnDecoder.ReadSequence(slice, AsnEncodingRules.DER, out var innerContentOffset,
137144
out var innerContentLength, out var innerBytesConsumed);
145+
Assert(innerBytesConsumed <= slice.Length, "incorrect inner sequence length");
146+
Assert(innerContentOffset >= 0, "invalid inner sequence content offset");
147+
Assert(innerContentLength > 0, "invalid inner sequence content length");
148+
Assert(innerContentOffset + innerContentLength <= slice.Length, "invalid inner sequence end offset");
149+
138150
// Advance the outer offset by the consumed bytes.
139151
contentOffset += innerBytesConsumed;
140152

141153
// Parse the first value in the sequence as an Oid.
142154
slice = slice.Slice(innerContentOffset, innerContentLength);
143-
var oid = AsnDecoder.ReadObjectIdentifier(slice, AsnEncodingRules.DER, out _);
155+
var oid = AsnDecoder.ReadObjectIdentifier(slice, AsnEncodingRules.DER, out var oidBytesConsumed);
156+
Assert(oidBytesConsumed > 0, "invalid inner sequence OID length");
157+
Assert(oidBytesConsumed <= slice.Length, "invalid inner sequence OID length");
144158
if (oid == ExtendedValidationCodeSigningOid.Value)
145159
return true;
146160

@@ -157,6 +171,13 @@ private static bool IsExtendedValidationCertificate(X509Certificate2 cert)
157171

158172
return false;
159173
}
174+
175+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
176+
private static void Assert(bool condition, string message)
177+
{
178+
if (!condition)
179+
throw new Exception("Failed certificate parse assertion: " + message);
180+
}
160181
}
161182

162183
public class AssemblyVersionDownloadValidator : IDownloadValidator

0 commit comments

Comments
 (0)
Please sign in to comment.