summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2014-08-27 18:22:21 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2014-08-27 18:22:21 +0700
commitd76f7c4d645aede7a2880ac1f59ed545f633e005 (patch)
treeb51cce31c02557a0231afd0d27085026dc3faa48
parentImprove sorting for SETs (diff)
downloadBouncyCastle.NET-ed25519-d76f7c4d645aede7a2880ac1f59ed545f633e005.tar.xz
Refactor redundant blocks
Support no-password operation (as best we can)
-rw-r--r--crypto/src/pkcs/Pkcs12Store.cs465
1 files changed, 169 insertions, 296 deletions
diff --git a/crypto/src/pkcs/Pkcs12Store.cs b/crypto/src/pkcs/Pkcs12Store.cs
index 40364eec7..e4fe29401 100644
--- a/crypto/src/pkcs/Pkcs12Store.cs
+++ b/crypto/src/pkcs/Pkcs12Store.cs
@@ -28,6 +28,8 @@ namespace Org.BouncyCastle.Pkcs
         private readonly DerObjectIdentifier	certAlgorithm;
         private readonly bool					useDerEncoding;
 
+        private AsymmetricKeyEntry unmarkedKeyEntry = null;
+
         private const int MinIterations = 1024;
         private const int SaltSize = 20;
 
@@ -107,22 +109,101 @@ namespace Org.BouncyCastle.Pkcs
             Load(input, password);
         }
 
+        protected virtual void LoadKeyBag(PrivateKeyInfo privKeyInfo, Asn1Set bagAttributes)
+        {
+            AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privKeyInfo);
+
+            IDictionary attributes = Platform.CreateHashtable();
+            AsymmetricKeyEntry keyEntry = new AsymmetricKeyEntry(privKey, attributes);
+
+            string alias = null;
+            Asn1OctetString localId = null;
+
+            if (bagAttributes != null)
+            {
+                foreach (Asn1Sequence sq in bagAttributes)
+                {
+                    DerObjectIdentifier aOid = DerObjectIdentifier.GetInstance(sq[0]);
+                    Asn1Set attrSet = Asn1Set.GetInstance(sq[1]);
+                    Asn1Encodable attr = null;
+
+                    if (attrSet.Count > 0)
+                    {
+                        // TODO We should be adding all attributes in the set
+                        attr = attrSet[0];
+
+                        // TODO We might want to "merge" attribute sets with
+                        // the same OID - currently, differing values give an error
+                        if (attributes.Contains(aOid.Id))
+                        {
+                            // OK, but the value has to be the same
+                            if (!attributes[aOid.Id].Equals(attr))
+                                throw new IOException("attempt to add existing attribute with different value");
+                        }
+                        else
+                        {
+                            attributes.Add(aOid.Id, attr);
+                        }
+
+                        if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
+                        {
+                            alias = ((DerBmpString)attr).GetString();
+                            // TODO Do these in a separate loop, just collect aliases here
+                            keys[alias] = keyEntry;
+                        }
+                        else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
+                        {
+                            localId = (Asn1OctetString)attr;
+                        }
+                    }
+                }
+            }
+
+            if (localId != null)
+            {
+                string name = Hex.ToHexString(localId.GetOctets());
+
+                if (alias == null)
+                {
+                    keys[name] = keyEntry;
+                }
+                else
+                {
+                    // TODO There may have been more than one alias
+                    localIds[alias] = name;
+                }
+            }
+            else
+            {
+                unmarkedKeyEntry = keyEntry;
+            }
+        }
+
+        protected virtual void LoadPkcs8ShroudedKeyBag(EncryptedPrivateKeyInfo encPrivKeyInfo, Asn1Set bagAttributes,
+            char[] password, bool wrongPkcs12Zero)
+        {
+            if (password != null)
+            {
+                PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(
+                    password, wrongPkcs12Zero, encPrivKeyInfo);
+
+                LoadKeyBag(privInfo, bagAttributes);
+            }
+        }
+
         public void Load(
             Stream	input,
             char[]	password)
         {
             if (input == null)
                 throw new ArgumentNullException("input");
-            if (password == null)
-                throw new ArgumentNullException("password");
 
             Asn1Sequence obj = (Asn1Sequence) Asn1Object.FromStream(input);
             Pfx bag = new Pfx(obj);
             ContentInfo info = bag.AuthSafe;
-            bool unmarkedKey = false;
             bool wrongPkcs12Zero = false;
 
-            if (bag.MacData != null) // check the mac code
+            if (password != null && bag.MacData != null) // check the mac code
             {
                 MacData mData = bag.MacData;
                 DigestInfo dInfo = mData.Mac;
@@ -152,8 +233,9 @@ namespace Org.BouncyCastle.Pkcs
 
             keys.Clear();
             localIds.Clear();
+            unmarkedKeyEntry = null;
 
-            IList chain = Platform.CreateArrayList();
+            IList certBags = Platform.CreateArrayList();
 
             if (info.ContentType.Equals(PkcsObjectIdentifiers.Data))
             {
@@ -166,109 +248,28 @@ namespace Org.BouncyCastle.Pkcs
                 {
                     DerObjectIdentifier oid = ci.ContentType;
 
+                    byte[] octets = null;
                     if (oid.Equals(PkcsObjectIdentifiers.Data))
                     {
-                        byte[] octets = ((Asn1OctetString)ci.Content).GetOctets();
-                        Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(octets);
-
-                        foreach (Asn1Sequence subSeq in seq)
+                        octets = ((Asn1OctetString)ci.Content).GetOctets();
+                    }
+                    else if (oid.Equals(PkcsObjectIdentifiers.EncryptedData))
+                    {
+                        if (password != null)
                         {
-                            SafeBag b = new SafeBag(subSeq);
-
-                            if (b.BagID.Equals(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag))
-                            {
-                                EncryptedPrivateKeyInfo eIn = EncryptedPrivateKeyInfo.GetInstance(b.BagValue);
-                                PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(
-                                    password, wrongPkcs12Zero, eIn);
-                                AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privInfo);
-
-                                //
-                                // set the attributes on the key
-                                //
-                                IDictionary attributes = Platform.CreateHashtable();
-                                AsymmetricKeyEntry pkcs12Key = new AsymmetricKeyEntry(privKey, attributes);
-                                string alias = null;
-                                Asn1OctetString localId = null;
-
-                                if (b.BagAttributes != null)
-                                {
-                                    foreach (Asn1Sequence sq in b.BagAttributes)
-                                    {
-                                        DerObjectIdentifier aOid = (DerObjectIdentifier) sq[0];
-                                        Asn1Set attrSet = (Asn1Set) sq[1];
-                                        Asn1Encodable attr = null;
-
-                                        if (attrSet.Count > 0)
-                                        {
-                                            // TODO We should be adding all attributes in the set
-                                            attr = attrSet[0];
-
-                                            // TODO We might want to "merge" attribute sets with
-                                            // the same OID - currently, differing values give an error
-                                            if (attributes.Contains(aOid.Id))
-                                            {
-                                                // OK, but the value has to be the same
-                                                if (!attributes[aOid.Id].Equals(attr))
-                                                {
-                                                    throw new IOException("attempt to add existing attribute with different value");
-                                                }
-                                            }
-                                            else
-                                            {
-                                                attributes.Add(aOid.Id, attr);
-                                            }
-
-                                            if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
-                                            {
-                                                alias = ((DerBmpString)attr).GetString();
-                                                // TODO Do these in a separate loop, just collect aliases here
-                                                keys[alias] = pkcs12Key;
-                                            }
-                                            else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
-                                            {
-                                                localId = (Asn1OctetString)attr;
-                                            }
-                                        }
-                                    }
-                                }
-
-                                if (localId != null)
-                                {
-                                    string name = Hex.ToHexString(localId.GetOctets());
-
-                                    if (alias == null)
-                                    {
-                                        keys[name] = pkcs12Key;
-                                    }
-                                    else
-                                    {
-                                        // TODO There may have been more than one alias
-                                        localIds[alias] = name;
-                                    }
-                                }
-                                else
-                                {
-                                    unmarkedKey = true;
-                                    keys["unmarked"] = pkcs12Key;
-                                }
-                            }
-                            else if (b.BagID.Equals(PkcsObjectIdentifiers.CertBag))
-                            {
-                                chain.Add(b);
-                            }
-                            else
-                            {
-                                Console.WriteLine("extra " + b.BagID);
-                                Console.WriteLine("extra " + Asn1Dump.DumpAsString(b));
-                            }
+                            EncryptedData d = EncryptedData.GetInstance(ci.Content);
+                            octets = CryptPbeData(false, d.EncryptionAlgorithm,
+                                password, wrongPkcs12Zero, d.Content.GetOctets());
                         }
                     }
-                    else if (oid.Equals(PkcsObjectIdentifiers.EncryptedData))
+                    else
+                    {
+                        // TODO Other data types
+                    }
+
+                    if (octets != null)
                     {
-                        EncryptedData d = EncryptedData.GetInstance(ci.Content);
-                        byte[] octets = CryptPbeData(false, d.EncryptionAlgorithm,
-                            password, wrongPkcs12Zero, d.Content.GetOctets());
-                        Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(octets);
+                        Asn1Sequence seq = (Asn1Sequence)Asn1Object.FromByteArray(octets);
 
                         foreach (Asn1Sequence subSeq in seq)
                         {
@@ -276,156 +277,23 @@ namespace Org.BouncyCastle.Pkcs
 
                             if (b.BagID.Equals(PkcsObjectIdentifiers.CertBag))
                             {
-                                chain.Add(b);
+                                certBags.Add(b);
                             }
                             else if (b.BagID.Equals(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag))
                             {
-                                EncryptedPrivateKeyInfo eIn = EncryptedPrivateKeyInfo.GetInstance(b.BagValue);
-                                PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(
-                                    password, wrongPkcs12Zero, eIn);
-                                AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privInfo);
-
-                                //
-                                // set the attributes on the key
-                                //
-                                IDictionary attributes = Platform.CreateHashtable();
-                                AsymmetricKeyEntry pkcs12Key = new AsymmetricKeyEntry(privKey, attributes);
-                                string alias = null;
-                                Asn1OctetString localId = null;
-
-                                foreach (Asn1Sequence sq in b.BagAttributes)
-                                {
-                                    DerObjectIdentifier aOid = (DerObjectIdentifier) sq[0];
-                                    Asn1Set attrSet = (Asn1Set) sq[1];
-                                    Asn1Encodable attr = null;
-
-                                    if (attrSet.Count > 0)
-                                    {
-                                        // TODO We should be adding all attributes in the set
-                                        attr = attrSet[0];
-
-                                        // TODO We might want to "merge" attribute sets with
-                                        // the same OID - currently, differing values give an error
-                                        if (attributes.Contains(aOid.Id))
-                                        {
-                                            // OK, but the value has to be the same
-                                            if (!attributes[aOid.Id].Equals(attr))
-                                            {
-                                                throw new IOException("attempt to add existing attribute with different value");
-                                            }
-                                        }
-                                        else
-                                        {
-                                            attributes.Add(aOid.Id, attr);
-                                        }
-
-                                        if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
-                                        {
-                                            alias = ((DerBmpString)attr).GetString();
-                                            // TODO Do these in a separate loop, just collect aliases here
-                                            keys[alias] = pkcs12Key;
-                                        }
-                                        else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
-                                        {
-                                            localId = (Asn1OctetString)attr;
-                                        }
-                                    }
-                                }
-
-                                // TODO Should we be checking localIds != null here
-                                // as for PkcsObjectIdentifiers.Data version above?
-
-                                string name = Hex.ToHexString(localId.GetOctets());
-
-                                if (alias == null)
-                                {
-                                    keys[name] = pkcs12Key;
-                                }
-                                else
-                                {
-                                    // TODO There may have been more than one alias
-                                    localIds[alias] = name;
-                                }
+                                LoadPkcs8ShroudedKeyBag(EncryptedPrivateKeyInfo.GetInstance(b.BagValue),
+                                    b.BagAttributes, password, wrongPkcs12Zero);
                             }
                             else if (b.BagID.Equals(PkcsObjectIdentifiers.KeyBag))
                             {
-                                PrivateKeyInfo privKeyInfo = PrivateKeyInfo.GetInstance(b.BagValue);
-                                AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privKeyInfo);
-
-                                //
-                                // set the attributes on the key
-                                //
-                                string alias = null;
-                                Asn1OctetString localId = null;
-                                IDictionary attributes = Platform.CreateHashtable();
-                                AsymmetricKeyEntry pkcs12Key = new AsymmetricKeyEntry(privKey, attributes);
-
-                                foreach (Asn1Sequence sq in b.BagAttributes)
-                                {
-                                    DerObjectIdentifier aOid = DerObjectIdentifier.GetInstance(sq[0]);
-                                    Asn1Set attrSet = Asn1Set.GetInstance(sq[1]);
-                                    Asn1Encodable attr = null;
-
-                                    if (attrSet.Count > 0)
-                                    {
-                                        // TODO We should be adding all attributes in the set
-                                        attr = attrSet[0];
-
-                                        // TODO We might want to "merge" attribute sets with
-                                        // the same OID - currently, differing values give an error
-                                        if (attributes.Contains(aOid.Id))
-                                        {
-                                            // OK, but the value has to be the same
-                                            if (!attributes[aOid.Id].Equals(attr))
-                                            {
-                                                throw new IOException("attempt to add existing attribute with different value");
-                                            }
-                                        }
-                                        else
-                                        {
-                                            attributes.Add(aOid.Id, attr);
-                                        }
-
-                                        if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
-                                        {
-                                            alias = ((DerBmpString)attr).GetString();
-                                            // TODO Do these in a separate loop, just collect aliases here
-                                            keys[alias] = pkcs12Key;
-                                        }
-                                        else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
-                                        {
-                                            localId = (Asn1OctetString)attr;
-                                        }
-                                    }
-                                }
-
-                                // TODO Should we be checking localIds != null here
-                                // as for PkcsObjectIdentifiers.Data version above?
-
-                                string name = Hex.ToHexString(localId.GetOctets());
-
-                                if (alias == null)
-                                {
-                                    keys[name] = pkcs12Key;
-                                }
-                                else
-                                {
-                                    // TODO There may have been more than one alias
-                                    localIds[alias] = name;
-                                }
+                                LoadKeyBag(PrivateKeyInfo.GetInstance(b.BagValue), b.BagAttributes);
                             }
                             else
                             {
-                                Console.WriteLine("extra " + b.BagID);
-                                Console.WriteLine("extra " + Asn1Dump.DumpAsString(b));
+                                // TODO Other bag types
                             }
                         }
                     }
-                    else
-                    {
-                        Console.WriteLine("extra " + oid);
-                        Console.WriteLine("extra " + Asn1Dump.DumpAsString(ci.Content));
-                    }
                 }
             }
 
@@ -433,10 +301,10 @@ namespace Org.BouncyCastle.Pkcs
             chainCerts.Clear();
             keyCerts.Clear();
 
-            foreach (SafeBag b in chain)
+            foreach (SafeBag b in certBags)
             {
-                CertBag cb = new CertBag((Asn1Sequence)b.BagValue);
-                byte[] octets = ((Asn1OctetString) cb.CertValue).GetOctets();
+                CertBag certBag = new CertBag((Asn1Sequence)b.BagValue);
+                byte[] octets = ((Asn1OctetString)certBag.CertValue).GetOctets();
                 X509Certificate cert = new X509CertificateParser().ReadCertificate(octets);
 
                 //
@@ -486,21 +354,18 @@ namespace Org.BouncyCastle.Pkcs
                 }
 
                 CertId certId = new CertId(cert.GetPublicKey());
-                X509CertificateEntry pkcs12Cert = new X509CertificateEntry(cert, attributes);
+                X509CertificateEntry certEntry = new X509CertificateEntry(cert, attributes);
 
-                chainCerts[certId] = pkcs12Cert;
+                chainCerts[certId] = certEntry;
 
-                if (unmarkedKey)
+                if (unmarkedKeyEntry != null)
                 {
                     if (keyCerts.Count == 0)
                     {
                         string name = Hex.ToHexString(certId.Id);
 
-                        keyCerts[name] = pkcs12Cert;
-
-                        object temp = keys["unmarked"];
-                        keys.Remove("unmarked");
-                        keys[name] = temp;
+                        keyCerts[name] = certEntry;
+                        keys[name] = unmarkedKeyEntry;
                     }
                 }
                 else
@@ -509,13 +374,13 @@ namespace Org.BouncyCastle.Pkcs
                     {
                         string name = Hex.ToHexString(localId.GetOctets());
 
-                        keyCerts[name] = pkcs12Cert;
+                        keyCerts[name] = certEntry;
                     }
 
                     if (alias != null)
                     {
                         // TODO There may have been more than one alias
-                        certs[alias] = pkcs12Cert;
+                        certs[alias] = certEntry;
                     }
                 }
             }
@@ -841,24 +706,34 @@ namespace Org.BouncyCastle.Pkcs
         {
             if (stream == null)
                 throw new ArgumentNullException("stream");
-            if (password == null)
-                throw new ArgumentNullException("password");
             if (random == null)
                 throw new ArgumentNullException("random");
 
             //
-            // handle the key
+            // handle the keys
             //
-            Asn1EncodableVector keyS = new Asn1EncodableVector();
+            Asn1EncodableVector keyBags = new Asn1EncodableVector();
             foreach (string name in keys.Keys)
             {
                 byte[] kSalt = new byte[SaltSize];
                 random.NextBytes(kSalt);
 
-                AsymmetricKeyEntry privKey = (AsymmetricKeyEntry) keys[name];
-                EncryptedPrivateKeyInfo kInfo =
-                    EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
-                    keyAlgorithm, password, kSalt, MinIterations, privKey.Key);
+                AsymmetricKeyEntry privKey = (AsymmetricKeyEntry)keys[name];
+
+                DerObjectIdentifier bagOid;
+                Asn1Encodable bagData;
+
+                if (password == null)
+                {
+                    bagOid = PkcsObjectIdentifiers.KeyBag;
+                    bagData = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privKey.Key);
+                }
+                else
+                {
+                    bagOid = PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag;
+                    bagData = EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
+                        keyAlgorithm, password, kSalt, MinIterations, privKey.Key);
+                }
 
                 Asn1EncodableVector kName = new Asn1EncodableVector();
 
@@ -903,13 +778,11 @@ namespace Org.BouncyCastle.Pkcs
                             new DerSet(subjectKeyID)));
                 }
 
-                SafeBag kBag = new SafeBag(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag, kInfo.ToAsn1Object(), new DerSet(kName));
-                keyS.Add(kBag);
+                keyBags.Add(new SafeBag(bagOid, bagData.ToAsn1Object(), new DerSet(kName)));
             }
 
-            byte[] derEncodedBytes = new DerSequence(keyS).GetDerEncoded();
-
-            BerOctetString keyString = new BerOctetString(derEncodedBytes);
+            byte[] keyBagsEncoding = new DerSequence(keyBags).GetDerEncoded();
+            ContentInfo keysInfo = new ContentInfo(PkcsObjectIdentifiers.Data, new BerOctetString(keyBagsEncoding));
 
             //
             // certificate processing
@@ -918,7 +791,7 @@ namespace Org.BouncyCastle.Pkcs
 
             random.NextBytes(cSalt);
 
-            Asn1EncodableVector	certSeq = new Asn1EncodableVector();
+            Asn1EncodableVector	certBags = new Asn1EncodableVector();
             Pkcs12PbeParams		cParams = new Pkcs12PbeParams(cSalt, MinIterations);
             AlgorithmIdentifier	cAlgId = new AlgorithmIdentifier(certAlgorithm, cParams.ToAsn1Object());
             ISet				doneCerts = new HashSet();
@@ -972,10 +845,7 @@ namespace Org.BouncyCastle.Pkcs
                             new DerSet(subjectKeyID)));
                 }
 
-                SafeBag sBag = new SafeBag(
-                    PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName));
-
-                certSeq.Add(sBag);
+                certBags.Add(new SafeBag(PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName)));
 
                 doneCerts.Add(certEntry.Certificate);
             }
@@ -1026,10 +896,7 @@ namespace Org.BouncyCastle.Pkcs
                             new DerSet(new DerBmpString(certId))));
                 }
 
-                SafeBag sBag = new SafeBag(PkcsObjectIdentifiers.CertBag,
-                    cBag.ToAsn1Object(), new DerSet(fName));
-
-                certSeq.Add(sBag);
+                certBags.Add(new SafeBag(PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName)));
 
                 doneCerts.Add(cert.Certificate);
             }
@@ -1062,22 +929,24 @@ namespace Org.BouncyCastle.Pkcs
                             new DerSet(cert[oid])));
                 }
 
-                SafeBag sBag = new SafeBag(PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName));
-
-                certSeq.Add(sBag);
+                certBags.Add(new SafeBag(PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName)));
             }
 
-            derEncodedBytes = new DerSequence(certSeq).GetDerEncoded();
-
-            byte[] certBytes = CryptPbeData(true, cAlgId, password, false, derEncodedBytes);
+            byte[] certBagsEncoding = new DerSequence(certBags).GetDerEncoded();
 
-            EncryptedData cInfo = new EncryptedData(PkcsObjectIdentifiers.Data, cAlgId, new BerOctetString(certBytes));
-
-            ContentInfo[] info = new ContentInfo[]
+            ContentInfo certsInfo;
+            if (password == null)
             {
-                new ContentInfo(PkcsObjectIdentifiers.Data, keyString),
-                new ContentInfo(PkcsObjectIdentifiers.EncryptedData, cInfo.ToAsn1Object())
-            };
+                certsInfo = new ContentInfo(PkcsObjectIdentifiers.Data, new BerOctetString(certBagsEncoding));
+            }
+            else
+            {
+                byte[] certBytes = CryptPbeData(true, cAlgId, password, false, certBagsEncoding);
+                EncryptedData cInfo = new EncryptedData(PkcsObjectIdentifiers.Data, cAlgId, new BerOctetString(certBytes));
+                certsInfo = new ContentInfo(PkcsObjectIdentifiers.EncryptedData, cInfo.ToAsn1Object());
+            }
+
+            ContentInfo[] info = new ContentInfo[]{ keysInfo, certsInfo };
 
             byte[] data = new AuthenticatedSafe(info).GetEncoded(
                 useDerEncoding ? Asn1Encodable.Der : Asn1Encodable.Ber);
@@ -1087,22 +956,26 @@ namespace Org.BouncyCastle.Pkcs
             //
             // create the mac
             //
-            byte[] mSalt = new byte[20];
-            random.NextBytes(mSalt);
+            MacData macData = null;
+            if (password != null)
+            {
+                byte[] mSalt = new byte[20];
+                random.NextBytes(mSalt);
 
-            byte[] mac = CalculatePbeMac(OiwObjectIdentifiers.IdSha1,
-                mSalt, MinIterations, password, false, data);
+                byte[] mac = CalculatePbeMac(OiwObjectIdentifiers.IdSha1,
+                    mSalt, MinIterations, password, false, data);
 
-            AlgorithmIdentifier algId = new AlgorithmIdentifier(
-                OiwObjectIdentifiers.IdSha1, DerNull.Instance);
-            DigestInfo dInfo = new DigestInfo(algId, mac);
+                AlgorithmIdentifier algId = new AlgorithmIdentifier(
+                    OiwObjectIdentifiers.IdSha1, DerNull.Instance);
+                DigestInfo dInfo = new DigestInfo(algId, mac);
 
-            MacData mData = new MacData(dInfo, mSalt, MinIterations);
+                macData = new MacData(dInfo, mSalt, MinIterations);
+            }
 
             //
             // output the Pfx
             //
-            Pfx pfx = new Pfx(mainInfo, mData);
+            Pfx pfx = new Pfx(mainInfo, macData);
 
             DerOutputStream derOut;
             if (useDerEncoding)