public static readonly PemKind PgpMessagePartX; // How to handle this? /// <summary> /// Initializes the <see cref="PemKind"/> class. /// </summary> static PemKind() { registry = new Dictionary <string, PemKind>(); X509Certificate = new PemKind("CERTIFICATE", "Stores a X509 Certificate"); X509CertificatePair = new PemKind("CERTIFICATE PAIR", "Stores a pair of X509 Certificates"); X509TrustedCertificate = new PemKind("TRUSTED CERTIFICATE", "Stores a trusted X509 Certificate"); X509CertificateRequest = new PemKind("CERTIFICATE REQUEST", "Stores a X509 Certificate Signature Request"); // PKCS #10 X509CertificateRevocationList = new PemKind("X509 CRL", "Stores a X509 Certificate Revocation List"); AnyPrivateKey = new PemKind("ANY PRIVATE KEY", "Stores a private key"); PublicKey = new PemKind("PUBLIC KEY", "Stores a public key"); RsaPrivateKey = new PemKind("RSA PRIVATE KEY", "Stores a RSA private key"); RsaPublicKey = new PemKind("RSA PUBLIC KEY", "Stores a RSA public key"); DsaPrivateKey = new PemKind("DSA PRIVATE KEY", "Stores a DSA private key"); DsaPublicKey = new PemKind("DSA PUBLIC KEY", "Stores a DSA public key"); DsaParameters = new PemKind("DSA PARAMETERS", "Stores DSA parameters"); EcdsaPrivateKey = new PemKind("EC PRIVATE KEY", "Stores a ECDSA private key"); EcdsaPublicKey = new PemKind("ECDSA PUBLIC KEY", "Stores a ECDSA public key"); EcdsaParameters = new PemKind("EC PARAMETERS", "Stores ECDSA parameters"); Parameters = new PemKind("PARAMETERS", "Stores a cryptographic algorithm parameters"); Pkcs7 = new PemKind("PKCS7", "Stores a PKCS #7 message"); Pkcs7Signed = new PemKind("PKCS #7 SIGNED DATA", "Stores a signed PKCS #7 message"); Pkcs8Encrypted = new PemKind("ENCRYPTED PRIVATE KEY", "Stores an encrypted PKCS #8 key pair"); Pkcs8 = new PemKind("PRIVATE KEY", "Stores a PKCS #8 key pair"); DiffieHelmmanPkcs3 = new PemKind("DH PARAMETERS", "Stores Diffie–Hellman Key Agreement parameters according to the scheme specified by PKCS #3"); DiffieHelmmanX942 = new PemKind("X9.42 DH PARAMETERS", "Stores Diffie–Hellman Key Agreement parameters according to the scheme specified in ANSI X9.42"); SslSession = new PemKind("SSL SESSION PARAMETERS", "Stores the parameters of a SSL session"); Cms = new PemKind("CMS", "Stores Cryptographic Message Syntax data"); X509CertificateOld = new PemKind("X509 CERTIFICATE", "Stores a X509 Certificate; obsolete, prefer 'CERTIFICATE'", true); X509CertificateRequestOld = new PemKind("NEW CERTIFICATE REQUEST", "Stores a X509 Certificate Request; obsolete, prefer 'CERTIFICATE REQUEST'", true); // Below are other common PEM Headers (but not grabbed from OpenSSL) Ssh2PublicKeyRfc4716 = new PemKind("SSH2 PUBLIC KEY", "Stores an SSH2 Public Key according to RFC 4716"); // ASCII-armored PGP files PgpPublicKey = new PemKind("PGP PUBLIC KEY BLOCK", "Stores a PGP Public Key and its checksum", hasPgpChecksum: true); PgpPrivateKey = new PemKind("PGP PRIVATE KEY BLOCK", "Stores a PGP Private Key and its checksum", hasPgpChecksum: true); PgpSignature = new PemKind("PGP SIGNATURE", "Stores a PGP Signature and its checksum", hasPgpChecksum: true); PgpMessage = new PemKind("PGP MESSAGE", "Stores a PGP Public Key and its checksum", hasPgpChecksum: true); PgpMessagePartXY = new PemKind("PGP MESSAGE, PART {0}/{1}", "Stores a PGP Public Key and its checksum", hasPgpChecksum: true); // how to handle this? PgpMessagePartX = new PemKind("PGP MESSAGE, PART {0}", "Stores a PGP Public Key and its checksum", hasPgpChecksum: true); // how to handle this? }
public static readonly PemKind PgpMessagePartX; // How to handle this? /// <summary> /// Initializes the <see cref="PemKind"/> class. /// </summary> static PemKind() { registry = new Dictionary<string, PemKind>(); X509Certificate = new PemKind("CERTIFICATE", "Stores a X509 Certificate"); X509CertificatePair = new PemKind("CERTIFICATE PAIR", "Stores a pair of X509 Certificates"); X509TrustedCertificate = new PemKind("TRUSTED CERTIFICATE", "Stores a trusted X509 Certificate"); X509CertificateRequest = new PemKind("CERTIFICATE REQUEST", "Stores a X509 Certificate Signature Request"); // PKCS #10 X509CertificateRevocationList = new PemKind("X509 CRL", "Stores a X509 Certificate Revocation List"); AnyPrivateKey = new PemKind("ANY PRIVATE KEY", "Stores a private key"); PublicKey = new PemKind("PUBLIC KEY", "Stores a public key"); RsaPrivateKey = new PemKind("RSA PRIVATE KEY", "Stores a RSA private key"); RsaPublicKey = new PemKind("RSA PUBLIC KEY", "Stores a RSA public key"); DsaPrivateKey = new PemKind("DSA PRIVATE KEY", "Stores a DSA private key"); DsaPublicKey = new PemKind("DSA PUBLIC KEY", "Stores a DSA public key"); DsaParameters = new PemKind("DSA PARAMETERS", "Stores DSA parameters"); EcdsaPrivateKey = new PemKind("EC PRIVATE KEY", "Stores a ECDSA private key"); EcdsaPublicKey = new PemKind("ECDSA PUBLIC KEY", "Stores a ECDSA public key"); EcdsaParameters = new PemKind("EC PARAMETERS", "Stores ECDSA parameters"); Parameters = new PemKind("PARAMETERS", "Stores a cryptographic algorithm parameters"); Pkcs7 = new PemKind("PKCS7", "Stores a PKCS #7 message"); Pkcs7Signed = new PemKind("PKCS #7 SIGNED DATA", "Stores a signed PKCS #7 message"); Pkcs8Encrypted = new PemKind("ENCRYPTED PRIVATE KEY", "Stores an encrypted PKCS #8 key pair"); Pkcs8 = new PemKind("PRIVATE KEY", "Stores a PKCS #8 key pair"); DiffieHelmmanPkcs3 = new PemKind("DH PARAMETERS", "Stores Diffie–Hellman Key Agreement parameters according to the scheme specified by PKCS #3"); DiffieHelmmanX942 = new PemKind("X9.42 DH PARAMETERS", "Stores Diffie–Hellman Key Agreement parameters according to the scheme specified in ANSI X9.42"); SslSession = new PemKind("SSL SESSION PARAMETERS", "Stores the parameters of a SSL session"); Cms = new PemKind("CMS", "Stores Cryptographic Message Syntax data"); X509CertificateOld = new PemKind("X509 CERTIFICATE", "Stores a X509 Certificate; obsolete, prefer 'CERTIFICATE'", true); X509CertificateRequestOld = new PemKind("NEW CERTIFICATE REQUEST", "Stores a X509 Certificate Request; obsolete, prefer 'CERTIFICATE REQUEST'", true); // Below are other common PEM Headers (but not grabbed from OpenSSL) Ssh2PublicKeyRfc4716 = new PemKind("SSH2 PUBLIC KEY", "Stores an SSH2 Public Key according to RFC 4716"); // ASCII-armored PGP files PgpPublicKey = new PemKind("PGP PUBLIC KEY BLOCK", "Stores a PGP Public Key and its checksum", hasPgpChecksum: true); PgpPrivateKey = new PemKind("PGP PRIVATE KEY BLOCK", "Stores a PGP Private Key and its checksum", hasPgpChecksum: true); PgpSignature = new PemKind("PGP SIGNATURE", "Stores a PGP Signature and its checksum", hasPgpChecksum: true); PgpMessage = new PemKind("PGP MESSAGE", "Stores a PGP Public Key and its checksum", hasPgpChecksum: true); PgpMessagePartXY = new PemKind("PGP MESSAGE, PART {0}/{1}", "Stores a PGP Public Key and its checksum", hasPgpChecksum: true); // how to handle this? PgpMessagePartX = new PemKind("PGP MESSAGE, PART {0}", "Stores a PGP Public Key and its checksum", hasPgpChecksum: true); // how to handle this? }
private PemInfo Decode() { if (dirty) { throw new InvalidOperationException("A PemDecoder instance should only be used once."); } dirty = true; var strings = ReadAllLines(TextData); if (strings == null || strings.Length == 0) { AddError("No data."); return(null); } var altHeader = false; FullHeader = strings[0]; if (!IsHeader(FullHeader, out altHeader)) { AddError("First line does not contain a PEM Header."); return(null); } var altFooter = false; var index = 1; var workloadLines = new List <string>(); var additionalDataBuilder = new StringBuilder(); while (index < strings.Length) { var current = strings[index]; var tag = string.Empty; var content = string.Empty; if (IsAdditionalHeader(current, out tag, out content)) { AddAdditionalHeader(tag, content); } else if (string.IsNullOrWhiteSpace(current)) { // ignore white lines } else if (!IsFooter(current, out altFooter)) { if (string.IsNullOrEmpty(FullFooter)) { workloadLines.Add(current); } else { additionalDataBuilder.AppendLine(current); } } else { FullFooter = current; } index++; } // All data was read, now go check consistency. if (altHeader != altFooter) { AddWarning(altHeader ? "PEM inconsistency: header uses the alternate form ('---- BEGIN') whereas footer does not ('-----END')." : "PEM inconsistency: header uses the normal form ('-----BEGIN') whereas footer does not ('---- END')."); } var header = ExtractHeader(FullHeader, altHeader); var footer = ExtractFooter(FullFooter, altFooter); if (header != footer) { AddWarning(string.Format( "PEM inconsistency: header ({0}) does not match footer ({1}).", header, footer)); } Kind = PemKind.Find(header); if (Kind == null) { AddWarning(string.Format("PEM header {0} is not a well-known PEM header.", header)); Kind = PemKind.GetCustom(header, "Not a well-known PEM header."); } // convert the lines list to a string builder. IEnumerable <string> lines = Kind.HasPgpChecksum ? // if PGP-like PEM, last line is a checksum, not part of the real workload Enumerable.Range(0, workloadLines.Count - 1).Select(i => workloadLines[i]) : workloadLines; var base64Builder = new StringBuilder(); foreach (var line in lines) { base64Builder.Append(line); } if (Kind.HasPgpChecksum) { try { // PGP Checksums starts with a '=' character var checksum = workloadLines[workloadLines.Count - 1]; checksum = checksum.TrimStart('='); PgpChecksum = Convert.FromBase64String(checksum); } catch (Exception ex) { AddWarning(string.Format("Could not decode PGP Checksum from input Base64 data: {0}", ex.Message)); } } try { Workload = Convert.FromBase64String(base64Builder.ToString()); } catch (Exception ex) { AddError(string.Format("Could not decode input Base64 data: {0}", ex.Message)); } // TODO: validates PGP checksums AdditionalText = additionalDataBuilder.ToString(); return(new PemInfo(this)); }