You've already forked linux-packaging-mono
Imported Upstream version 5.16.0.100
Former-commit-id: 38faa55fb9669e35e7d8448b15c25dc447f25767
This commit is contained in:
parent
0a9828183b
commit
7d7f676260
@@ -4,7 +4,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.Private;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Internal.Cryptography
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -54,10 +54,16 @@ namespace Internal.Cryptography.Pal
|
||||
|
||||
using (SafeBioHandle bio = Interop.Crypto.CreateMemoryBio())
|
||||
{
|
||||
Interop.Crypto.CheckValidOpenSslHandle(bio);
|
||||
|
||||
Interop.Crypto.BioWrite(bio, data, data.Length);
|
||||
|
||||
handle = Interop.Crypto.PemReadBioX509Crl(bio);
|
||||
|
||||
// DecodeX509Crl failed, so we need to clear its error.
|
||||
// If PemReadBioX509Crl failed, clear that too.
|
||||
Interop.Crypto.ErrClearError();
|
||||
|
||||
if (!handle.IsInvalid)
|
||||
{
|
||||
return handle;
|
||||
|
||||
@@ -34,12 +34,13 @@ namespace Internal.Cryptography.Pal
|
||||
Debug.Assert(password != null);
|
||||
|
||||
ICertificatePal cert;
|
||||
Exception openSslException;
|
||||
|
||||
if (TryReadX509Der(rawData, out cert) ||
|
||||
TryReadX509Pem(rawData, out cert) ||
|
||||
PkcsFormatReader.TryReadPkcs7Der(rawData, out cert) ||
|
||||
PkcsFormatReader.TryReadPkcs7Pem(rawData, out cert) ||
|
||||
PkcsFormatReader.TryReadPkcs12(rawData, password, out cert))
|
||||
PkcsFormatReader.TryReadPkcs12(rawData, password, out cert, out openSslException))
|
||||
{
|
||||
if (cert == null)
|
||||
{
|
||||
@@ -51,7 +52,8 @@ namespace Internal.Cryptography.Pal
|
||||
}
|
||||
|
||||
// Unsupported
|
||||
throw Interop.Crypto.CreateOpenSslCryptographicException();
|
||||
Debug.Assert(openSslException != null);
|
||||
throw openSslException;
|
||||
}
|
||||
|
||||
public static ICertificatePal FromFile(string fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
|
||||
@@ -104,7 +106,9 @@ namespace Internal.Cryptography.Pal
|
||||
// Rewind, try again.
|
||||
RewindBio(bio, bioPosition);
|
||||
|
||||
if (PkcsFormatReader.TryReadPkcs12(bio, password, out certPal))
|
||||
// Capture the exception so in case of failure, the call to BioSeek does not override it.
|
||||
Exception openSslException;
|
||||
if (PkcsFormatReader.TryReadPkcs12(bio, password, out certPal, out openSslException))
|
||||
{
|
||||
return certPal;
|
||||
}
|
||||
@@ -112,14 +116,14 @@ namespace Internal.Cryptography.Pal
|
||||
// Since we aren't going to finish reading, leaving the buffer where it was when we got
|
||||
// it seems better than leaving it in some arbitrary other position.
|
||||
//
|
||||
// But, before seeking back to start, save the Exception representing the last reported
|
||||
// OpenSSL error in case the last BioSeek would change it.
|
||||
Exception openSslException = Interop.Crypto.CreateOpenSslCryptographicException();
|
||||
|
||||
// Use BioSeek directly for the last seek attempt, because any failure here should instead
|
||||
// report the already created (but not yet thrown) exception.
|
||||
Interop.Crypto.BioSeek(bio, bioPosition);
|
||||
if (Interop.Crypto.BioSeek(bio, bioPosition) < 0)
|
||||
{
|
||||
Interop.Crypto.ErrClearError();
|
||||
}
|
||||
|
||||
Debug.Assert(openSslException != null);
|
||||
throw openSslException;
|
||||
}
|
||||
|
||||
@@ -141,6 +145,7 @@ namespace Internal.Cryptography.Pal
|
||||
{
|
||||
certHandle.Dispose();
|
||||
certPal = null;
|
||||
Interop.Crypto.ErrClearError();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -156,6 +161,7 @@ namespace Internal.Cryptography.Pal
|
||||
{
|
||||
cert.Dispose();
|
||||
certPal = null;
|
||||
Interop.Crypto.ErrClearError();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -169,7 +175,11 @@ namespace Internal.Cryptography.Pal
|
||||
{
|
||||
Interop.Crypto.CheckValidOpenSslHandle(bio);
|
||||
|
||||
Interop.Crypto.BioWrite(bio, rawData, rawData.Length);
|
||||
if (Interop.Crypto.BioWrite(bio, rawData, rawData.Length) != rawData.Length)
|
||||
{
|
||||
Interop.Crypto.ErrClearError();
|
||||
}
|
||||
|
||||
return TryReadX509Pem(bio, out certPal);
|
||||
}
|
||||
}
|
||||
@@ -182,6 +192,7 @@ namespace Internal.Cryptography.Pal
|
||||
{
|
||||
cert.Dispose();
|
||||
fromBio = null;
|
||||
Interop.Crypto.ErrClearError();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -163,11 +163,7 @@ namespace Internal.Cryptography.Pal
|
||||
{
|
||||
userIntermediate.Add(cert);
|
||||
}
|
||||
catch (CryptographicException)
|
||||
{
|
||||
// Saving is opportunistic, just ignore failures
|
||||
}
|
||||
catch (IOException)
|
||||
catch
|
||||
{
|
||||
// Saving is opportunistic, just ignore failures
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace Internal.Cryptography.Pal
|
||||
{
|
||||
internal static class CrlCache
|
||||
{
|
||||
private const ulong X509_R_CERT_ALREADY_IN_HASH_TABLE = 0x0B07D065;
|
||||
|
||||
public static void AddCrlForCertificate(
|
||||
X509Certificate2 cert,
|
||||
SafeX509StoreHandle store,
|
||||
@@ -50,6 +52,7 @@ namespace Internal.Cryptography.Pal
|
||||
{
|
||||
if (bio.IsInvalid)
|
||||
{
|
||||
Interop.Crypto.ErrClearError();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -59,6 +62,7 @@ namespace Internal.Cryptography.Pal
|
||||
{
|
||||
if (crl.IsInvalid)
|
||||
{
|
||||
Interop.Crypto.ErrClearError();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -83,9 +87,18 @@ namespace Internal.Cryptography.Pal
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO (#3063): Check the return value of X509_STORE_add_crl, and throw on any error other
|
||||
// than X509_R_CERT_ALREADY_IN_HASH_TABLE
|
||||
Interop.Crypto.X509StoreAddCrl(store, crl);
|
||||
if (!Interop.Crypto.X509StoreAddCrl(store, crl))
|
||||
{
|
||||
// Ignore error "cert already in store", throw on anything else. In any case the error queue will be cleared.
|
||||
if (X509_R_CERT_ALREADY_IN_HASH_TABLE == Interop.Crypto.ErrPeekLastError())
|
||||
{
|
||||
Interop.Crypto.ErrClearError();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Interop.Crypto.CreateOpenSslCryptographicException();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -111,9 +124,18 @@ namespace Internal.Cryptography.Pal
|
||||
// null is a valid return (e.g. no remainingDownloadTime)
|
||||
if (crl != null && !crl.IsInvalid)
|
||||
{
|
||||
// TODO (#3063): Check the return value of X509_STORE_add_crl, and throw on any error other
|
||||
// than X509_R_CERT_ALREADY_IN_HASH_TABLE
|
||||
Interop.Crypto.X509StoreAddCrl(store, crl);
|
||||
if (!Interop.Crypto.X509StoreAddCrl(store, crl))
|
||||
{
|
||||
// Ignore error "cert already in store", throw on anything else. In any case the error queue will be cleared.
|
||||
if (X509_R_CERT_ALREADY_IN_HASH_TABLE == Interop.Crypto.ErrPeekLastError())
|
||||
{
|
||||
Interop.Crypto.ErrClearError();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Interop.Crypto.CreateOpenSslCryptographicException();
|
||||
}
|
||||
}
|
||||
|
||||
// Saving the CRL to the disk is just a performance optimization for later requests to not
|
||||
// need to use the network again, so failure to save shouldn't throw an exception or mark
|
||||
@@ -124,9 +146,10 @@ namespace Internal.Cryptography.Pal
|
||||
|
||||
using (SafeBioHandle bio = Interop.Crypto.BioNewFile(crlFile, "wb"))
|
||||
{
|
||||
if (!bio.IsInvalid)
|
||||
if (bio.IsInvalid || Interop.Crypto.PemWriteBioX509Crl(bio, crl) == 0)
|
||||
{
|
||||
Interop.Crypto.PemWriteBioX509Crl(bio, crl);
|
||||
// No bio, or write failed
|
||||
Interop.Crypto.ErrClearError();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -147,6 +170,11 @@ namespace Internal.Cryptography.Pal
|
||||
// X509_issuer_name_hash returns "unsigned long", which is marshalled as ulong.
|
||||
// But it only sets 32 bits worth of data, so force it down to uint just... in case.
|
||||
ulong persistentHashLong = Interop.Crypto.X509IssuerNameHash(pal.SafeHandle);
|
||||
if (persistentHashLong == 0)
|
||||
{
|
||||
Interop.Crypto.ErrClearError();
|
||||
}
|
||||
|
||||
uint persistentHash = unchecked((uint)persistentHashLong);
|
||||
|
||||
// OpenSSL's hashed filename algorithm is the 8-character hex version of the 32-bit value
|
||||
|
||||
@@ -116,6 +116,22 @@ namespace Internal.Cryptography.Pal
|
||||
throw new CryptographicException(SR.Cryptography_X509_StoreReadOnly);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
AddCertToStore(certPal);
|
||||
}
|
||||
catch (CryptographicException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new CryptographicException(SR.Cryptography_X509_StoreAddFailure, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddCertToStore(ICertificatePal certPal)
|
||||
{
|
||||
// This may well be the first time that we've added something to this store.
|
||||
Directory.CreateDirectory(_storePath);
|
||||
|
||||
|
||||
@@ -22,35 +22,17 @@ namespace Internal.Cryptography.Pal
|
||||
_pkcs12Handle = pkcs12Handle;
|
||||
}
|
||||
|
||||
public static bool TryRead(byte[] data, out OpenSslPkcs12Reader pkcs12Reader)
|
||||
{
|
||||
SafePkcs12Handle handle = Interop.Crypto.DecodePkcs12(data, data.Length);
|
||||
public static bool TryRead(byte[] data, out OpenSslPkcs12Reader pkcs12Reader) =>
|
||||
TryRead(data, out pkcs12Reader, out _, captureException: false);
|
||||
|
||||
if (!handle.IsInvalid)
|
||||
{
|
||||
pkcs12Reader = new OpenSslPkcs12Reader(handle);
|
||||
return true;
|
||||
}
|
||||
public static bool TryRead(byte[] data, out OpenSslPkcs12Reader pkcs12Reader, out Exception openSslException) =>
|
||||
TryRead(data, out pkcs12Reader, out openSslException, captureException: true);
|
||||
|
||||
handle.Dispose();
|
||||
pkcs12Reader = null;
|
||||
return false;
|
||||
}
|
||||
public static bool TryRead(SafeBioHandle fileBio, out OpenSslPkcs12Reader pkcs12Reader) =>
|
||||
TryRead(fileBio, out pkcs12Reader, out _, captureException: false);
|
||||
|
||||
public static bool TryRead(SafeBioHandle fileBio, out OpenSslPkcs12Reader pkcs12Reader)
|
||||
{
|
||||
SafePkcs12Handle p12 = Interop.Crypto.DecodePkcs12FromBio(fileBio);
|
||||
|
||||
if (!p12.IsInvalid)
|
||||
{
|
||||
pkcs12Reader = new OpenSslPkcs12Reader(p12);
|
||||
return true;
|
||||
}
|
||||
|
||||
p12.Dispose();
|
||||
pkcs12Reader = null;
|
||||
return false;
|
||||
}
|
||||
public static bool TryRead(SafeBioHandle fileBio, out OpenSslPkcs12Reader pkcs12Reader, out Exception openSslException) =>
|
||||
TryRead(fileBio, out pkcs12Reader, out openSslException, captureException: true);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
@@ -132,5 +114,55 @@ namespace Internal.Cryptography.Pal
|
||||
|
||||
return certs;
|
||||
}
|
||||
|
||||
private static bool TryRead(byte[] data, out OpenSslPkcs12Reader pkcs12Reader, out Exception openSslException, bool captureException)
|
||||
{
|
||||
SafePkcs12Handle handle = Interop.Crypto.DecodePkcs12(data, data.Length);
|
||||
openSslException = null;
|
||||
|
||||
if (!handle.IsInvalid)
|
||||
{
|
||||
pkcs12Reader = new OpenSslPkcs12Reader(handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
handle.Dispose();
|
||||
pkcs12Reader = null;
|
||||
if (captureException)
|
||||
{
|
||||
openSslException = Interop.Crypto.CreateOpenSslCryptographicException();
|
||||
}
|
||||
else
|
||||
{
|
||||
Interop.Crypto.ErrClearError();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryRead(SafeBioHandle fileBio, out OpenSslPkcs12Reader pkcs12Reader, out Exception openSslException, bool captureException)
|
||||
{
|
||||
SafePkcs12Handle p12 = Interop.Crypto.DecodePkcs12FromBio(fileBio);
|
||||
openSslException = null;
|
||||
|
||||
if (!p12.IsInvalid)
|
||||
{
|
||||
pkcs12Reader = new OpenSslPkcs12Reader(p12);
|
||||
return true;
|
||||
}
|
||||
|
||||
p12.Dispose();
|
||||
pkcs12Reader = null;
|
||||
if (captureException)
|
||||
{
|
||||
openSslException = Interop.Crypto.CreateOpenSslCryptographicException();
|
||||
}
|
||||
else
|
||||
{
|
||||
Interop.Crypto.ErrClearError();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,16 +380,19 @@ namespace Internal.Cryptography.Pal
|
||||
using (var systemIntermediateStore = new X509Store(StoreName.CertificateAuthority, StoreLocation.LocalMachine))
|
||||
using (var userRootStore = new X509Store(StoreName.Root, StoreLocation.CurrentUser))
|
||||
using (var userIntermediateStore = new X509Store(StoreName.CertificateAuthority, StoreLocation.CurrentUser))
|
||||
using (var userMyStore = new X509Store(StoreName.My, StoreLocation.CurrentUser))
|
||||
{
|
||||
systemRootStore.Open(OpenFlags.ReadOnly);
|
||||
systemIntermediateStore.Open(OpenFlags.ReadOnly);
|
||||
userRootStore.Open(OpenFlags.ReadOnly);
|
||||
userIntermediateStore.Open(OpenFlags.ReadOnly);
|
||||
userMyStore.Open(OpenFlags.ReadOnly);
|
||||
|
||||
X509Certificate2Collection systemRootCerts = systemRootStore.Certificates;
|
||||
X509Certificate2Collection systemIntermediateCerts = systemIntermediateStore.Certificates;
|
||||
X509Certificate2Collection userRootCerts = userRootStore.Certificates;
|
||||
X509Certificate2Collection userIntermediateCerts = userIntermediateStore.Certificates;
|
||||
X509Certificate2Collection userMyCerts = userMyStore.Certificates;
|
||||
|
||||
// fill the system trusted collection
|
||||
foreach (X509Certificate2 userRootCert in userRootCerts)
|
||||
@@ -416,6 +419,7 @@ namespace Internal.Cryptography.Pal
|
||||
X509Certificate2Collection[] storesToCheck =
|
||||
{
|
||||
extraStore,
|
||||
userMyCerts,
|
||||
userIntermediateCerts,
|
||||
systemIntermediateCerts,
|
||||
userRootCerts,
|
||||
@@ -452,7 +456,7 @@ namespace Internal.Cryptography.Pal
|
||||
candidates,
|
||||
ReferenceEqualityComparer<X509Certificate2>.Instance);
|
||||
|
||||
// Certificates come from 5 sources:
|
||||
// Certificates come from 6 sources:
|
||||
// 1) extraStore.
|
||||
// These are cert objects that are provided by the user, we shouldn't dispose them.
|
||||
// 2) the machine root store
|
||||
@@ -463,8 +467,11 @@ namespace Internal.Cryptography.Pal
|
||||
// These certs were either path candidates, or not. If they were, don't dispose them. Otherwise do.
|
||||
// 5) the user intermediate store
|
||||
// These certs were either path candidates, or not. If they were, don't dispose them. Otherwise do.
|
||||
// 6) the user my store
|
||||
// These certs were either path candidates, or not. If they were, don't dispose them. Otherwise do.
|
||||
DisposeUnreferenced(candidatesByReference, systemIntermediateCerts);
|
||||
DisposeUnreferenced(candidatesByReference, userIntermediateCerts);
|
||||
DisposeUnreferenced(candidatesByReference, userMyCerts);
|
||||
}
|
||||
|
||||
return candidates;
|
||||
|
||||
@@ -15,21 +15,35 @@ namespace Internal.Cryptography.Pal
|
||||
{
|
||||
using (SafePkcs7Handle pkcs7 = Interop.Crypto.DecodePkcs7(rawData, rawData.Length))
|
||||
{
|
||||
if (!pkcs7.IsInvalid)
|
||||
if (pkcs7.IsInvalid)
|
||||
{
|
||||
Interop.Crypto.ErrClearError();
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
using (SafeBioHandle bio = Interop.Crypto.CreateMemoryBio())
|
||||
{
|
||||
Interop.Crypto.CheckValidOpenSslHandle(bio);
|
||||
|
||||
Interop.Crypto.BioWrite(bio, rawData, rawData.Length);
|
||||
if (Interop.Crypto.BioWrite(bio, rawData, rawData.Length) != rawData.Length)
|
||||
{
|
||||
Interop.Crypto.ErrClearError();
|
||||
}
|
||||
|
||||
using (SafePkcs7Handle pkcs7 = Interop.Crypto.PemReadBioPkcs7(bio))
|
||||
{
|
||||
return !pkcs7.IsInvalid;
|
||||
if (pkcs7.IsInvalid)
|
||||
{
|
||||
Interop.Crypto.ErrClearError();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,7 +52,13 @@ namespace Internal.Cryptography.Pal
|
||||
{
|
||||
using (SafePkcs7Handle pkcs7 = Interop.Crypto.D2IPkcs7Bio(fileBio))
|
||||
{
|
||||
return !pkcs7.IsInvalid;
|
||||
if (pkcs7.IsInvalid)
|
||||
{
|
||||
Interop.Crypto.ErrClearError();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +66,13 @@ namespace Internal.Cryptography.Pal
|
||||
{
|
||||
using (SafePkcs7Handle pkcs7 = Interop.Crypto.PemReadBioPkcs7(fileBio))
|
||||
{
|
||||
return !pkcs7.IsInvalid;
|
||||
if (pkcs7.IsInvalid)
|
||||
{
|
||||
Interop.Crypto.ErrClearError();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,6 +116,7 @@ namespace Internal.Cryptography.Pal
|
||||
{
|
||||
certPal = null;
|
||||
certPals = null;
|
||||
Interop.Crypto.ErrClearError();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -109,6 +136,7 @@ namespace Internal.Cryptography.Pal
|
||||
{
|
||||
certPal = null;
|
||||
certPals = null;
|
||||
Interop.Crypto.ErrClearError();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -154,7 +182,10 @@ namespace Internal.Cryptography.Pal
|
||||
{
|
||||
Interop.Crypto.CheckValidOpenSslHandle(bio);
|
||||
|
||||
Interop.Crypto.BioWrite(bio, rawData, rawData.Length);
|
||||
if (Interop.Crypto.BioWrite(bio, rawData, rawData.Length) != rawData.Length)
|
||||
{
|
||||
Interop.Crypto.ErrClearError();
|
||||
}
|
||||
|
||||
return TryReadPkcs7Pem(bio, single, out certPal, out certPals);
|
||||
}
|
||||
@@ -172,6 +203,7 @@ namespace Internal.Cryptography.Pal
|
||||
{
|
||||
certPal = null;
|
||||
certPals = null;
|
||||
Interop.Crypto.ErrClearError();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -218,33 +250,32 @@ namespace Internal.Cryptography.Pal
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static bool TryReadPkcs12(byte[] rawData, SafePasswordHandle password, out ICertificatePal certPal)
|
||||
internal static bool TryReadPkcs12(byte[] rawData, SafePasswordHandle password, out ICertificatePal certPal, out Exception openSslException)
|
||||
{
|
||||
List<ICertificatePal> ignored;
|
||||
|
||||
return TryReadPkcs12(rawData, password, true, out certPal, out ignored);
|
||||
|
||||
return TryReadPkcs12(rawData, password, true, out certPal, out ignored, out openSslException);
|
||||
}
|
||||
|
||||
internal static bool TryReadPkcs12(SafeBioHandle bio, SafePasswordHandle password, out ICertificatePal certPal)
|
||||
internal static bool TryReadPkcs12(SafeBioHandle bio, SafePasswordHandle password, out ICertificatePal certPal, out Exception openSslException)
|
||||
{
|
||||
List<ICertificatePal> ignored;
|
||||
|
||||
return TryReadPkcs12(bio, password, true, out certPal, out ignored);
|
||||
return TryReadPkcs12(bio, password, true, out certPal, out ignored, out openSslException);
|
||||
}
|
||||
|
||||
internal static bool TryReadPkcs12(byte[] rawData, SafePasswordHandle password, out List<ICertificatePal> certPals)
|
||||
internal static bool TryReadPkcs12(byte[] rawData, SafePasswordHandle password, out List<ICertificatePal> certPals, out Exception openSslException)
|
||||
{
|
||||
ICertificatePal ignored;
|
||||
|
||||
return TryReadPkcs12(rawData, password, false, out ignored, out certPals);
|
||||
return TryReadPkcs12(rawData, password, false, out ignored, out certPals, out openSslException);
|
||||
}
|
||||
|
||||
internal static bool TryReadPkcs12(SafeBioHandle bio, SafePasswordHandle password, out List<ICertificatePal> certPals)
|
||||
internal static bool TryReadPkcs12(SafeBioHandle bio, SafePasswordHandle password, out List<ICertificatePal> certPals, out Exception openSslException)
|
||||
{
|
||||
ICertificatePal ignored;
|
||||
|
||||
return TryReadPkcs12(bio, password, false, out ignored, out certPals);
|
||||
return TryReadPkcs12(bio, password, false, out ignored, out certPals, out openSslException);
|
||||
}
|
||||
|
||||
private static bool TryReadPkcs12(
|
||||
@@ -252,12 +283,13 @@ namespace Internal.Cryptography.Pal
|
||||
SafePasswordHandle password,
|
||||
bool single,
|
||||
out ICertificatePal readPal,
|
||||
out List<ICertificatePal> readCerts)
|
||||
out List<ICertificatePal> readCerts,
|
||||
out Exception openSslException)
|
||||
{
|
||||
// DER-PKCS12
|
||||
OpenSslPkcs12Reader pfx;
|
||||
|
||||
if (!OpenSslPkcs12Reader.TryRead(rawData, out pfx))
|
||||
if (!OpenSslPkcs12Reader.TryRead(rawData, out pfx, out openSslException))
|
||||
{
|
||||
readPal = null;
|
||||
readCerts = null;
|
||||
@@ -275,12 +307,13 @@ namespace Internal.Cryptography.Pal
|
||||
SafePasswordHandle password,
|
||||
bool single,
|
||||
out ICertificatePal readPal,
|
||||
out List<ICertificatePal> readCerts)
|
||||
out List<ICertificatePal> readCerts,
|
||||
out Exception openSslException)
|
||||
{
|
||||
// DER-PKCS12
|
||||
OpenSslPkcs12Reader pfx;
|
||||
|
||||
if (!OpenSslPkcs12Reader.TryRead(bio, out pfx))
|
||||
if (!OpenSslPkcs12Reader.TryRead(bio, out pfx, out openSslException))
|
||||
{
|
||||
readPal = null;
|
||||
readCerts = null;
|
||||
|
||||
@@ -42,17 +42,19 @@ namespace Internal.Cryptography.Pal
|
||||
}
|
||||
|
||||
List<ICertificatePal> certPals;
|
||||
Exception openSslException;
|
||||
|
||||
if (PkcsFormatReader.TryReadPkcs7Der(rawData, out certPals) ||
|
||||
PkcsFormatReader.TryReadPkcs7Pem(rawData, out certPals) ||
|
||||
PkcsFormatReader.TryReadPkcs12(rawData, password, out certPals))
|
||||
PkcsFormatReader.TryReadPkcs12(rawData, password, out certPals, out openSslException))
|
||||
{
|
||||
Debug.Assert(certPals != null);
|
||||
|
||||
return ListToLoaderPal(certPals);
|
||||
}
|
||||
|
||||
throw Interop.Crypto.CreateOpenSslCryptographicException();
|
||||
Debug.Assert(openSslException != null);
|
||||
throw openSslException;
|
||||
}
|
||||
|
||||
public static ILoaderPal FromFile(string fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
|
||||
@@ -106,7 +108,9 @@ namespace Internal.Cryptography.Pal
|
||||
// Rewind, try again.
|
||||
CertificatePal.RewindBio(bio, bioPosition);
|
||||
|
||||
if (PkcsFormatReader.TryReadPkcs12(bio, password, out certPals))
|
||||
// Capture the exception so in case of failure, the call to BioSeek does not override it.
|
||||
Exception openSslException;
|
||||
if (PkcsFormatReader.TryReadPkcs12(bio, password, out certPals, out openSslException))
|
||||
{
|
||||
return ListToLoaderPal(certPals);
|
||||
}
|
||||
@@ -114,14 +118,14 @@ namespace Internal.Cryptography.Pal
|
||||
// Since we aren't going to finish reading, leaving the buffer where it was when we got
|
||||
// it seems better than leaving it in some arbitrary other position.
|
||||
//
|
||||
// But, before seeking back to start, save the Exception representing the last reported
|
||||
// OpenSSL error in case the last BioSeek would change it.
|
||||
Exception openSslException = Interop.Crypto.CreateOpenSslCryptographicException();
|
||||
|
||||
// Use BioSeek directly for the last seek attempt, because any failure here should instead
|
||||
// report the already created (but not yet thrown) exception.
|
||||
Interop.Crypto.BioSeek(bio, bioPosition);
|
||||
|
||||
if (Interop.Crypto.BioSeek(bio, bioPosition) < 0)
|
||||
{
|
||||
Interop.Crypto.ErrClearError();
|
||||
}
|
||||
|
||||
Debug.Assert(openSslException != null);
|
||||
throw openSslException;
|
||||
}
|
||||
|
||||
@@ -250,6 +254,13 @@ namespace Internal.Cryptography.Pal
|
||||
{
|
||||
using (SafeBioHandle fileBio = Interop.Crypto.BioNewFile(file.FullName, "rb"))
|
||||
{
|
||||
// The handle may be invalid, for example when we don't have read permission for the file.
|
||||
if (fileBio.IsInvalid)
|
||||
{
|
||||
Interop.Crypto.ErrClearError();
|
||||
continue;
|
||||
}
|
||||
|
||||
ICertificatePal pal;
|
||||
|
||||
while (CertificatePal.TryReadX509Pem(fileBio, out pal) ||
|
||||
|
||||
@@ -127,7 +127,7 @@ namespace Internal.Cryptography.Pal
|
||||
}
|
||||
}
|
||||
|
||||
if (addTrailingDelimiter)
|
||||
if (addTrailingDelimiter && decodedName.Length > 0)
|
||||
{
|
||||
decodedName.Append(dnSeparator);
|
||||
}
|
||||
@@ -150,7 +150,7 @@ namespace Internal.Cryptography.Pal
|
||||
case DerSequenceReader.DerTag.UTF8String:
|
||||
return tavReader.ReadUtf8String();
|
||||
case DerSequenceReader.DerTag.T61String:
|
||||
return "";
|
||||
return tavReader.ReadT61String();
|
||||
default:
|
||||
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
|
||||
}
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Text;
|
||||
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace Internal.Cryptography.Pal
|
||||
{
|
||||
internal static partial class X500NameEncoder
|
||||
{
|
||||
private static string X500DistinguishedNameDecode(
|
||||
byte[] encodedName,
|
||||
bool printOid,
|
||||
bool reverse,
|
||||
bool quoteIfNeeded,
|
||||
string dnSeparator,
|
||||
string multiValueSeparator,
|
||||
bool addTrailingDelimiter)
|
||||
{
|
||||
using (SafeX509NameHandle x509Name = Interop.Crypto.DecodeX509Name(encodedName, encodedName.Length))
|
||||
{
|
||||
if (x509Name.IsInvalid)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
// We need to allocate a StringBuilder to hold the data as we're building it, and there's the usual
|
||||
// arbitrary process of choosing a number that's "big enough" to minimize reallocations without wasting
|
||||
// too much space in the average case.
|
||||
//
|
||||
// So, let's look at an example of what our output might be.
|
||||
//
|
||||
// GitHub.com's SSL cert has a "pretty long" subject (partially due to the unknown OIDs):
|
||||
// businessCategory=Private Organization
|
||||
// 1.3.6.1.4.1.311.60.2.1.3=US
|
||||
// 1.3.6.1.4.1.311.60.2.1.2=Delaware
|
||||
// serialNumber=5157550
|
||||
// street=548 4th Street
|
||||
// postalCode=94107
|
||||
// C=US
|
||||
// ST=California
|
||||
// L=San Francisco
|
||||
// O=GitHub, Inc.
|
||||
// CN=github.com
|
||||
//
|
||||
// Which comes out to 228 characters using OpenSSL's default pretty-print
|
||||
// (openssl x509 -in github.cer -text -noout)
|
||||
// Throw in some "maybe-I-need-to-quote-this" quotes, and a couple of extra/extra-long O/OU values
|
||||
// and round that up to the next programmer number, and you get that 512 should avoid reallocations
|
||||
// in all but the most dire of cases.
|
||||
StringBuilder decodedName = new StringBuilder(512);
|
||||
int entryCount = Interop.Crypto.GetX509NameEntryCount(x509Name);
|
||||
bool printSpacing = false;
|
||||
|
||||
for (int i = 0; i < entryCount; i++)
|
||||
{
|
||||
int loc = reverse ? entryCount - i - 1 : i;
|
||||
|
||||
using (SafeSharedX509NameEntryHandle nameEntry = Interop.Crypto.GetX509NameEntry(x509Name, loc))
|
||||
{
|
||||
Interop.Crypto.CheckValidOpenSslHandle(nameEntry);
|
||||
|
||||
string thisOidValue;
|
||||
|
||||
using (SafeSharedAsn1ObjectHandle oidHandle = Interop.Crypto.GetX509NameEntryOid(nameEntry))
|
||||
{
|
||||
thisOidValue = Interop.Crypto.GetOidValue(oidHandle);
|
||||
}
|
||||
|
||||
if (printSpacing)
|
||||
{
|
||||
decodedName.Append(dnSeparator);
|
||||
}
|
||||
else
|
||||
{
|
||||
printSpacing = true;
|
||||
}
|
||||
|
||||
if (printOid)
|
||||
{
|
||||
AppendOid(decodedName, thisOidValue);
|
||||
}
|
||||
|
||||
string rdnValue;
|
||||
|
||||
using (SafeSharedAsn1StringHandle valueHandle = Interop.Crypto.GetX509NameEntryData(nameEntry))
|
||||
{
|
||||
rdnValue = Interop.Crypto.Asn1StringToManagedString(valueHandle);
|
||||
}
|
||||
|
||||
bool quote = quoteIfNeeded && NeedsQuoting(rdnValue);
|
||||
|
||||
if (quote)
|
||||
{
|
||||
decodedName.Append('"');
|
||||
|
||||
// If the RDN itself had a quote within it, that quote needs to be escaped
|
||||
// with another quote.
|
||||
rdnValue = rdnValue.Replace("\"", "\"\"");
|
||||
}
|
||||
|
||||
decodedName.Append(rdnValue);
|
||||
|
||||
if (quote)
|
||||
{
|
||||
decodedName.Append('"');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (addTrailingDelimiter)
|
||||
{
|
||||
decodedName.Append(dnSeparator);
|
||||
}
|
||||
|
||||
return decodedName.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ namespace Internal.Cryptography.Pal
|
||||
byte[] encodedName,
|
||||
bool printOid,
|
||||
X500DistinguishedNameFlags flags,
|
||||
bool addTrailingDelimieter=false)
|
||||
bool addTrailingDelimiter = false)
|
||||
{
|
||||
bool reverse = (flags & X500DistinguishedNameFlags.Reversed) == X500DistinguishedNameFlags.Reversed;
|
||||
bool quoteIfNeeded = (flags & X500DistinguishedNameFlags.DoNotUseQuotes) != X500DistinguishedNameFlags.DoNotUseQuotes;
|
||||
@@ -51,7 +51,8 @@ namespace Internal.Cryptography.Pal
|
||||
{
|
||||
dnSeparator = "; ";
|
||||
}
|
||||
else if ((flags & X500DistinguishedNameFlags.UseNewLines) == X500DistinguishedNameFlags.UseNewLines)
|
||||
// Explicit UseCommas has preference over explicit UseNewLines.
|
||||
else if ((flags & (X500DistinguishedNameFlags.UseNewLines | X500DistinguishedNameFlags.UseCommas)) == X500DistinguishedNameFlags.UseNewLines)
|
||||
{
|
||||
dnSeparator = Environment.NewLine;
|
||||
}
|
||||
@@ -73,7 +74,7 @@ namespace Internal.Cryptography.Pal
|
||||
quoteIfNeeded,
|
||||
dnSeparator,
|
||||
multiValueSparator,
|
||||
addTrailingDelimieter);
|
||||
addTrailingDelimiter);
|
||||
}
|
||||
catch (CryptographicException)
|
||||
{
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Internal.Cryptography.Pal
|
||||
{
|
||||
Debug.Assert(index < chainStatus.Length);
|
||||
|
||||
chainStatus[index].StatusInformation = GetSystemErrorString(mapping.Win32ErrorCode);
|
||||
chainStatus[index].StatusInformation = Interop.Kernel32.GetMessage(mapping.Win32ErrorCode);
|
||||
chainStatus[index].Status = mapping.ChainStatusFlag;
|
||||
index++;
|
||||
dwStatus &= ~mapping.Win32Flag;
|
||||
@@ -60,23 +60,6 @@ namespace Internal.Cryptography.Pal
|
||||
return chainStatus;
|
||||
}
|
||||
|
||||
private static string GetSystemErrorString(int errorCode)
|
||||
{
|
||||
StringBuilder strMessage = new StringBuilder(512);
|
||||
int dwErrorCode = Interop.localization.FormatMessage(
|
||||
FormatMessageFlags.FORMAT_MESSAGE_FROM_SYSTEM | FormatMessageFlags.FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
IntPtr.Zero,
|
||||
errorCode,
|
||||
0,
|
||||
strMessage,
|
||||
strMessage.Capacity,
|
||||
IntPtr.Zero);
|
||||
if (dwErrorCode != 0)
|
||||
return strMessage.ToString();
|
||||
else
|
||||
return SR.Unknown_Error;
|
||||
}
|
||||
|
||||
private readonly struct X509ChainErrorMapping
|
||||
{
|
||||
public readonly CertTrustErrorStatus Win32Flag;
|
||||
|
||||
@@ -35,24 +35,23 @@ namespace Internal.Cryptography.Pal
|
||||
{
|
||||
exception = null;
|
||||
|
||||
CERT_CHAIN_POLICY_PARA para = new CERT_CHAIN_POLICY_PARA()
|
||||
unsafe
|
||||
{
|
||||
cbSize = Marshal.SizeOf<CERT_CHAIN_POLICY_PARA>(),
|
||||
dwFlags = (int)flags,
|
||||
};
|
||||
CERT_CHAIN_POLICY_PARA para = new CERT_CHAIN_POLICY_PARA();
|
||||
para.cbSize = sizeof(CERT_CHAIN_POLICY_PARA);
|
||||
para.dwFlags = (int)flags;
|
||||
|
||||
CERT_CHAIN_POLICY_STATUS status = new CERT_CHAIN_POLICY_STATUS()
|
||||
{
|
||||
cbSize = Marshal.SizeOf<CERT_CHAIN_POLICY_STATUS>(),
|
||||
};
|
||||
CERT_CHAIN_POLICY_STATUS status = new CERT_CHAIN_POLICY_STATUS();
|
||||
status.cbSize = sizeof(CERT_CHAIN_POLICY_STATUS);
|
||||
|
||||
if (!Interop.crypt32.CertVerifyCertificateChainPolicy(ChainPolicy.CERT_CHAIN_POLICY_BASE, _chain, ref para, ref status))
|
||||
{
|
||||
int errorCode = Marshal.GetLastWin32Error();
|
||||
exception = errorCode.ToCryptographicException();
|
||||
return default(bool?);
|
||||
if (!Interop.crypt32.CertVerifyCertificateChainPolicy(ChainPolicy.CERT_CHAIN_POLICY_BASE, _chain, ref para, ref status))
|
||||
{
|
||||
int errorCode = Marshal.GetLastWin32Error();
|
||||
exception = errorCode.ToCryptographicException();
|
||||
return default(bool?);
|
||||
}
|
||||
return status.dwError == 0;
|
||||
}
|
||||
return status.dwError == 0;
|
||||
}
|
||||
|
||||
public X509ChainElement[] ChainElements
|
||||
|
||||
@@ -360,7 +360,7 @@ namespace Internal.Cryptography.Pal
|
||||
// This needs to be kept in sync with IsCertValid in the
|
||||
// Unix/OpenSSL PAL version (and potentially any other PALs that come about)
|
||||
ChainPal chainPal = ChainPal.BuildChain(
|
||||
true,
|
||||
false,
|
||||
CertificatePal.FromHandle(pCertContext.DangerousGetHandle()),
|
||||
null, //extraStore
|
||||
null, //applicationPolicy
|
||||
|
||||
@@ -5,13 +5,9 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using Internal.Cryptography.Pal;
|
||||
|
||||
namespace Internal.Cryptography.Pal.Native
|
||||
{
|
||||
internal static class Helpers
|
||||
@@ -30,41 +26,44 @@ namespace Internal.Cryptography.Pal.Native
|
||||
return SafeLocalAllocHandle.InvalidHandle;
|
||||
}
|
||||
|
||||
// Copy the oid strings to a local list to prevent a security race condition where
|
||||
// Copy the oid strings to a local array to prevent a security race condition where
|
||||
// the OidCollection or individual oids can be modified by another thread and
|
||||
// potentially cause a buffer overflow
|
||||
List<byte[]> oidStrings = new List<byte[]>();
|
||||
foreach (Oid oid in oids)
|
||||
var oidStrings = new string[oids.Count];
|
||||
for (int i = 0; i < oidStrings.Length; i++)
|
||||
{
|
||||
byte[] oidString = oid.ValueAsAscii();
|
||||
oidStrings.Add(oidString);
|
||||
oidStrings[i] = oids[i].Value;
|
||||
}
|
||||
|
||||
numOids = oidStrings.Count;
|
||||
unsafe
|
||||
{
|
||||
int allocationSize = checked(numOids * sizeof(void*));
|
||||
foreach (byte[] oidString in oidStrings)
|
||||
int allocationSize = checked(oidStrings.Length * sizeof(void*));
|
||||
foreach (string oidString in oidStrings)
|
||||
{
|
||||
checked
|
||||
{
|
||||
allocationSize += oidString.Length + 1;
|
||||
allocationSize += oidString.Length + 1; // Encoding.ASCII doesn't have a fallback, so it's fine to use String.Length
|
||||
}
|
||||
}
|
||||
|
||||
SafeLocalAllocHandle safeLocalAllocHandle = SafeLocalAllocHandle.Create(allocationSize);
|
||||
byte** pOidPointers = (byte**)(safeLocalAllocHandle.DangerousGetHandle());
|
||||
byte* pOidContents = (byte*)(pOidPointers + numOids);
|
||||
byte* pOidContents = (byte*)(pOidPointers + oidStrings.Length);
|
||||
|
||||
for (int i = 0; i < numOids; i++)
|
||||
for (int i = 0; i < oidStrings.Length; i++)
|
||||
{
|
||||
string oidString = oidStrings[i];
|
||||
|
||||
pOidPointers[i] = pOidContents;
|
||||
byte[] oidString = oidStrings[i];
|
||||
Marshal.Copy(oidString, 0, new IntPtr(pOidContents), oidString.Length);
|
||||
|
||||
int bytesWritten = Encoding.ASCII.GetBytes(oidString, new Span<byte>(pOidContents, oidString.Length));
|
||||
Debug.Assert(bytesWritten == oidString.Length);
|
||||
|
||||
pOidContents[oidString.Length] = 0;
|
||||
pOidContents += oidString.Length + 1;
|
||||
}
|
||||
|
||||
numOids = oidStrings.Length;
|
||||
return safeLocalAllocHandle;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using Internal.Cryptography.Pal.Native;
|
||||
|
||||
internal static partial class Interop
|
||||
{
|
||||
public static class localization
|
||||
{
|
||||
[DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "FormatMessageW")]
|
||||
public static extern int FormatMessage(FormatMessageFlags dwFlags, IntPtr lpSource, int dwMessageId, int dwLanguageId, [Out] StringBuilder lpBuffer, int nSize, IntPtr Arguments);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user