diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2014-08-27 18:22:21 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2014-08-27 18:22:21 +0700 |
commit | d76f7c4d645aede7a2880ac1f59ed545f633e005 (patch) | |
tree | b51cce31c02557a0231afd0d27085026dc3faa48 /crypto/src/pkcs | |
parent | Improve sorting for SETs (diff) | |
download | BouncyCastle.NET-ed25519-d76f7c4d645aede7a2880ac1f59ed545f633e005.tar.xz |
Refactor redundant blocks
Support no-password operation (as best we can)
Diffstat (limited to 'crypto/src/pkcs')
-rw-r--r-- | crypto/src/pkcs/Pkcs12Store.cs | 465 |
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) |