}
}
+ 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);
get
{
EnsureCertData();
- return _certData.RawData;
+ return _certData.RawData.CloneByteArray();
}
}
internal X500DistinguishedName Issuer;
internal X500DistinguishedName Subject;
internal List<X509Extension> Extensions;
+ internal string IssuerName;
+ internal string SubjectName;
internal int Version => certificate.TbsCertificate.Version;
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);
private SafeEvpPKeyHandle? _privateKey;
private X500DistinguishedName? _subjectName;
private X500DistinguishedName? _issuerName;
+ private string? _subject;
+ private string? _issuer;
public static ICertificatePal FromHandle(IntPtr handle)
{
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);
}
}
+ [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;
}
}
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()
{
using (X509Certificate2 c1 = new X509Certificate2(TestData.MsCertificate))