diff --git a/crypto/src/pkcs/PKCS12StoreBuilder.cs b/crypto/src/pkcs/PKCS12StoreBuilder.cs index ad90dc5a7..977bd5c05 100644 --- a/crypto/src/pkcs/PKCS12StoreBuilder.cs +++ b/crypto/src/pkcs/PKCS12StoreBuilder.cs @@ -3,6 +3,10 @@ namespace Org.BouncyCastle.Pkcs { + /// + /// Fluent builder for instances, configuring PBE algorithms and + /// encoding options used when saving PKCS#12 files (RFC 7292). + /// // TODO[api] Make sealed public class Pkcs12StoreBuilder { @@ -19,16 +23,26 @@ public class Pkcs12StoreBuilder private bool overwriteFriendlyName = true; private bool enableOracleTrustedKeyUsage = true; + /// Creates a builder with library-default PBE algorithms and options. public Pkcs12StoreBuilder() { } + /// + /// Builds a new using the configured algorithms and options. + /// + /// A new, empty PKCS#12 store. public Pkcs12Store Build() { return new Pkcs12Store(certAlgorithm, certPrfAlgorithm, keyAlgorithm, keyPrfAlgorithm, useDerEncoding, reverseCertificates, overwriteFriendlyName, enableOracleTrustedKeyUsage); } + /// + /// Sets the PBE algorithm used to encrypt certificate bags when saving (PKCS#12 scheme 1). + /// + /// The certificate encryption algorithm OID. + /// This builder instance. public Pkcs12StoreBuilder SetCertAlgorithm(DerObjectIdentifier certAlgorithm) { this.certAlgorithm = certAlgorithm; @@ -36,8 +50,14 @@ public Pkcs12StoreBuilder SetCertAlgorithm(DerObjectIdentifier certAlgorithm) return this; } - // Specify a PKCS#5 Scheme 2 encryption for certs - public Pkcs12StoreBuilder SetCertAlgorithm(DerObjectIdentifier certAlgorithm, DerObjectIdentifier certPrfAlgorithm) + /// + /// Sets the PBES2 algorithm and PRF used to encrypt certificate bags when saving (PKCS#12 scheme 2). + /// + /// The certificate encryption algorithm OID. + /// The PRF algorithm OID. + /// This builder instance. + public Pkcs12StoreBuilder SetCertAlgorithm(DerObjectIdentifier certAlgorithm, + DerObjectIdentifier certPrfAlgorithm) { this.certAlgorithm = certAlgorithm; this.certPrfAlgorithm = certPrfAlgorithm; @@ -48,14 +68,19 @@ public Pkcs12StoreBuilder SetCertAlgorithm(DerObjectIdentifier certAlgorithm, De /// Whether to include Oracle's TrustedKeyUsage attribute in CertBag attributes. Defaults to true. /// /// The OID 2.16.840.1.113894.746875.1.1 is used for this attribute. - /// - /// + /// true to emit the attribute when saving. + /// This builder instance. public Pkcs12StoreBuilder SetEnableOracleTrustedKeyUsage(bool enableOracleTrustedKeyUsage) { this.enableOracleTrustedKeyUsage = enableOracleTrustedKeyUsage; return this; } + /// + /// Sets the PBE algorithm used to encrypt private-key bags when saving (PKCS#12 scheme 1). + /// + /// The key encryption algorithm OID. + /// This builder instance. public Pkcs12StoreBuilder SetKeyAlgorithm(DerObjectIdentifier keyAlgorithm) { this.keyAlgorithm = keyAlgorithm; @@ -63,26 +88,48 @@ public Pkcs12StoreBuilder SetKeyAlgorithm(DerObjectIdentifier keyAlgorithm) return this; } - // Specify a PKCS#5 Scheme 2 encryption for keys - public Pkcs12StoreBuilder SetKeyAlgorithm(DerObjectIdentifier keyAlgorithm, DerObjectIdentifier keyPrfAlgorithm) + /// + /// Sets the PBES2 algorithm and PRF used to encrypt private-key bags when saving (PKCS#12 scheme 2). + /// + /// The key encryption algorithm OID. + /// The PRF algorithm OID. + /// This builder instance. + public Pkcs12StoreBuilder SetKeyAlgorithm(DerObjectIdentifier keyAlgorithm, + DerObjectIdentifier keyPrfAlgorithm) { this.keyAlgorithm = keyAlgorithm; this.keyPrfAlgorithm = keyPrfAlgorithm; return this; } + /// + /// Controls whether may replace an existing friendly name. + /// Defaults to true. + /// + /// true to allow overwriting friendly names. + /// This builder instance. public Pkcs12StoreBuilder SetOverwriteFriendlyName(bool overwriteFriendlyName) { this.overwriteFriendlyName = overwriteFriendlyName; return this; } + /// + /// When true, certificate and key bags are written in reverse insertion order when saving. + /// + /// true to reverse bag order on save. + /// This builder instance. public Pkcs12StoreBuilder SetReverseCertificates(bool reverseCertificates) { this.reverseCertificates = reverseCertificates; return this; } + /// + /// When true, saved PKCS#12 structures use DER encoding instead of BER for inner content. + /// + /// true for definite-length DER encoding. + /// This builder instance. public Pkcs12StoreBuilder SetUseDerEncoding(bool useDerEncoding) { this.useDerEncoding = useDerEncoding; diff --git a/crypto/src/pkcs/Pkcs12Entry.cs b/crypto/src/pkcs/Pkcs12Entry.cs index 5e1a0ee83..2a936dc1f 100644 --- a/crypto/src/pkcs/Pkcs12Entry.cs +++ b/crypto/src/pkcs/Pkcs12Entry.cs @@ -6,6 +6,10 @@ namespace Org.BouncyCastle.Pkcs { + /// + /// Base class for PKCS#12 bag entries (private keys and certificates) carrying optional + /// PKCS#9 bag attributes such as friendly name and local key identifier. + /// public abstract class Pkcs12Entry { private readonly IDictionary m_attributes; @@ -17,17 +21,35 @@ protected internal Pkcs12Entry(IDictionary a m_attributes = attributes; } + /// + /// Gets the bag attribute value for the given object identifier, or null if absent. + /// + /// The bag attribute OID. public Asn1Encodable this[DerObjectIdentifier oid] => CollectionUtilities.GetValueOrNull(m_attributes, oid); + /// Gets the object identifiers of all bag attributes on this entry. public IEnumerable BagAttributeKeys => CollectionUtilities.Proxy(m_attributes.Keys); + /// + /// Returns true if this entry has a PKCS#9 friendly name attribute. + /// public bool HasFriendlyName => m_attributes.ContainsKey(PkcsObjectIdentifiers.Pkcs9AtFriendlyName); + /// + /// Sets or replaces the PKCS#9 friendly name bag attribute on this entry. + /// + /// The friendly name to store. public void SetFriendlyName(string friendlyName) { m_attributes[PkcsObjectIdentifiers.Pkcs9AtFriendlyName] = new DerBmpString(friendlyName); } + /// + /// Attempts to retrieve a bag attribute by OID. + /// + /// The bag attribute OID. + /// The attribute value, if present. + /// true if the attribute was found. public bool TryGetAttribute(DerObjectIdentifier oid, out Asn1Encodable attribute) => m_attributes.TryGetValue(oid, out attribute); } diff --git a/crypto/src/pkcs/Pkcs12Store.cs b/crypto/src/pkcs/Pkcs12Store.cs index 7bfa8a073..b546ce640 100644 --- a/crypto/src/pkcs/Pkcs12Store.cs +++ b/crypto/src/pkcs/Pkcs12Store.cs @@ -18,8 +18,16 @@ namespace Org.BouncyCastle.Pkcs { + /// + /// In-memory PKCS#12 keystore (PFX) as defined in RFC 7292. Loads and saves password-protected bags of + /// private keys and X.509 certificates. Create instances via . + /// public class Pkcs12Store { + /// + /// Environment variable that, when set to true, suppresses the error raised when + /// is called with a password but the file does not require one. + /// public const string IgnoreUselessPasswordProperty = "Org.BouncyCastle.Pkcs12.IgnoreUselessPassword"; private readonly Dictionary m_keys = @@ -174,6 +182,21 @@ protected virtual void LoadPkcs8ShroudedKeyBag(EncryptedPrivateKeyInfo encPrivKe LoadKeyBag(privateKeyInfo, bagAttributes); } + /// + /// Loads a PKCS#12 file from a stream, populating this store with keys and certificates. + /// + /// The stream containing the PKCS#12 PFX structure. + /// + /// The password used to verify the MAC and decrypt shrouded key bags, or null if none is required. + /// + /// + /// is null, or a password is required but is + /// null. + /// + /// + /// The MAC verification failed, a password was supplied when none is required (unless + /// is set), or bag attributes conflict. + /// public void Load(Stream input, char[] password) { if (input == null) @@ -387,6 +410,11 @@ public void Load(Stream input, char[] password) } } + /// + /// Returns the private-key entry for the given alias, or null if not present. + /// + /// The entry alias (friendly name or local key id hex string). + /// is null. public AsymmetricKeyEntry GetKey(string alias) { if (alias == null) @@ -395,6 +423,11 @@ public AsymmetricKeyEntry GetKey(string alias) return CollectionUtilities.GetValueOrNull(m_keys, alias); } + /// + /// Returns true if the alias refers to a certificate-only entry (no private key). + /// + /// The entry alias. + /// is null. public bool IsCertificateEntry(string alias) { if (alias == null) @@ -403,6 +436,11 @@ public bool IsCertificateEntry(string alias) return m_certs.ContainsKey(alias) && !m_keys.ContainsKey(alias); } + /// + /// Returns true if the alias refers to a private-key entry. + /// + /// The entry alias. + /// is null. public bool IsKeyEntry(string alias) { if (alias == null) @@ -411,6 +449,7 @@ public bool IsKeyEntry(string alias) return m_keys.ContainsKey(alias); } + /// Gets all aliases in this store (union of certificate and key aliases). public IEnumerable Aliases { get @@ -421,6 +460,11 @@ public IEnumerable Aliases } } + /// + /// Returns true if an entry exists under the given alias. + /// + /// The entry alias. + /// is null. public bool ContainsAlias(string alias) { if (alias == null) @@ -429,9 +473,13 @@ public bool ContainsAlias(string alias) return m_certs.ContainsKey(alias) || m_keys.ContainsKey(alias); } - /** - * simply return the cert entry for the private key - */ + /// + /// Returns the certificate entry for the alias — either a certificate-only entry or the end-entity + /// certificate associated with a private-key alias. + /// + /// The entry alias. + /// The certificate entry, or null if not found. + /// is null. public X509CertificateEntry GetCertificate(string alias) { if (alias == null) @@ -449,6 +497,12 @@ public X509CertificateEntry GetCertificate(string alias) return CollectionUtilities.GetValueOrNull(m_keyCerts, keyCertsKey); } + /// + /// Finds the alias of the first entry whose certificate equals . + /// + /// The certificate to search for. + /// The alias, or null if not found. + /// is null. public string GetCertificateAlias(X509Certificate cert) { if (cert == null) @@ -470,6 +524,13 @@ public string GetCertificateAlias(X509Certificate cert) return null; } + /// + /// Builds the certificate chain for a private-key alias by following Authority Key Identifier + /// or issuer/subject matching. + /// + /// The private-key alias. + /// The chain from end entity to root, or null if the alias is not a key entry. + /// is null. public X509CertificateEntry[] GetCertificateChain(string alias) { if (alias == null) @@ -545,6 +606,17 @@ public X509CertificateEntry[] GetCertificateChain(string alias) return cs.ToArray(); } + /// + /// Adds or replaces a certificate-only entry under the given alias. + /// + /// The entry alias. + /// The certificate entry to store. + /// + /// or is null. + /// + /// + /// A private-key entry already exists under . + /// public void SetCertificateEntry(string alias, X509CertificateEntry certEntry) { if (alias == null) @@ -558,6 +630,14 @@ public void SetCertificateEntry(string alias, X509CertificateEntry certEntry) Map(m_chainCerts, m_chainCertsOrder, new CertID(certEntry), certEntry); } + /// + /// Renames an entry by updating its PKCS#9 friendly name and re-keying internal maps. + /// + /// The current alias. + /// The new friendly name. + /// + /// or is null. + /// public void SetFriendlyName(string alias, string newFriendlyName) { if (alias == null) @@ -601,6 +681,20 @@ public void SetFriendlyName(string alias, string newFriendlyName) } } + /// + /// Adds or replaces a private-key entry and optional certificate chain under the given alias. + /// + /// The entry alias. + /// The private-key entry. + /// + /// The certificate chain for the key (required when holds a private key). + /// + /// + /// or is null. + /// + /// + /// A private key was supplied without a certificate chain. + /// public void SetKeyEntry(string alias, AsymmetricKeyEntry keyEntry, X509CertificateEntry[] chain) { if (alias == null) @@ -630,6 +724,9 @@ public void SetKeyEntry(string alias, AsymmetricKeyEntry keyEntry, X509Certifica } } + /// Removes the entry (certificate and/or key) for the given alias. + /// The entry alias. + /// is null. public void DeleteEntry(string alias) { if (alias == null) @@ -664,6 +761,11 @@ private void DeleteKeysEntry(string alias) } } + /// + /// Returns true if the alias refers to an entry assignable to . + /// + /// The entry alias. + /// or . public bool IsEntryOfType(string alias, Type entryType) { if (entryType == typeof(X509CertificateEntry)) @@ -675,6 +777,7 @@ public bool IsEntryOfType(string alias, Type entryType) return false; } + /// Gets the number of distinct aliases in this store. public int Count { get @@ -693,6 +796,17 @@ public int Count } } + /// + /// Writes this store as a PKCS#12 PFX structure to a stream. + /// + /// The output stream. + /// + /// The password used to encrypt shrouded key bags and the integrity MAC, or null for unencrypted keys. + /// + /// Randomness source for salts and IVs. + /// + /// or is null. + /// public void Save(Stream stream, char[] password, SecureRandom random) { if (stream == null)