{
unsafe
{
- Interop.Crypt32.CERT_CONTEXT* pCertContext = _certContext.CertContext;
- string keyAlgorithm = Marshal.PtrToStringAnsi(pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId)!;
- GC.KeepAlive(this);
- return keyAlgorithm;
+ return InvokeWithCertContext(static certContext =>
+ {
+ return Marshal.PtrToStringAnsi(certContext->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId)!;
+ });
}
}
}
{
unsafe
{
- Interop.Crypt32.CERT_CONTEXT* pCertContext = _certContext.CertContext;
- string keyAlgorithmOid = Marshal.PtrToStringAnsi(pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId)!;
-
- int algId;
- if (keyAlgorithmOid == Oids.Rsa)
- algId = AlgId.CALG_RSA_KEYX; // Fast-path for the most common case.
- else
- algId = Interop.Crypt32.FindOidInfo(Interop.Crypt32.CryptOidInfoKeyType.CRYPT_OID_INFO_OID_KEY, keyAlgorithmOid, OidGroup.PublicKeyAlgorithm, fallBackToAllGroups: true).AlgId;
-
- unsafe
+ return InvokeWithCertContext(pCertContext =>
{
- byte* NULL_ASN_TAG = (byte*)0x5;
+ string keyAlgorithmOid = Marshal.PtrToStringAnsi(pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId)!;
- byte[] keyAlgorithmParameters;
-
- if (algId == AlgId.CALG_DSS_SIGN
- && pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.cbData == 0
- && pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.pbData.ToPointer() == NULL_ASN_TAG)
- {
- //
- // DSS certificates may not have the DSS parameters in the certificate. In this case, we try to build
- // the certificate chain and propagate the parameters down from the certificate chain.
- //
- keyAlgorithmParameters = PropagateKeyAlgorithmParametersFromChain();
- }
+ int algId;
+ if (keyAlgorithmOid == Oids.Rsa)
+ algId = AlgId.CALG_RSA_KEYX; // Fast-path for the most common case.
else
+ algId = Interop.Crypt32.FindOidInfo(Interop.Crypt32.CryptOidInfoKeyType.CRYPT_OID_INFO_OID_KEY, keyAlgorithmOid, OidGroup.PublicKeyAlgorithm, fallBackToAllGroups: true).AlgId;
+
+ unsafe
{
- keyAlgorithmParameters = pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.ToByteArray();
+ byte* NULL_ASN_TAG = (byte*)0x5;
+
+ byte[] keyAlgorithmParameters;
+
+ if (algId == AlgId.CALG_DSS_SIGN
+ && pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.cbData == 0
+ && pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.pbData.ToPointer() == NULL_ASN_TAG)
+ {
+ //
+ // DSS certificates may not have the DSS parameters in the certificate. In this case, we try to build
+ // the certificate chain and propagate the parameters down from the certificate chain.
+ //
+ keyAlgorithmParameters = PropagateKeyAlgorithmParametersFromChain();
+ }
+ else
+ {
+ keyAlgorithmParameters = pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.ToByteArray();
+ }
+
+ return keyAlgorithmParameters;
}
-
- GC.KeepAlive(this);
- return keyAlgorithmParameters;
- }
+ });
}
}
}
{
unsafe
{
- Interop.Crypt32.CERT_CONTEXT* pCertContext = _certContext.CertContext;
- byte[] publicKey = pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.ToByteArray();
- GC.KeepAlive(this);
- return publicKey;
+ return InvokeWithCertContext(static pCertContext =>
+ {
+ return pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.ToByteArray();
+ });
}
}
}
{
unsafe
{
- Interop.Crypt32.CERT_CONTEXT* pCertContext = _certContext.CertContext;
- byte[] serialNumber = pCertContext->pCertInfo->SerialNumber.ToByteArray();
- Array.Reverse(serialNumber);
- GC.KeepAlive(this);
- return serialNumber;
+ return InvokeWithCertContext(static pCertContext =>
+ {
+ byte[] serialNumber = pCertContext->pCertInfo->SerialNumber.ToByteArray();
+ Array.Reverse(serialNumber);
+ return serialNumber;
+ });
}
}
}
{
unsafe
{
- Interop.Crypt32.CERT_CONTEXT* pCertContext = _certContext.CertContext;
- string signatureAlgorithm = Marshal.PtrToStringAnsi(pCertContext->pCertInfo->SignatureAlgorithm.pszObjId)!;
- GC.KeepAlive(this);
- return signatureAlgorithm;
+ return InvokeWithCertContext(static pCertContext =>
+ {
+ return Marshal.PtrToStringAnsi(pCertContext->pCertInfo->SignatureAlgorithm.pszObjId)!;
+ });
}
}
}
{
unsafe
{
- Interop.Crypt32.CERT_CONTEXT* pCertContext = _certContext.CertContext;
- DateTime notAfter = pCertContext->pCertInfo->NotAfter.ToDateTime();
- GC.KeepAlive(this);
- return notAfter;
+ return InvokeWithCertContext(static pCertContext => pCertContext->pCertInfo->NotAfter.ToDateTime());
}
}
}
{
unsafe
{
- Interop.Crypt32.CERT_CONTEXT* pCertContext = _certContext.CertContext;
- DateTime notBefore = pCertContext->pCertInfo->NotBefore.ToDateTime();
- GC.KeepAlive(this);
- return notBefore;
+ return InvokeWithCertContext(static pCertContext => pCertContext->pCertInfo->NotBefore.ToDateTime());
}
}
}
{
unsafe
{
- Interop.Crypt32.CERT_CONTEXT* pCertContext = _certContext.CertContext;
- byte[] rawData = new Span<byte>(pCertContext->pbCertEncoded, pCertContext->cbCertEncoded).ToArray();
- GC.KeepAlive(this);
- return rawData;
+ return InvokeWithCertContext(static pCertContext =>
+ {
+ return new Span<byte>(pCertContext->pbCertEncoded, pCertContext->cbCertEncoded).ToArray();
+ });
}
}
}
{
unsafe
{
- Interop.Crypt32.CERT_CONTEXT* pCertContext = _certContext.CertContext;
- int version = pCertContext->pCertInfo->dwVersion + 1;
- GC.KeepAlive(this);
- return version;
+ return InvokeWithCertContext(static pCertContext => pCertContext->pCertInfo->dwVersion + 1);
}
}
}
{
unsafe
{
- // X500DN creates a copy of the data for itself; data is kept alive with GC.KeepAlive.
- ReadOnlySpan<byte> encodedSubjectName = _certContext.CertContext->pCertInfo->Subject.DangerousAsSpan();
- X500DistinguishedName subjectName = new X500DistinguishedName(encodedSubjectName);
- GC.KeepAlive(this);
- return subjectName;
+ return InvokeWithCertContext(static certContext =>
+ {
+ ReadOnlySpan<byte> encodedSubjectName = certContext->pCertInfo->Subject.DangerousAsSpan();
+ X500DistinguishedName subjectName = new X500DistinguishedName(encodedSubjectName);
+ return subjectName;
+ });
}
}
}
{
unsafe
{
- // X500DN creates a copy of the data for itself; data is kept alive with GC.KeepAlive.
- ReadOnlySpan<byte> encodedIssuerName = _certContext.CertContext->pCertInfo->Issuer.DangerousAsSpan();
- X500DistinguishedName issuerName = new X500DistinguishedName(encodedIssuerName);
- GC.KeepAlive(this);
- return issuerName;
+ return InvokeWithCertContext(static certContext =>
+ {
+ ReadOnlySpan<byte> encodedIssuerName = certContext->pCertInfo->Issuer.DangerousAsSpan();
+ X500DistinguishedName issuerName = new X500DistinguishedName(encodedIssuerName);
+ return issuerName;
+ });
}
}
}
{
unsafe
{
- Interop.Crypt32.CERT_INFO* pCertInfo = _certContext.CertContext->pCertInfo;
- int numExtensions = pCertInfo->cExtension;
- X509Extension[] extensions = new X509Extension[numExtensions];
-
- for (int i = 0; i < numExtensions; i++)
+ return InvokeWithCertContext(static certContext =>
{
- Interop.Crypt32.CERT_EXTENSION* pCertExtension = (Interop.Crypt32.CERT_EXTENSION*)pCertInfo->rgExtension.ToPointer() + i;
- string oidValue = Marshal.PtrToStringAnsi(pCertExtension->pszObjId)!;
- Oid oid = new Oid(oidValue, friendlyName: null);
- bool critical = pCertExtension->fCritical != 0;
-
- // X509Extension creates a copy of the data for itself. The underlying data
- // is kept alive with the KeepAlive below.
- ReadOnlySpan<byte> rawData = pCertExtension->Value.DangerousAsSpan();
- extensions[i] = new X509Extension(oid, rawData, critical);
- }
+ Interop.Crypt32.CERT_INFO* pCertInfo = certContext->pCertInfo;
+ int numExtensions = pCertInfo->cExtension;
+ X509Extension[] extensions = new X509Extension[numExtensions];
+
+ for (int i = 0; i < numExtensions; i++)
+ {
+ Interop.Crypt32.CERT_EXTENSION* pCertExtension = (Interop.Crypt32.CERT_EXTENSION*)pCertInfo->rgExtension.ToPointer() + i;
+ string oidValue = Marshal.PtrToStringAnsi(pCertExtension->pszObjId)!;
+ Oid oid = new Oid(oidValue, friendlyName: null);
+ bool critical = pCertExtension->fCritical != 0;
+
+ // X509Extension creates a copy of the data for itself.
+ ReadOnlySpan<byte> rawData = pCertExtension->Value.DangerousAsSpan();
+ extensions[i] = new X509Extension(oid, rawData, critical);
+ }
- GC.KeepAlive(this);
- return extensions;
+ return extensions;
+ });
}
}
}
internal SafeCertContextHandle GetCertContext()
{
- SafeCertContextHandle certContext = Interop.Crypt32.CertDuplicateCertificateContext(_certContext.DangerousGetHandle());
- GC.KeepAlive(_certContext);
- return certContext;
+ unsafe
+ {
+ return InvokeWithCertContext(static certContext =>
+ {
+ return Interop.Crypt32.CertDuplicateCertificateContext((IntPtr)certContext);
+ });
+ }
}
private static Interop.Crypt32.CertNameType MapNameType(X509NameType nameType)
return exported;
}
}
+
+ private unsafe T InvokeWithCertContext<T>(CertContextCallback<T> callback)
+ {
+ bool added = false;
+ _certContext.DangerousAddRef(ref added);
+
+ try
+ {
+ return callback(_certContext.DangerousCertContext);
+ }
+ finally
+ {
+ if (added)
+ {
+ _certContext.DangerousRelease();
+ }
+ }
+ }
+
+ private unsafe delegate T CertContextCallback<T>(Interop.Crypt32.CERT_CONTEXT* certContext);
}
}
(hexValue, decimalValue),
static (state, pCertContext) =>
{
- ReadOnlySpan<byte> actual = pCertContext.CertContext->pCertInfo->SerialNumber.DangerousAsSpan();
+ // FindCore owns the lifetime of the CERT_CONTEXT and doesn't escape, so it can't be disposed of
+ // by another thread.
+ ReadOnlySpan<byte> actual = pCertContext.DangerousCertContext->pCertInfo->SerialNumber.DangerousAsSpan();
// Convert to BigInteger as the comparison must not fail due to spurious leading zeros
BigInteger actualAsBigInteger = new BigInteger(actual, isUnsigned: true);
{
int comparison = Interop.Crypt32.CertVerifyTimeValidity(
ref state.fileTime,
- pCertContext.CertContext->pCertInfo);
+ pCertContext.DangerousCertContext->pCertInfo);
GC.KeepAlive(pCertContext);
return comparison == state.compareResult;
});
// V2 format (XP only) can be a friendly name or an OID.
// An example of Template Name can be "ClientAuth".
+ // FindCore owns the lifetime of the CERT_CONTEXT and doesn't escape, so it can't be disposed of
+ // by another thread.
bool foundMatch = false;
- Interop.Crypt32.CERT_INFO* pCertInfo = pCertContext.CertContext->pCertInfo;
+ Interop.Crypt32.CERT_INFO* pCertInfo = pCertContext.DangerousCertContext->pCertInfo;
Interop.Crypt32.CERT_EXTENSION* pV1Template = Interop.Crypt32.CertFindExtension(
Oids.EnrollCertTypeExtension,
pCertInfo->cExtension,
oidValue,
static (oidValue, pCertContext) =>
{
- Interop.Crypt32.CERT_INFO* pCertInfo = pCertContext.CertContext->pCertInfo;
+ Interop.Crypt32.CERT_INFO* pCertInfo = pCertContext.DangerousCertContext->pCertInfo;
Interop.Crypt32.CERT_EXTENSION* pCertExtension = Interop.Crypt32.CertFindExtension(
Oids.CertPolicies,
pCertInfo->cExtension,
oidValue,
static (oidValue, pCertContext) =>
{
- Interop.Crypt32.CERT_INFO* pCertInfo = pCertContext.CertContext->pCertInfo;
+ Interop.Crypt32.CERT_INFO* pCertInfo = pCertContext.DangerousCertContext->pCertInfo;
Interop.Crypt32.CERT_EXTENSION* pCertExtension = Interop.Crypt32.CertFindExtension(oidValue, pCertInfo->cExtension, pCertInfo->rgExtension);
GC.KeepAlive(pCertContext);
return pCertExtension != null;
keyUsage,
static (keyUsage, pCertContext) =>
{
- Interop.Crypt32.CERT_INFO* pCertInfo = pCertContext.CertContext->pCertInfo;
+ Interop.Crypt32.CERT_INFO* pCertInfo = pCertContext.DangerousCertContext->pCertInfo;
X509KeyUsageFlags actual;
if (!Interop.crypt32.CertGetIntendedKeyUsage(Interop.Crypt32.CertEncodingType.All, pCertInfo, out actual, sizeof(X509KeyUsageFlags)))