/// <summary>
        /// Imports a collection of RFC 7468 PEM-encoded certificates.
        /// </summary>
        /// <param name="certPem">The text of the PEM-encoded X509 certificate collection.</param>
        /// <remarks>
        /// <para>
        /// PEM-encoded items with a CERTIFICATE PEM label will be imported. PEM items
        /// with other labels will be ignored.
        /// </para>
        /// <para>
        /// More advanced scenarios for loading certificates and
        /// can leverage <see cref="System.Security.Cryptography.PemEncoding" /> to enumerate
        /// PEM-encoded values and apply any custom loading behavior.
        /// </para>
        /// </remarks>
        /// <exception cref="CryptographicException">
        /// The decoded contents of a PEM are invalid or corrupt and could not be imported.
        /// </exception>
        public void ImportFromPem(ReadOnlySpan <char> certPem)
        {
            int added = 0;

            try
            {
                foreach ((ReadOnlySpan <char> contents, PemFields fields) in new PemEnumerator(certPem))
                {
                    ReadOnlySpan <char> label = contents[fields.Label];

                    if (label.SequenceEqual(PemLabels.X509Certificate))
                    {
                        // We verify below that every byte is written to.
                        byte[] certBytes = GC.AllocateUninitializedArray <byte>(fields.DecodedDataLength);

                        if (!Convert.TryFromBase64Chars(contents[fields.Base64Data], certBytes, out int bytesWritten) ||
                            bytesWritten != fields.DecodedDataLength)
                        {
                            Debug.Fail("The contents should have already been validated by the PEM reader.");
                            throw new CryptographicException(SR.Cryptography_X509_NoPemCertificate);
                        }

                        try
                        {
                            // Check that the contents are actually an X509 DER encoded
                            // certificate, not something else that the constructor will
                            // will otherwise be able to figure out.
                            CertificateAsn.Decode(certBytes, AsnEncodingRules.DER);
                        }
                        catch (CryptographicException)
                        {
                            throw new CryptographicException(SR.Cryptography_X509_NoPemCertificate);
                        }

                        Import(certBytes);
                        added++;
                    }
                }
            }
            catch
            {
                for (int i = 0; i < added; i++)
                {
                    RemoveAt(Count - 1);
                }
                throw;
            }
        }
Example #2
0
        internal CertificateData(byte[] rawData)
        {
#if DEBUG
            try
            {
#endif
            RawData     = rawData;
            certificate = CertificateAsn.Decode(rawData, AsnEncodingRules.DER);
            certificate.TbsCertificate.ValidateVersion();
            Issuer  = new X500DistinguishedName(certificate.TbsCertificate.Issuer.ToArray());
            Subject = new X500DistinguishedName(certificate.TbsCertificate.Subject.ToArray());

            using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
            {
                certificate.TbsCertificate.SubjectPublicKeyInfo.Encode(writer);
                SubjectPublicKeyInfo = writer.Encode();
            }

            Extensions = new List <X509Extension>();
            if (certificate.TbsCertificate.Extensions != null)
            {
                foreach (X509ExtensionAsn rawExtension in certificate.TbsCertificate.Extensions)
                {
                    X509Extension extension = new X509Extension(
                        rawExtension.ExtnId,
                        rawExtension.ExtnValue.ToArray(),
                        rawExtension.Critical);

                    Extensions.Add(extension);
                }
            }
#if DEBUG
        }

        catch (Exception e)
        {
            throw new CryptographicException(
                      $"Error in reading certificate:{Environment.NewLine}{PemPrintCert(rawData)}",
                      e);
        }
#endif
        }
        internal CertificateData(byte[] rawData)
        {
#if DEBUG
            try
            {
#endif
            RawData     = rawData;
            certificate = CertificateAsn.Decode(rawData, AsnEncodingRules.DER);
            certificate.TbsCertificate.ValidateVersion();
            Issuer      = new X500DistinguishedName(certificate.TbsCertificate.Issuer.Span);
            Subject     = new X500DistinguishedName(certificate.TbsCertificate.Subject.Span);
            IssuerName  = Issuer.Name;
            SubjectName = Subject.Name;

            AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
            certificate.TbsCertificate.SubjectPublicKeyInfo.Encode(writer);
            SubjectPublicKeyInfo = writer.Encode();

            Extensions = new List <X509Extension>((certificate.TbsCertificate.Extensions?.Length).GetValueOrDefault());
            if (certificate.TbsCertificate.Extensions != null)
            {
                foreach (X509ExtensionAsn rawExtension in certificate.TbsCertificate.Extensions)
                {
                    X509Extension extension = new X509Extension(
                        rawExtension.ExtnId,
                        rawExtension.ExtnValue.Span,
                        rawExtension.Critical);

                    Extensions.Add(extension);
                }
            }
#if DEBUG
        }

        catch (Exception e)
        {
            string pem = PemEncoding.WriteString(PemLabels.X509Certificate, rawData);
            throw new CryptographicException($"Error in reading certificate:{Environment.NewLine}{pem}", e);
        }
#endif
        }