Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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 @@ -37,6 +37,12 @@ internal DateTime ToDateTime()
return DateTime.FromFileTime(fileTime);
}

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

internal static FILETIME FromDateTime(DateTime dt)
{
long fileTime = dt.ToFileTime();

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'll complete the refactor and make this method obsolete.

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 @@ -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
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.FromDateTime(instant.UtcDateTime);

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
Original file line number Diff line number Diff line change
Expand Up @@ -110,39 +110,19 @@ public void FindBySerialNumber(BigInteger hexValue, BigInteger decimalValue)
});
}

private static DateTime NormalizeDateTime(DateTime dateTime)
public void FindByTimeValid(DateTimeOffset instant)
{
// If it's explicitly UTC, convert it to local before a comparison, since the
// NotBefore and NotAfter are in Local time.
//
// If it was Unknown, assume it was Local.
if (dateTime.Kind == DateTimeKind.Utc)
{
return dateTime.ToLocalTime();
}

return dateTime;
FindCore(instant, static (instant, cert) => cert.GetNotBeforeUtc() <= instant && instant <= cert.GetNotAfterUtc());
}

public void FindByTimeValid(DateTime dateTime)
public void FindByTimeNotYetValid(DateTimeOffset instant)
{
DateTime normalized = NormalizeDateTime(dateTime);

FindCore(normalized, static (normalized, cert) => cert.NotBefore <= normalized && normalized <= cert.NotAfter);
FindCore(instant, static (instant, cert) => cert.GetNotBeforeUtc() > instant);
}

public void FindByTimeNotYetValid(DateTime dateTime)
public void FindByTimeExpired(DateTimeOffset instant)
{
DateTime normalized = NormalizeDateTime(dateTime);

FindCore(normalized, static (normalized, cert) => cert.NotBefore > normalized);
}

public void FindByTimeExpired(DateTime dateTime)
{
DateTime normalized = NormalizeDateTime(dateTime);

FindCore(normalized, static (normalized, cert) => cert.NotAfter < normalized);
FindCore(instant, static (instant, cert) => cert.GetNotAfterUtc() < instant);
}

public void FindByTemplateName(string templateName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ public static void AddCrlForCertificate(
SafeX509Handle cert,
SafeX509StoreHandle store,
X509RevocationMode revocationMode,
DateTime verificationTime,
DateTimeOffset verificationTime,
TimeSpan downloadTimeout)
{
// In Offline mode, accept any cached CRL we have.
// "CRL is Expired" is a better match for Offline than "Could not find CRL"
if (revocationMode != X509RevocationMode.Online)
{
verificationTime = DateTime.MinValue;
verificationTime = DateTimeOffset.MinValue;
}

string? url = GetCdpUrl(cert);
Expand Down Expand Up @@ -76,14 +76,8 @@ public static void AddCrlForCertificate(
DownloadAndAddCrl(url, crlFileName, store, downloadTimeout);
}

private static bool AddCachedCrl(string crlFileName, SafeX509StoreHandle store, DateTime verificationTime)
private static bool AddCachedCrl(string crlFileName, SafeX509StoreHandle store, DateTimeOffset verificationTime)
{
// OpenSSL is going to convert our input time to universal, so we should be in Local or
// Unspecified (local-assumed).
Debug.Assert(
verificationTime.Kind != DateTimeKind.Utc,
"UTC verificationTime should have been normalized to Local");

if (s_crlCache.TryGetValueAndUpRef(crlFileName, out CachedCrlEntry? cacheEntry))
{
try
Expand All @@ -94,7 +88,7 @@ private static bool AddCachedCrl(string crlFileName, SafeX509StoreHandle store,
{
if (OpenSslX509ChainEventSource.Log.IsEnabled())
{
OpenSslX509ChainEventSource.Log.CrlCacheInMemoryHit(cacheEntry.Expiration);
OpenSslX509ChainEventSource.Log.CrlCacheInMemoryHit(cacheEntry.Expiration.UtcDateTime);
}

AttachCrl(store, cacheEntry.CrlHandle);
Expand All @@ -103,7 +97,7 @@ private static bool AddCachedCrl(string crlFileName, SafeX509StoreHandle store,

if (OpenSslX509ChainEventSource.Log.IsEnabled())
{
OpenSslX509ChainEventSource.Log.CrlCacheInMemoryExpired(verificationTime, cacheEntry.Expiration);
OpenSslX509ChainEventSource.Log.CrlCacheInMemoryExpired(verificationTime.UtcDateTime, cacheEntry.Expiration.UtcDateTime);
}
}
finally
Expand Down Expand Up @@ -165,7 +159,7 @@ private static void AttachCrl(SafeX509StoreHandle store, SafeX509CrlHandle crl)
}
}

private static CachedCrlEntry? CheckDiskCache(string crlFileName, DateTime verificationTime)
private static CachedCrlEntry? CheckDiskCache(string crlFileName, DateTimeOffset verificationTime)
{
string crlFile = GetCachedCrlPath(crlFileName);

Expand All @@ -187,7 +181,7 @@ private static void AttachCrl(SafeX509StoreHandle store, SafeX509CrlHandle crl)
}
}

private static CachedCrlEntry? CheckDiskCacheCore(string crlFile, DateTime verificationTime)
private static CachedCrlEntry? CheckDiskCacheCore(string crlFile, DateTimeOffset verificationTime)
{
using (SafeBioHandle bio = Interop.Crypto.BioNewFile(crlFile, "rb"))
{
Expand Down Expand Up @@ -223,7 +217,7 @@ private static void AttachCrl(SafeX509StoreHandle store, SafeX509CrlHandle crl)
//
// If crl.NextUpdate is in the past, try downloading a newer version.
IntPtr nextUpdatePtr = Interop.Crypto.GetX509CrlNextUpdate(crl);
DateTime nextUpdate;
DateTimeOffset nextUpdate;

// If there is no crl.NextUpdate, this indicates that the CA is not providing
// any more updates to the CRL, or they made a mistake not providing a NextUpdate.
Expand All @@ -237,7 +231,7 @@ private static void AttachCrl(SafeX509StoreHandle store, SafeX509CrlHandle crl)

try
{
nextUpdate = ExpirationTimeFromCacheFileTime(File.GetLastWriteTime(crlFile));
nextUpdate = ExpirationTimeFromCacheFileTime(File.GetLastWriteTimeUtc(crlFile));
Comment thread
koen-lee marked this conversation as resolved.
}
catch
{
Expand All @@ -259,7 +253,7 @@ private static void AttachCrl(SafeX509StoreHandle store, SafeX509CrlHandle crl)
{
if (OpenSslX509ChainEventSource.Log.IsEnabled())
{
OpenSslX509ChainEventSource.Log.CrlCacheExpired(verificationTime, nextUpdate);
OpenSslX509ChainEventSource.Log.CrlCacheExpired(verificationTime.UtcDateTime, nextUpdate.UtcDateTime);
}

crl.Dispose();
Expand All @@ -268,7 +262,7 @@ private static void AttachCrl(SafeX509StoreHandle store, SafeX509CrlHandle crl)

if (OpenSslX509ChainEventSource.Log.IsEnabled())
{
OpenSslX509ChainEventSource.Log.CrlCacheAcceptedFile(nextUpdate);
OpenSslX509ChainEventSource.Log.CrlCacheAcceptedFile(nextUpdate.UtcDateTime);
}

return new CachedCrlEntry(crl, nextUpdate);
Expand Down Expand Up @@ -305,14 +299,14 @@ private static void DownloadAndAddCrl(
}

IntPtr nextUpdatePtr = Interop.Crypto.GetX509CrlNextUpdate(crl);
DateTime expiryTime;
DateTimeOffset expiryTime;

// If there is no crl.NextUpdate, this indicates that the CA is not providing
// any more updates to the CRL, or they made a mistake not providing a NextUpdate.
// We'll cache it for a few days to cover the case it was a mistake.
if (nextUpdatePtr == IntPtr.Zero)
{
expiryTime = ExpirationTimeFromCacheFileTime(DateTime.Now);
expiryTime = ExpirationTimeFromCacheFileTime(DateTimeOffset.UtcNow);
}
else
{
Expand Down Expand Up @@ -352,7 +346,7 @@ private static void DownloadAndAddCrl(
return new CachedCrlEntry(crl, expiryTime);
}

private static DateTime ExpirationTimeFromCacheFileTime(DateTime cacheFileTime)
private static DateTimeOffset ExpirationTimeFromCacheFileTime(DateTimeOffset cacheFileTime)
{
// CA/Browser Forum says that CRLs should be updated every 4 to 7 days,
// so recheck any cached CRL, that doesn't have a NextUpdate, every 3 days.
Expand Down Expand Up @@ -766,9 +760,9 @@ internal GCWatcher(MruCrlCache owner)
private sealed class CachedCrlEntry
{
internal SafeX509CrlHandle CrlHandle { get; }
internal DateTime Expiration { get; }
internal DateTimeOffset Expiration { get; }

internal CachedCrlEntry(SafeX509CrlHandle crlHandle, DateTime expiration)
internal CachedCrlEntry(SafeX509CrlHandle crlHandle, DateTimeOffset expiration)
{
CrlHandle = crlHandle;
Expiration = expiration;
Expand Down
Loading
Loading