Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create copies of mutable properties on X509Certificate2 #38884

Merged
merged 6 commits into from
Jul 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,23 @@ public IntPtr Handle
}
}

public string Issuer
{
get
{
EnsureCertData();
return _certData.IssuerName;
}
}

public string Issuer => IssuerName.Name;

public string Subject => SubjectName.Name;
public string Subject
{
get
{
EnsureCertData();
return _certData.SubjectName;
}
}

public string LegacyIssuer => IssuerName.Decode(X500DistinguishedNameFlags.None);

Expand Down Expand Up @@ -323,7 +336,7 @@ public byte[] RawData
get
{
EnsureCertData();
return _certData.RawData;
return _certData.RawData.CloneByteArray();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ public AlgorithmIdentifier(AlgorithmIdentifierAsn algorithmIdentifier)
internal X500DistinguishedName Issuer;
internal X500DistinguishedName Subject;
internal List<X509Extension> Extensions;
internal string IssuerName;
internal string SubjectName;

internal int Version => certificate.TbsCertificate.Version;

Expand Down Expand Up @@ -82,6 +84,8 @@ internal CertificateData(byte[] rawData)
certificate.TbsCertificate.ValidateVersion();
Issuer = new X500DistinguishedName(certificate.TbsCertificate.Issuer.ToArray());
Subject = new X500DistinguishedName(certificate.TbsCertificate.Subject.ToArray());
IssuerName = Issuer.Name;
SubjectName = Subject.Name;

AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
certificate.TbsCertificate.SubjectPublicKeyInfo.Encode(writer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ internal sealed class OpenSslX509CertificateReader : ICertificatePal
private SafeEvpPKeyHandle? _privateKey;
private X500DistinguishedName? _subjectName;
private X500DistinguishedName? _issuerName;
private string? _subject;
private string? _issuer;

public static ICertificatePal FromHandle(IntPtr handle)
{
Expand Down Expand Up @@ -259,9 +261,37 @@ internal SafeX509Handle SafeHandle
get { return _cert; }
}

public string Issuer => IssuerName.Name;
public string Issuer
{
get
{
if (_issuer == null)
{
// IssuerName is mutable to callers in X509Certificate. We want to be
// able to get the issuer even if IssuerName has been mutated, so we
// don't use it here.
_issuer = Interop.Crypto.LoadX500Name(Interop.Crypto.X509GetIssuerName(_cert)).Name;
}

return _issuer;
}
}

public string Subject => SubjectName.Name;
public string Subject
{
get
{
if (_subject == null)
{
// SubjectName is mutable to callers in X509Certificate. We want to be
// able to get the subject even if SubjectName has been mutated, so we
// don't use it here.
_subject = Interop.Crypto.LoadX500Name(Interop.Crypto.X509GetSubjectName(_cert)).Name;
}

return _subject;
}
}

public string LegacyIssuer => IssuerName.Decode(X500DistinguishedNameFlags.None);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,39 @@ public static void SerializedCertDisposeDoesNotRemoveKeyFile()
}
}

[Fact]
public static void CopyResult_RawData()
{
using (X509Certificate2 cert = new X509Certificate2(TestData.MsCertificate))
{
byte[] first = cert.RawData;
byte[] second = cert.RawData;
Assert.NotSame(first, second);
}
}

[Fact]
public static void MutateDistinguishedName_IssuerName_DoesNotImpactIssuer()
{
using (X509Certificate2 cert = new X509Certificate2(TestData.MsCertificate))
{
byte[] issuerBytes = cert.IssuerName.RawData;
Array.Clear(issuerBytes, 0, issuerBytes.Length);
Assert.Equal("CN=Microsoft Code Signing PCA, O=Microsoft Corporation, L=Redmond, S=Washington, C=US", cert.Issuer);
}
}

[Fact]
public static void MutateDistinguishedName_SubjectName_DoesNotImpactSubject()
{
using (X509Certificate2 cert = new X509Certificate2(TestData.MsCertificate))
{
byte[] subjectBytes = cert.SubjectName.RawData;
Array.Clear(subjectBytes, 0, subjectBytes.Length);
Assert.Equal("CN=Microsoft Corporation, OU=MOPR, O=Microsoft Corporation, L=Redmond, S=Washington, C=US", cert.Subject);
}
}

public static IEnumerable<object[]> StorageFlags => CollectionImportTests.StorageFlags;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ namespace System.Security.Cryptography.X509Certificates.Tests
{
public static class ExportTests
{
[Fact]
public static void ExportAsCert_CreatesCopy()
{
using (X509Certificate2 cert = new X509Certificate2(TestData.MsCertificate))
{
byte[] first = cert.Export(X509ContentType.Cert);
byte[] second = cert.Export(X509ContentType.Cert);
Assert.NotSame(first, second);
}
}

[Fact]
public static void ExportAsCert()
{
Expand Down