Imported Upstream version 5.16.0.100

Former-commit-id: 38faa55fb9669e35e7d8448b15c25dc447f25767
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2018-08-07 15:19:03 +00:00
parent 0a9828183b
commit 7d7f676260
4419 changed files with 170950 additions and 90273 deletions

View File

@@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Private;
using System.Globalization;
namespace Internal.Cryptography

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
}
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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) ||

View File

@@ -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);
}

View File

@@ -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();
}
}
}
}

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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