Example #1
0
        public static unsafe bool TryExportToPem <T>(
            T arg,
            string label,
            TryExportKeyAction <T> exporter,
            Span <char> destination,
            out int charsWritten)
        {
            int bufferSize = 4096;

            while (true)
            {
                byte[] buffer       = CryptoPool.Rent(bufferSize);
                int    bytesWritten = 0;
                bufferSize = buffer.Length;

                // Fixed to prevent GC moves.
                fixed(byte *bufferPtr = buffer)
                {
                    try
                    {
                        if (exporter(arg, buffer, out bytesWritten))
                        {
                            Span <byte> writtenSpan = new Span <byte>(buffer, 0, bytesWritten);
                            return(PemEncoding.TryWrite(label, writtenSpan, destination, out charsWritten));
                        }
                    }
                    finally
                    {
                        CryptoPool.Return(buffer, bytesWritten);
                    }

                    bufferSize = checked (bufferSize * 2);
                }
            }
        }
Example #2
0
        public bool TryExportPkcs7Pem(Span <char> destination, out int charsWritten)
        {
            byte[]? pkcs7 = Export(X509ContentType.Pkcs7);

            if (pkcs7 is null)
            {
                throw new CryptographicException(SR.Cryptography_X509_ExportFailed);
            }

            return(PemEncoding.TryWrite(PemLabels.Pkcs7Certificate, pkcs7, destination, out charsWritten));
        }
Example #3
0
        public static void TryWrite_Simple()
        {
            char[] buffer = new char[1000];
            string label  = "HELLO";

            byte[] content = new byte[] { 0x66, 0x6F, 0x6F };
            Assert.True(PemEncoding.TryWrite(label, content, buffer, out int charsWritten));
            string pem = new string(buffer, 0, charsWritten);

            Assert.Equal("-----BEGIN HELLO-----\nZm9v\n-----END HELLO-----", pem);
        }
Example #4
0
        /// <summary>
        /// Attempts to export the public X.509 certificates, encoded as PEM.
        /// </summary>
        /// <param name="destination">The buffer to receive the PEM encoded certificates.</param>
        /// <param name="charsWritten">When this method returns, the total number of characters written to <paramref name="destination" />.</param>
        /// <returns>
        ///   <see langword="true"/> if <paramref name="destination"/> was large enough to receive the encoded PEMs;
        ///   otherwise, <see langword="false" />.
        /// </returns>
        /// <exception cref="CryptographicException">
        /// A certificate is corrupt, in an invalid state, or could not be exported
        /// to PEM.
        /// </exception>
        /// <remarks>
        /// <p>
        ///   A PEM-encoded X.509 certificate collection will contain certificates
        ///   where each certificate begins with <c>-----BEGIN CERTIFICATE-----</c>
        ///   and ends with <c>-----END CERTIFICATE-----</c>, with the base64 encoded DER
        ///   contents of the certificate between the PEM boundaries. Each certificate is
        ///   separated by a single line-feed character.
        /// </p>
        /// <p>
        ///   Certificates are encoded according to the IETF RFC 7468 &quot;strict&quot;
        ///   encoding rules.
        /// </p>
        /// </remarks>
        public bool TryExportCertificatePems(Span <char> destination, out int charsWritten)
        {
            Span <char> buffer  = destination;
            int         written = 0;

            for (int i = 0; i < Count; i++)
            {
                ReadOnlyMemory <byte> certData = this[i].RawDataMemory;
                int certSize = PemEncoding.GetEncodedSize(PemLabels.X509Certificate.Length, certData.Length);

                // If we ran out of space in the destination, return false. It's okay
                // that we may have successfully written data to the destination
                // already. Since certificates only contain "public" information,
                // we don't need to clear what has been written already.
                if (buffer.Length < certSize)
                {
                    charsWritten = 0;
                    return(false);
                }

                if (!PemEncoding.TryWrite(PemLabels.X509Certificate, certData.Span, buffer, out int certWritten) ||
                    certWritten != certSize)
                {
                    Debug.Fail("Presized buffer is too small or did not write the correct amount.");
                    throw new CryptographicException();
                }

                buffer   = buffer.Slice(certWritten);
                written += certWritten;

                // write a new line if not the last certificate.
                if (i < Count - 1)
                {
                    if (buffer.IsEmpty)
                    {
                        charsWritten = 0;
                        return(false);
                    }

                    // Always use Unix line endings between certificates to match the
                    // behavior of PemEncoding.TryWrite, which is following RFC 7468.
                    buffer[0] = '\n';
                    buffer    = buffer.Slice(1);
                    written++;
                }
            }

            charsWritten = written;
            return(true);
        }
Example #5
0
        internal static string CreatePemFromData(string label, ReadOnlyMemory <byte> data)
        {
            int pemSize = PemEncoding.GetEncodedSize(label.Length, data.Length);

            return(string.Create(pemSize, (label, data), static (destination, args) =>
            {
                (string label, ReadOnlyMemory <byte> data) = args;

                if (!PemEncoding.TryWrite(label, data.Span, destination, out int charsWritten) ||
                    charsWritten != destination.Length)
                {
                    Debug.Fail("Pre-allocated buffer was not the correct size.");
                    throw new CryptographicException();
                }
            }));
Example #6
0
        public static unsafe bool TryExportToEncryptedPem <T>(
            T arg,
            ReadOnlySpan <char> password,
            PbeParameters pbeParameters,
            TryExportEncryptedKeyAction <T> exporter,
            Span <char> destination,
            out int charsWritten)
        {
            int bufferSize = 4096;

            while (true)
            {
                byte[] buffer       = CryptoPool.Rent(bufferSize);
                int    bytesWritten = 0;
                bufferSize = buffer.Length;

                // Fixed to prevent GC moves.
                fixed(byte *bufferPtr = buffer)
                {
                    try
                    {
                        if (exporter(arg, password, pbeParameters, buffer, out bytesWritten))
                        {
                            Span <byte> writtenSpan = new Span <byte>(buffer, 0, bytesWritten);
                            return(PemEncoding.TryWrite(PemLabels.EncryptedPkcs8PrivateKey, writtenSpan, destination, out charsWritten));
                        }
                    }
                    finally
                    {
                        CryptoPool.Return(buffer, bytesWritten);
                    }

                    bufferSize = checked (bufferSize * 2);
                }
            }
        }