123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375 |
- #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
- #pragma warning disable
- using System;
- using System.Collections;
- using System.IO;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Encoders;
- namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.IO.Pem
- {
- public class PemReader
- {
- private readonly TextReader reader;
- private readonly MemoryStream buffer;
- private readonly StreamWriter textBuffer;
- private readonly IList pushback = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateArrayList();
- int c = 0;
-
- public PemReader(TextReader reader)
- {
- if (reader == null)
- throw new ArgumentNullException("reader");
- buffer = new MemoryStream();
- textBuffer = new StreamWriter(buffer);
- this.reader = reader;
- }
- public TextReader Reader
- {
- get { return reader; }
- }
- /// <returns>
- /// A <see cref="PemObject"/>
- /// </returns>
- /// <exception cref="IOException"></exception>
- 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.
- return null;
- }
- // consume dash [-----]BEGIN ...
- if (!consumeDash())
- {
- throw new IOException("no data after consuming leading dashes");
- }
- skipWhiteSpace();
- if (!expect("BEGIN"))
- {
- continue;
- }
- break;
- }
- skipWhiteSpace();
- //
- // Consume type, accepting whitespace
- //
- if (!bufferUntilStopChar('-',false) )
- {
- throw new IOException("ran out of data before consuming type");
- }
- string type = bufferedString().Trim();
- // Consume dashes after type.
- if (!consumeDash())
- {
- throw new IOException("ran out of data consuming header");
- }
- skipWhiteSpace();
- //
- // Read ahead looking for headers.
- // Look for a colon for up to 64 characters, as an indication there might be a header.
- //
- IList headers = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateArrayList();
- while (seekColon(64))
- {
- if (!bufferUntilStopChar(':',false))
- {
- throw new IOException("ran out of data reading header key value");
- }
- string key = bufferedString().Trim();
- 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.
- {
- throw new IOException("ran out of data before consuming header value");
- }
- skipWhiteSpace();
- string value = bufferedString().Trim();
- headers.Add(new PemHeader(key,value));
- }
- //
- // Consume payload, ignoring all white space until we encounter a '-'
- //
- skipWhiteSpace();
- if (!bufferUntilStopChar('-',true))
- {
- throw new IOException("ran out of data before consuming payload");
- }
- string payload = bufferedString();
-
- // Seek the start of the end.
- if (!seekDash())
- {
- throw new IOException("did not find leading '-'");
- }
- if (!consumeDash())
- {
- throw new IOException("no data after consuming trailing dashes");
- }
- if (!expect("END "+type))
- {
- throw new IOException("END "+type+" was not found.");
- }
- if (!seekDash())
- {
- throw new IOException("did not find ending '-'");
- }
- // consume trailing dashes.
- consumeDash();
-
- return new PemObject(type, headers, Base64.Decode(payload));
- }
-
- private string bufferedString()
- {
- textBuffer.Flush();
- string value = Strings.FromUtf8ByteArray(buffer.ToArray());
- buffer.Position = 0;
- buffer.SetLength(0);
- return value;
- }
- private bool seekDash()
- {
- c = 0;
- while((c = Read()) >=0)
- {
- if (c == '-')
- {
- break;
- }
- }
- PushBack(c);
- return c == '-';
- }
- /// <summary>
- /// Seek ':" up to the limit.
- /// </summary>
- /// <param name="upTo"></param>
- /// <returns></returns>
- private bool seekColon(int upTo)
- {
- c = 0;
- bool colonFound = false;
- IList read = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateArrayList();
- for (; upTo>=0 && c >=0; upTo--)
- {
- c = Read();
- read.Add(c);
- if (c == ':')
- {
- colonFound = true;
- break;
- }
- }
- while(read.Count>0)
- {
- PushBack((int)read[read.Count-1]);
- read.RemoveAt(read.Count-1);
- }
- return colonFound;
- }
- /// <summary>
- /// Consume the dashes
- /// </summary>
- /// <returns></returns>
- private bool consumeDash()
- {
- c = 0;
- while ((c = Read()) >= 0)
- {
- if (c != '-')
- {
- break;
- }
- }
- PushBack(c);
- return c != -1;
- }
- /// <summary>
- /// Skip white space leave char in stream.
- /// </summary>
- private void skipWhiteSpace()
- {
- while ((c = Read()) >= 0)
- {
- if (c > ' ')
- {
- break;
- }
- }
- PushBack(c);
- }
- /// <summary>
- /// Read forward consuming the expected string.
- /// </summary>
- /// <param name="value">expected string</param>
- /// <returns>false if not consumed</returns>
- private bool expect(String value)
- {
- for (int t=0; t<value.Length; t++)
- {
- c = Read();
- if (c == value[t])
- {
- continue;
- } else
- {
- return false;
- }
- }
- return true;
- }
-
- /// <summary>
- /// Consume until dash.
- /// </summary>
- /// <returns>true if stream end not met</returns>
- private bool bufferUntilStopChar(char stopChar, bool skipWhiteSpace)
- {
- while ((c = Read()) >= 0)
- {
- if (skipWhiteSpace && c <=' ')
- {
- continue;
- }
- if (c != stopChar)
- {
- textBuffer.Write((char)c);
- textBuffer.Flush();
-
- } else
- {
- PushBack(c);
- break;
- }
- }
-
- return c > -1;
- }
- private void PushBack(int value)
- {
- if (pushback.Count == 0)
- {
- pushback.Add(value);
- } else
- {
- pushback.Insert(0, value);
- }
- }
- private int Read()
- {
- if (pushback.Count>0)
- {
- int i = (int)pushback[0];
- pushback.RemoveAt(0);
- return i;
- }
- return reader.Read();
- }
- }
- }
- #pragma warning restore
- #endif
|