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); } } }
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)); }
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); }
/// <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 "strict" /// 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); }
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(); } }));
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); } } }