Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

using Microsoft.Win32.SafeHandles;
Expand All @@ -20,17 +19,9 @@ internal static partial class CoreFoundation
[LibraryImport(Libraries.CoreFoundationLibrary)]
private static partial SafeCFDateHandle CFDateCreate(IntPtr zero, CFAbsoluteTime at);

internal static SafeCFDateHandle CFDateCreate(DateTime date)
internal static SafeCFDateHandle CFDateCreate(DateTimeOffset date)
{
Debug.Assert(
date.Kind != DateTimeKind.Unspecified,
"DateTimeKind.Unspecified should be specified to Local or UTC by the caller");

// UTC stays unchanged, Local is changed.
// Unspecified gets treated as Local (which may or may not be desired).
DateTime utcDate = date.ToUniversalTime();

double epochDeltaSeconds = (utcDate - s_cfDateEpoch).TotalSeconds;
double epochDeltaSeconds = (date.UtcDateTime - s_cfDateEpoch).TotalSeconds;

SafeCFDateHandle cfDate = CFDateCreate(IntPtr.Zero, epochDeltaSeconds);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ internal struct FILETIME
internal uint ftTimeLow;
internal uint ftTimeHigh;

internal DateTime ToDateTime()
internal DateTimeOffset ToDateTimeOffset()
{
long fileTime = (((long)ftTimeHigh) << 32) + ftTimeLow;
return DateTime.FromFileTime(fileTime);
return new DateTimeOffset(DateTime.FromFileTimeUtc(fileTime));
}

internal static FILETIME FromDateTime(DateTime dt)
internal static FILETIME FromDateTimeOffset(DateTimeOffset instant)
{
long fileTime = dt.ToFileTime();
long fileTime = instant.UtcDateTime.ToFileTimeUtc();

unchecked
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -280,21 +280,21 @@ public string SignatureAlgorithm
}
}

public DateTime NotAfter
public DateTimeOffset NotAfter

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the value ultimately being stored here is now UTC Ticks, I'd change the cert PAL to be public long NotAfterUtcTicks and avoid a lot of "turn this into a DateTimeOffset, then back into a long, then back into a DateTimeOffset".

Plus, a long return fits in a register and the DateTimeOffset doesn't.

{
get
{
EnsureCertificateData();
return _certData.NotAfter.ToLocalTime();
return _certData.NotAfter;
}
}

public DateTime NotBefore
public DateTimeOffset NotBefore
{
get
{
EnsureCertificateData();
return _certData.NotBefore.ToLocalTime();
return _certData.NotBefore;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ public void Dispose()
public byte[] PublicKeyValue => _realPal.PublicKeyValue;
public byte[] SerialNumber => _realPal.SerialNumber;
public string SignatureAlgorithm => _realPal.SignatureAlgorithm;
public DateTime NotAfter => _realPal.NotAfter;
public DateTime NotBefore => _realPal.NotBefore;
public DateTimeOffset NotAfter => _realPal.NotAfter;
public DateTimeOffset NotBefore => _realPal.NotBefore;
public byte[] RawData => _realPal.RawData;
public byte[] Export(X509ContentType contentType, SafePasswordHandle password) =>
_realPal.Export(contentType, password);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,21 +274,21 @@ public byte[] RawData
}
}

public DateTime NotAfter
public DateTimeOffset NotAfter
{
get
{
EnsureCertData();
return _certData.NotAfter.ToLocalTime();
return _certData.NotAfter;
}
}

public DateTime NotBefore
public DateTimeOffset NotBefore
{
get
{
EnsureCertData();
return _certData.NotBefore.ToLocalTime();
return _certData.NotBefore;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ public AlgorithmIdentifier(AlgorithmIdentifierAsn algorithmIdentifier)

internal byte[] SerialNumber => certificate.TbsCertificate.SerialNumber.ToArray();

internal DateTime NotBefore => certificate.TbsCertificate.Validity.NotBefore.GetValue().UtcDateTime;
internal DateTimeOffset NotBefore => certificate.TbsCertificate.Validity.NotBefore.GetValue();

internal DateTime NotAfter => certificate.TbsCertificate.Validity.NotAfter.GetValue().UtcDateTime;
internal DateTimeOffset NotAfter => certificate.TbsCertificate.Validity.NotAfter.GetValue();

internal AlgorithmIdentifier PublicKeyAlgorithm => new AlgorithmIdentifier(certificate.TbsCertificate.SubjectPublicKeyInfo.Algorithm);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,24 +217,24 @@ public string SignatureAlgorithm
}
}

public DateTime NotAfter
public DateTimeOffset NotAfter
{
get
{
unsafe
{
return InvokeWithCertContext(static pCertContext => pCertContext->pCertInfo->NotAfter.ToDateTime());
return InvokeWithCertContext(static pCertContext => pCertContext->pCertInfo->NotAfter.ToDateTimeOffset());
}
}
}

public DateTime NotBefore
public DateTimeOffset NotBefore
{
get
{
unsafe
{
return InvokeWithCertContext(static pCertContext => pCertContext->pCertInfo->NotBefore.ToDateTime());
return InvokeWithCertContext(static pCertContext => pCertContext->pCertInfo->NotBefore.ToDateTimeOffset());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -842,33 +842,30 @@ public X509Certificate2 Create(
nameof(issuerCertificate));
}

DateTime notBeforeLocal = notBefore.LocalDateTime;
if (notBeforeLocal < issuerCertificate.NotBefore)
if (notBefore < issuerCertificate.GetNotBeforeUtc())
{
throw new ArgumentException(
SR.Format(
SR.Cryptography_CertReq_NotBeforeNotNested,
notBeforeLocal,
notBefore.LocalDateTime,
issuerCertificate.NotBefore),
nameof(notBefore));
}

DateTime notAfterLocal = notAfter.LocalDateTime;

// Round down to the second, since that's the cert accuracy.
// This makes one method which uses the same DateTimeOffset for chained notAfters
// not need to do the rounding locally.
long notAfterLocalTicks = notAfterLocal.Ticks;
long fractionalSeconds = notAfterLocalTicks % TimeSpan.TicksPerSecond;
notAfterLocalTicks -= fractionalSeconds;
notAfterLocal = new DateTime(notAfterLocalTicks, notAfterLocal.Kind);
long notAfterTicks = notAfter.Ticks;
long fractionalSeconds = notAfterTicks % TimeSpan.TicksPerSecond;
notAfterTicks -= fractionalSeconds;
notAfter = new DateTimeOffset(notAfterTicks, notAfter.Offset);

if (notAfterLocal > issuerCertificate.NotAfter)
if (notAfter > issuerCertificate.GetNotAfterUtc())
{
throw new ArgumentException(
SR.Format(
SR.Cryptography_CertReq_NotAfterNotNested,
notAfterLocal,
notAfter.LocalDateTime,
issuerCertificate.NotAfter),
nameof(notAfter));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ internal static partial bool ReleaseSafeX509ChainHandle(IntPtr handle)
X509RevocationFlag revocationFlag,
X509Certificate2Collection? customTrustStore,
X509ChainTrustMode trustMode,
DateTime verificationTime,
DateTimeOffset verificationTime,
TimeSpan timeout,
bool disableAia)
{
Expand Down Expand Up @@ -182,15 +182,15 @@ internal void Initialize(
}

internal void Evaluate(
DateTime verificationTime,
DateTimeOffset verificationTime,
OidCollection? applicationPolicy,
OidCollection? certificatePolicy,
X509RevocationMode revocationMode,
X509RevocationFlag revocationFlag)
{
Debug.Assert(_chainContext != null);

long timeInMsFromUnixEpoch = new DateTimeOffset(verificationTime).ToUnixTimeMilliseconds();
long timeInMsFromUnixEpoch = verificationTime.ToUnixTimeMilliseconds();
_isValid = Interop.AndroidCrypto.X509ChainBuild(_chainContext, timeInMsFromUnixEpoch);
if (!_isValid)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ internal sealed class SecTrustChainPal : IChainPal
private SafeX509ChainHandle? _chainHandle;
public X509ChainElement[]? ChainElements { get; private set; }
public X509ChainStatus[]? ChainStatus { get; private set; }
private DateTime _verificationTime;
private DateTimeOffset _verificationTime;
private X509RevocationMode _revocationMode;

Comment thread
koen-lee marked this conversation as resolved.
internal SecTrustChainPal()
Expand Down Expand Up @@ -222,7 +222,7 @@ private SafeCreateHandle GetCertsArray(List<SafeHandle> safeHandles)
}

internal void Execute(
DateTime verificationTime,
DateTimeOffset verificationTime,
bool allowNetwork,
OidCollection? applicationPolicy,
OidCollection? certificatePolicy,
Expand Down Expand Up @@ -478,7 +478,7 @@ private X509ChainStatus[] BuildChainElementStatuses(X509Certificate2? cert, int
const int errSecCertificateExpired = -67818;
const int errSecCertificateNotValidYet = -67819;

osStatus = cert != null && cert.NotBefore > _verificationTime ?
osStatus = cert != null && cert.GetNotBeforeUtc() > _verificationTime ?
errSecCertificateNotValidYet :
errSecCertificateExpired;
errorString = Interop.AppleCrypto.GetSecErrorString(osStatus);
Expand Down Expand Up @@ -593,17 +593,10 @@ internal static partial bool ReleaseSafeX509ChainHandle(IntPtr handle)
X509RevocationFlag revocationFlag,
X509Certificate2Collection? customTrustStore,
X509ChainTrustMode trustMode,
DateTime verificationTime,
DateTimeOffset verificationTime,
TimeSpan timeout,
bool disableAia)
{
// If the time was given in Universal, it will stay Universal.
// If the time was given in Local, it will be converted.
// If the time was given in Unspecified, it will be assumed local, and converted.
//
// This matches the "assume Local unless explicitly Universal" implicit contract.
verificationTime = verificationTime.ToUniversalTime();

SecTrustChainPal chainPal = new SecTrustChainPal();

// The allowNetwork controls all network activity for macOS chain building.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ internal static partial bool ReleaseSafeX509ChainHandle(IntPtr handle)
X509RevocationFlag revocationFlag,
X509Certificate2Collection? customTrustStore,
X509ChainTrustMode trustMode,
DateTime verificationTime,
DateTimeOffset verificationTime,
TimeSpan timeout,
bool disableAia)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public static void FlushStores()
X509RevocationFlag revocationFlag,
X509Certificate2Collection? customTrustStore,
X509ChainTrustMode trustMode,
DateTime verificationTime,
DateTimeOffset verificationTime,
TimeSpan timeout,
bool disableAia)
{
Expand Down Expand Up @@ -81,7 +81,7 @@ public static void FlushStores()
X509RevocationFlag revocationFlag,
X509Certificate2Collection? customTrustStore,
X509ChainTrustMode trustMode,
DateTime verificationTime,
DateTimeOffset verificationTime,
TimeSpan timeout,
bool disableAia)
{
Expand All @@ -98,8 +98,6 @@ public static void FlushStores()
timeout = s_maxUrlRetrievalTimeout;
}

DateTimeOffset verificationInstant = new DateTimeOffset(verificationTime);

// Until we support the Disallowed store, ensure it's empty (which is done by the ctor)
using (new X509Store(StoreName.Disallowed, StoreLocation.CurrentUser, OpenFlags.ReadOnly))
{
Expand All @@ -111,7 +109,7 @@ public static void FlushStores()
((OpenSslX509CertificateReader)cert).SafeHandle,
customTrustStore,
trustMode,
verificationInstant,
verificationTime,
downloadTimeout);

Interop.Crypto.X509VerifyStatusCode status = chainPal.FindFirstChain(extraStore);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ internal sealed partial class ChainPal : IDisposable, IChainPal
X509RevocationFlag revocationFlag,
X509Certificate2Collection? customTrustStore,
X509ChainTrustMode trustMode,
DateTime verificationTime,
DateTimeOffset verificationTime,
TimeSpan timeout,
bool disableAia)
{
Expand Down Expand Up @@ -60,7 +60,7 @@ internal sealed partial class ChainPal : IDisposable, IChainPal

chainPara.dwUrlRetrievalTimeout = (int)Math.Floor(timeout.TotalMilliseconds);

Interop.Crypt32.FILETIME ft = Interop.Crypt32.FILETIME.FromDateTime(verificationTime);
Interop.Crypt32.FILETIME ft = Interop.Crypt32.FILETIME.FromDateTimeOffset(verificationTime);
Interop.Crypt32.CertChainFlags flags = MapRevocationFlags(revocationMode, revocationFlag, disableAia);
SafeX509ChainHandle chain;
using (SafeCertContextHandle certContext = certificatePal.GetCertContext())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ internal partial class ChainPal
X509RevocationFlag revocationFlag,
X509Certificate2Collection? customTrustStore,
X509ChainTrustMode trustMode,
DateTime verificationTime,
DateTimeOffset verificationTime,
TimeSpan timeout,
bool disableAia);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,13 @@ public unsafe void FindBySerialNumber(BigInteger hexValue, BigInteger decimalVal
});
}

public void FindByTimeValid(DateTime dateTime) => FindByTime(dateTime, 0);
public void FindByTimeNotYetValid(DateTime dateTime) => FindByTime(dateTime, -1);
public void FindByTimeExpired(DateTime dateTime) => FindByTime(dateTime, 1);
public void FindByTimeValid(DateTimeOffset instant) => FindByTime(instant, 0);
public void FindByTimeNotYetValid(DateTimeOffset instant) => FindByTime(instant, -1);
public void FindByTimeExpired(DateTimeOffset instant) => FindByTime(instant, 1);

private unsafe void FindByTime(DateTime dateTime, int compareResult)
private unsafe void FindByTime(DateTimeOffset instant, int compareResult)
{
Interop.Crypt32.FILETIME fileTime = Interop.Crypt32.FILETIME.FromDateTime(dateTime);
Interop.Crypt32.FILETIME fileTime = Interop.Crypt32.FILETIME.FromDateTimeOffset(instant);

FindCore(
(fileTime, compareResult),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ internal interface ICertificatePalCore : IDisposable
byte[] PublicKeyValue { get; }
byte[] SerialNumber { get; }
string SignatureAlgorithm { get; }
DateTime NotAfter { get; }
DateTime NotBefore { get; }
DateTimeOffset NotAfter { get; }
DateTimeOffset NotBefore { get; }
byte[] RawData { get; }
byte[] Export(X509ContentType contentType, SafePasswordHandle password);
byte[] ExportPkcs12(Pkcs12ExportPbeParameters exportParameters, SafePasswordHandle password);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ internal interface IFindPal : IDisposable
void FindByIssuerName(string issuerName);
void FindByIssuerDistinguishedName(string issuerDistinguishedName);
void FindBySerialNumber(BigInteger hexValue, BigInteger decimalValue);
void FindByTimeValid(DateTime dateTime);
void FindByTimeNotYetValid(DateTime dateTime);
void FindByTimeExpired(DateTime dateTime);
void FindByTimeValid(DateTimeOffset instant);
void FindByTimeNotYetValid(DateTimeOffset instant);
void FindByTimeExpired(DateTimeOffset instant);
Comment thread
koen-lee marked this conversation as resolved.
void FindByTemplateName(string templateName);
void FindByApplicationPolicy(string oidValue);
void FindByCertificatePolicy(string oidValue);
Expand Down
Loading
Loading