From c93162764c5097f65f2792c577f8a7658c6ee0dc Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Mon, 16 Jan 2023 18:36:02 +0700 Subject: Refactoring in PEM classes --- crypto/src/openssl/MiscPemGenerator.cs | 10 +- crypto/src/openssl/PEMReader.cs | 30 ++-- crypto/src/openssl/PEMWriter.cs | 30 ++-- crypto/src/util/io/pem/PemObject.cs | 18 +-- crypto/src/util/io/pem/PemReader.cs | 253 ++++++++++++--------------------- crypto/src/util/io/pem/PemWriter.cs | 42 +++--- 6 files changed, 151 insertions(+), 232 deletions(-) diff --git a/crypto/src/openssl/MiscPemGenerator.cs b/crypto/src/openssl/MiscPemGenerator.cs index 0e918f793..fe2583063 100644 --- a/crypto/src/openssl/MiscPemGenerator.cs +++ b/crypto/src/openssl/MiscPemGenerator.cs @@ -32,15 +32,11 @@ namespace Org.BouncyCastle.OpenSsl private readonly SecureRandom random; public MiscPemGenerator(object obj) + : this(obj, null, null, null) { - this.obj = obj; } - public MiscPemGenerator( - object obj, - string algorithm, - char[] password, - SecureRandom random) + public MiscPemGenerator(object obj, string algorithm, char[] password, SecureRandom random) { this.obj = obj; this.algorithm = algorithm; @@ -54,9 +50,7 @@ namespace Org.BouncyCastle.OpenSsl throw new ArgumentNullException("obj"); if (obj is AsymmetricCipherKeyPair keyPair) - { return CreatePemObject(keyPair.Private); - } string type; byte[] encoding; diff --git a/crypto/src/openssl/PEMReader.cs b/crypto/src/openssl/PEMReader.cs index d2354dbe3..a2c4fd1d6 100644 --- a/crypto/src/openssl/PEMReader.cs +++ b/crypto/src/openssl/PEMReader.cs @@ -367,23 +367,17 @@ namespace Org.BouncyCastle.OpenSsl } } - // TODO Add an equivalent class for ECNamedCurveParameterSpec? - //private ECNamedCurveParameterSpec ReadECParameters( -// private X9ECParameters ReadECParameters(PemObject pemObject) -// { -// DerObjectIdentifier oid = (DerObjectIdentifier)Asn1Object.FromByteArray(pemObject.Content); -// -// //return ECNamedCurveTable.getParameterSpec(oid.Id); -// return GetCurveParameters(oid.Id); -// } - - private static X9ECParameters GetCurveParameters(string name) - { - X9ECParameters ecP = ECKeyPairGenerator.FindECCurveByName(name); - if (ecP == null) - throw new Exception("unknown curve name: " + name); - - return ecP; - } + //private X9ECParameters ReadECParameters(PemObject pemObject) + //{ + // DerObjectIdentifier oid = (DerObjectIdentifier)Asn1Object.FromByteArray(pemObject.Content); + + // //return ECNamedCurveTable.getParameterSpec(oid.Id); + // return GetCurveParameters(oid.Id); + //} + + //private static X9ECParameters GetCurveParameters(string name) + //{ + // return ECKeyPairGenerator.FindECCurveByName(name) ?? throw new Exception("unknown curve name: " + name); + //} } } diff --git a/crypto/src/openssl/PEMWriter.cs b/crypto/src/openssl/PEMWriter.cs index 043869cc3..58b6156d5 100644 --- a/crypto/src/openssl/PEMWriter.cs +++ b/crypto/src/openssl/PEMWriter.cs @@ -17,26 +17,22 @@ namespace Org.BouncyCastle.OpenSsl public void WriteObject(object obj) { - try - { - base.WriteObject(new MiscPemGenerator(obj)); - } - catch (PemGenerationException e) - { - if (e.InnerException is IOException inner) - throw inner; - - throw e; - } + WriteObject(obj, null, null, null); } - public void WriteObject( - object obj, - string algorithm, - char[] password, - SecureRandom random) + public void WriteObject(object obj, string algorithm, char[] password, SecureRandom random) { - base.WriteObject(new MiscPemGenerator(obj, algorithm, password, random)); + try + { + base.WriteObject(new MiscPemGenerator(obj, algorithm, password, random)); + } + catch (PemGenerationException e) + { + if (e.InnerException is IOException inner) + throw inner; + + throw e; + } } } } diff --git a/crypto/src/util/io/pem/PemObject.cs b/crypto/src/util/io/pem/PemObject.cs index 2a152f81d..ccba962af 100644 --- a/crypto/src/util/io/pem/PemObject.cs +++ b/crypto/src/util/io/pem/PemObject.cs @@ -6,9 +6,9 @@ namespace Org.BouncyCastle.Utilities.IO.Pem public class PemObject : PemObjectGenerator { - private string type; - private IList headers; - private byte[] content; + private readonly string m_type; + private readonly IList m_headers; + private readonly byte[] m_content; public PemObject(string type, byte[] content) : this(type, new List(), content) @@ -17,24 +17,24 @@ namespace Org.BouncyCastle.Utilities.IO.Pem public PemObject(string type, IList headers, byte[] content) { - this.type = type; - this.headers = new List(headers); - this.content = content; + m_type = type; + m_headers = new List(headers); + m_content = content; } public string Type { - get { return type; } + get { return m_type; } } public IList Headers { - get { return headers; } + get { return m_headers; } } public byte[] Content { - get { return content; } + get { return m_content; } } public PemObject Generate() diff --git a/crypto/src/util/io/pem/PemReader.cs b/crypto/src/util/io/pem/PemReader.cs index 77b457338..6e27a3749 100644 --- a/crypto/src/util/io/pem/PemReader.cs +++ b/crypto/src/util/io/pem/PemReader.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Text; using Org.BouncyCastle.Utilities.Encoders; @@ -8,18 +9,19 @@ namespace Org.BouncyCastle.Utilities.IO.Pem { public class PemReader : IDisposable - { - private readonly TextReader reader; - private readonly MemoryStream buffer; - private readonly StreamWriter textBuffer; - private readonly List pushback = new List(); - int c = 0; + { + private const int LineLength = 64; + + private readonly TextReader m_reader; + private readonly MemoryStream m_buffer; + private readonly StreamWriter m_textBuffer; + private readonly Stack m_pushback = new Stack(); public PemReader(TextReader reader) { - this.reader = reader ?? throw new ArgumentNullException(nameof(reader)); - this.buffer = new MemoryStream(); - this.textBuffer = new StreamWriter(buffer); + m_reader = reader ?? throw new ArgumentNullException(nameof(reader)); + m_buffer = new MemoryStream(); + m_textBuffer = new StreamWriter(m_buffer); } #region IDisposable @@ -34,15 +36,15 @@ namespace Org.BouncyCastle.Utilities.IO.Pem { if (disposing) { - reader.Dispose(); + m_reader.Dispose(); } } #endregion - public TextReader Reader + public TextReader Reader { - get { return reader; } + get { return m_reader; } } @@ -52,65 +54,43 @@ namespace Org.BouncyCastle.Utilities.IO.Pem /// public PemObject ReadPemObject() { - // // Look for BEGIN // for (;;) { - // Seek a leading dash, ignore anything up to that point. - if (!seekDash()) - { - // There are no pem objects here. + if (!SeekDash()) return null; - } - // consume dash [-----]BEGIN ... - if (!consumeDash()) - { + if (!ConsumeDash()) throw new IOException("no data after consuming leading dashes"); - } - - - skipWhiteSpace(); - - - if (!expect("BEGIN")) - { - continue; - } - break; + SkipWhiteSpace(); + if (Expect("BEGIN")) + break; } - - skipWhiteSpace(); + SkipWhiteSpace(); // // Consume type, accepting whitespace // - if (!bufferUntilStopChar('-',false) ) - { + if (!BufferUntilStopChar('-', false)) throw new IOException("ran out of data before consuming type"); - } - - string type = bufferedString().Trim(); + string type = BufferedString().Trim(); // Consume dashes after type. - if (!consumeDash()) - { + if (!ConsumeDash()) throw new IOException("ran out of data consuming header"); - } - - skipWhiteSpace(); + SkipWhiteSpace(); // // Read ahead looking for headers. @@ -119,127 +99,106 @@ namespace Org.BouncyCastle.Utilities.IO.Pem var headers = new List(); - while (seekColon(64)) + while (SeekColon(LineLength)) { - - if (!bufferUntilStopChar(':',false)) - { + if (!BufferUntilStopChar(':', false)) throw new IOException("ran out of data reading header key value"); - } - - string key = bufferedString().Trim(); + string key = BufferedString().Trim(); - c = Read(); + int c = Read(); if (c != ':') - { throw new IOException("expected colon"); - } - // // We are going to look for well formed headers, if they do not end with a "LF" we cannot // discern where they end. // - - if (!bufferUntilStopChar('\n', false)) // Now read to the end of the line. - { + + if (!BufferUntilStopChar('\n', false)) // Now read to the end of the line. throw new IOException("ran out of data before consuming header value"); - } - skipWhiteSpace(); + SkipWhiteSpace(); - string value = bufferedString().Trim(); - headers.Add(new PemHeader(key,value)); + string value = BufferedString().Trim(); + headers.Add(new PemHeader(key, value)); } - // // Consume payload, ignoring all white space until we encounter a '-' // - skipWhiteSpace(); + SkipWhiteSpace(); - if (!bufferUntilStopChar('-',true)) - { + if (!BufferUntilStopChar('-', true)) throw new IOException("ran out of data before consuming payload"); - } - string payload = bufferedString(); - + string payload = BufferedString(); + // Seek the start of the end. - if (!seekDash()) - { + if (!SeekDash()) throw new IOException("did not find leading '-'"); - } - if (!consumeDash()) - { + if (!ConsumeDash()) throw new IOException("no data after consuming trailing dashes"); - } - - if (!expect("END "+type)) - { - throw new IOException("END "+type+" was not found."); - } - + if (!Expect("END " + type)) + throw new IOException("END " + type + " was not found."); - if (!seekDash()) - { + if (!SeekDash()) throw new IOException("did not find ending '-'"); - } - // consume trailing dashes. - consumeDash(); - + ConsumeDash(); return new PemObject(type, headers, Base64.Decode(payload)); - } - - - private string bufferedString() + private string BufferedString() { - textBuffer.Flush(); - string value = Strings.FromUtf8ByteArray(buffer.ToArray()); - buffer.Position = 0; - buffer.SetLength(0); + m_textBuffer.Flush(); + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + if (!m_buffer.TryGetBuffer(out var data)) + throw new InvalidOperationException(); + + string value = Encoding.UTF8.GetString(data); +#else + string value = Strings.FromUtf8ByteArray(m_buffer.ToArray()); +#endif + + m_buffer.Position = 0; + m_buffer.SetLength(0); + return value; } - - private bool seekDash() + private bool SeekDash() { - c = 0; - while((c = Read()) >=0) + int c; + while ((c = Read()) >= 0) { if (c == '-') - { break; - } } PushBack(c); - return c == '-'; + return c >= 0; } - /// /// Seek ':" up to the limit. /// /// /// - private bool seekColon(int upTo) + private bool SeekColon(int upTo) { - c = 0; + int c = 0; bool colonFound = false; var read = new List(); - for (; upTo>=0 && c >=0; upTo--) + for (; upTo >= 0 && c >= 0; upTo--) { c = Read(); read.Add(c); @@ -250,49 +209,45 @@ namespace Org.BouncyCastle.Utilities.IO.Pem } } - while(read.Count>0) - { - PushBack((int)read[read.Count-1]); - read.RemoveAt(read.Count-1); - } + int readPos = read.Count; + while (--readPos >= 0) + { + PushBack(read[readPos]); + } return colonFound; } - - /// /// Consume the dashes /// /// - private bool consumeDash() + private bool ConsumeDash() { - c = 0; + int c; while ((c = Read()) >= 0) { if (c != '-') - { break; - } } PushBack(c); - return c != -1; + return c >= 0; } /// /// Skip white space leave char in stream. /// - private void skipWhiteSpace() + private void SkipWhiteSpace() { + int c; while ((c = Read()) >= 0) { if (c > ' ') - { break; - } } + PushBack(c); } @@ -301,19 +256,12 @@ namespace Org.BouncyCastle.Utilities.IO.Pem /// /// expected string /// false if not consumed - - private bool expect(string value) + private bool Expect(string value) { - for (int t=0; t /// true if stream end not met - private bool bufferUntilStopChar(char stopChar, bool skipWhiteSpace) + private bool BufferUntilStopChar(char stopChar, bool skipWhiteSpace) { + int c; while ((c = Read()) >= 0) { - if (skipWhiteSpace && c <=' ') - { + if (skipWhiteSpace && c <= ' ') continue; - } - if (c != stopChar) + if (c == stopChar) { - textBuffer.Write((char)c); - textBuffer.Flush(); - - } else - { - PushBack(c); - break; + PushBack(c); + break; } + + m_textBuffer.Write((char)c); + m_textBuffer.Flush(); } - - return c > -1; + + return c >= 0; } private void PushBack(int value) { - if (pushback.Count == 0) - { - pushback.Add(value); - } else - { - pushback.Insert(0, value); - } + m_pushback.Push(value); } private int Read() { - if (pushback.Count > 0) - { - int i = pushback[0]; - pushback.RemoveAt(0); - return i; - } + if (m_pushback.Count > 0) + return m_pushback.Pop(); - return reader.Read(); + return m_reader.Read(); } } } diff --git a/crypto/src/util/io/pem/PemWriter.cs b/crypto/src/util/io/pem/PemWriter.cs index ee92556c7..ce7b38821 100644 --- a/crypto/src/util/io/pem/PemWriter.cs +++ b/crypto/src/util/io/pem/PemWriter.cs @@ -13,9 +13,9 @@ namespace Org.BouncyCastle.Utilities.IO.Pem { private const int LineLength = 64; - private readonly TextWriter writer; - private readonly int nlLength; - private char[] buf = new char[LineLength]; + private readonly TextWriter m_writer; + private readonly int m_nlLength; + private readonly char[] m_buf = new char[LineLength]; /** * Base constructor. @@ -24,8 +24,8 @@ namespace Org.BouncyCastle.Utilities.IO.Pem */ public PemWriter(TextWriter writer) { - this.writer = writer ?? throw new ArgumentNullException(nameof(writer)); - this.nlLength = Environment.NewLine.Length; + m_writer = writer ?? throw new ArgumentNullException(nameof(writer)); + m_nlLength = Environment.NewLine.Length; } #region IDisposable @@ -40,7 +40,7 @@ namespace Org.BouncyCastle.Utilities.IO.Pem { if (disposing) { - writer.Dispose(); + m_writer.Dispose(); } } @@ -48,7 +48,7 @@ namespace Org.BouncyCastle.Utilities.IO.Pem public TextWriter Writer { - get { return writer; } + get { return m_writer; } } /** @@ -61,22 +61,22 @@ namespace Org.BouncyCastle.Utilities.IO.Pem public int GetOutputSize(PemObject obj) { // BEGIN and END boundaries. - int size = (2 * (obj.Type.Length + 10 + nlLength)) + 6 + 4; + int size = (2 * (obj.Type.Length + 10 + m_nlLength)) + 6 + 4; if (obj.Headers.Count > 0) { foreach (PemHeader header in obj.Headers) { - size += header.Name.Length + ": ".Length + header.Value.Length + nlLength; + size += header.Name.Length + ": ".Length + header.Value.Length + m_nlLength; } - size += nlLength; + size += m_nlLength; } // base64 encoding int dataLen = ((obj.Content.Length + 2) / 3) * 4; - size += dataLen + (((dataLen + LineLength - 1) / LineLength) * nlLength); + size += dataLen + (((dataLen + LineLength - 1) / LineLength) * m_nlLength); return size; } @@ -91,12 +91,12 @@ namespace Org.BouncyCastle.Utilities.IO.Pem { foreach (PemHeader header in obj.Headers) { - writer.Write(header.Name); - writer.Write(": "); - writer.WriteLine(header.Value); + m_writer.Write(header.Name); + m_writer.Write(": "); + m_writer.WriteLine(header.Value); } - writer.WriteLine(); + m_writer.WriteLine(); } WriteEncoded(obj.Content); @@ -107,29 +107,29 @@ namespace Org.BouncyCastle.Utilities.IO.Pem { bytes = Base64.Encode(bytes); - for (int i = 0; i < bytes.Length; i += buf.Length) + for (int i = 0; i < bytes.Length; i += m_buf.Length) { int index = 0; - while (index != buf.Length) + while (index != m_buf.Length) { if ((i + index) >= bytes.Length) break; - buf[index] = (char)bytes[i + index]; + m_buf[index] = (char)bytes[i + index]; index++; } - writer.WriteLine(buf, 0, index); + m_writer.WriteLine(m_buf, 0, index); } } private void WritePreEncapsulationBoundary(string type) { - writer.WriteLine("-----BEGIN " + type + "-----"); + m_writer.WriteLine("-----BEGIN " + type + "-----"); } private void WritePostEncapsulationBoundary(string type) { - writer.WriteLine("-----END " + type + "-----"); + m_writer.WriteLine("-----END " + type + "-----"); } } } -- cgit 1.4.1