public void Save(
Stream stream,
char[] password,
SecureRandom random)
{
if (stream == null)
throw new ArgumentNullException("stream");
if (password == null)
throw new ArgumentNullException("password");
if (random == null)
throw new ArgumentNullException("random");
ContentInfo[] c = new ContentInfo[2];
//
// handle the key
//
Asn1EncodableVector keyS = 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);
Asn1EncodableVector kName = new Asn1EncodableVector();
foreach (string oid in privKey.BagAttributeKeys)
{
kName.Add(
new DerSequence(
new DerObjectIdentifier(oid),
new DerSet(privKey[oid])));
}
//
// make sure we have a local key-id
//
if (privKey[PkcsObjectIdentifiers.Pkcs9AtLocalKeyID] == null)
{
X509CertificateEntry ct = GetCertificate(name);
SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(
ct.Certificate.GetPublicKey());
kName.Add(
new DerSequence(
PkcsObjectIdentifiers.Pkcs9AtLocalKeyID,
new DerSet(new SubjectKeyIdentifier(info))));
}
//
// make sure we are using the local alias on store
//
DerBmpString nm = (DerBmpString) privKey[PkcsObjectIdentifiers.Pkcs9AtFriendlyName];
if (nm == null || !nm.GetString().Equals(name))
{
kName.Add(
new DerSequence(
PkcsObjectIdentifiers.Pkcs9AtFriendlyName,
new DerSet(new DerBmpString(name))));
}
SafeBag kBag = new SafeBag(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag, kInfo.ToAsn1Object(), new DerSet(kName));
keyS.Add(kBag);
}
byte[] derEncodedBytes = new DerSequence(keyS).GetDerEncoded();
BerOctetString keyString = new BerOctetString(derEncodedBytes);
//
// certificate processing
//
byte[] cSalt = new byte[saltSize];
random.NextBytes(cSalt);
Asn1EncodableVector certSeq = new Asn1EncodableVector();
Pkcs12PbeParams cParams = new Pkcs12PbeParams(cSalt, minIterations);
AlgorithmIdentifier cAlgId = new AlgorithmIdentifier(certAlgorithm, cParams.ToAsn1Object());
Hashtable doneCerts = new Hashtable();
foreach (string name in keys.Keys)
{
X509CertificateEntry certEntry = GetCertificate(name);
CertBag cBag = new CertBag(
PkcsObjectIdentifiers.X509CertType,
new DerOctetString(certEntry.Certificate.GetEncoded()));
Asn1EncodableVector fName = new Asn1EncodableVector();
foreach (string oid in certEntry.BagAttributeKeys)
{
fName.Add(
new DerSequence(
new DerObjectIdentifier(oid),
new DerSet(certEntry[oid])));
}
//
// make sure we are using the local alias on store
//
DerBmpString nm = (DerBmpString)certEntry[PkcsObjectIdentifiers.Pkcs9AtFriendlyName];
if (nm == null || !nm.GetString().Equals(name))
{
fName.Add(
new DerSequence(
PkcsObjectIdentifiers.Pkcs9AtFriendlyName,
new DerSet(new DerBmpString(name))));
}
//
// make sure we have a local key-id
//
if (certEntry[PkcsObjectIdentifiers.Pkcs9AtLocalKeyID] == null)
{
SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(
certEntry.Certificate.GetPublicKey());
fName.Add(
new DerSequence(
PkcsObjectIdentifiers.Pkcs9AtLocalKeyID,
new DerSet(new SubjectKeyIdentifier(info))));
}
SafeBag sBag = new SafeBag(
PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName));
certSeq.Add(sBag);
doneCerts.Add(certEntry.Certificate, certEntry.Certificate);
}
foreach (string certId in certs.Keys)
{
X509CertificateEntry cert = (X509CertificateEntry)certs[certId];
if (keys[certId] != null)
{
continue;
}
CertBag cBag = new CertBag(
PkcsObjectIdentifiers.X509CertType,
new DerOctetString(cert.Certificate.GetEncoded()));
Asn1EncodableVector fName = new Asn1EncodableVector();
foreach (string oid in cert.BagAttributeKeys)
{
fName.Add(
new DerSequence(
new DerObjectIdentifier(oid),
new DerSet(cert[oid])));
}
//
// make sure we are using the local alias on store
//
DerBmpString nm = (DerBmpString) cert[PkcsObjectIdentifiers.Pkcs9AtFriendlyName];
if (nm == null || !nm.GetString().Equals(certId))
{
fName.Add(
new DerSequence(
PkcsObjectIdentifiers.Pkcs9AtFriendlyName,
new DerSet(new DerBmpString(certId))));
}
SafeBag sBag = new SafeBag(PkcsObjectIdentifiers.CertBag,
cBag.ToAsn1Object(), new DerSet(fName));
certSeq.Add(sBag);
doneCerts.Add(cert, cert);
}
foreach (CertId certId in chainCerts.Keys)
{
X509CertificateEntry cert = (X509CertificateEntry)chainCerts[certId];
if (doneCerts[cert] != null)
{
continue;
}
CertBag cBag = new CertBag(
PkcsObjectIdentifiers.X509CertType,
new DerOctetString(cert.Certificate.GetEncoded()));
Asn1EncodableVector fName = new Asn1EncodableVector();
foreach (string oid in cert.BagAttributeKeys)
{
fName.Add(new DerSequence(new DerObjectIdentifier(oid), new DerSet(cert[oid])));
}
SafeBag sBag = new SafeBag(PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName));
certSeq.Add(sBag);
}
derEncodedBytes = new DerSequence(certSeq).GetDerEncoded();
byte[] certBytes = EncryptData(new AlgorithmIdentifier(certAlgorithm, cParams), derEncodedBytes, password);
EncryptedData cInfo = new EncryptedData(PkcsObjectIdentifiers.Data, cAlgId, new BerOctetString(certBytes));
c[0] = new ContentInfo(PkcsObjectIdentifiers.Data, keyString);
c[1] = new ContentInfo(PkcsObjectIdentifiers.EncryptedData, cInfo.ToAsn1Object());
AuthenticatedSafe auth = new AuthenticatedSafe(c);
byte[] pkg = auth.GetEncoded();
ContentInfo mainInfo = new ContentInfo(PkcsObjectIdentifiers.Data, new BerOctetString(pkg));
//
// create the mac
//
byte[] mSalt = new byte[20];
int itCount = minIterations;
random.NextBytes(mSalt);
byte[] data = ((Asn1OctetString)mainInfo.Content).GetOctets();
Asn1Encodable parameters = PbeUtilities.GenerateAlgorithmParameters(OiwObjectIdentifiers.IdSha1, mSalt, itCount);
ICipherParameters keyParameters = PbeUtilities.GenerateCipherParameters(
OiwObjectIdentifiers.IdSha1, password, parameters);
IMac mac = (IMac)PbeUtilities.CreateEngine(OiwObjectIdentifiers.IdSha1);
mac.Init(keyParameters);
mac.BlockUpdate(data, 0, data.Length);
byte[] res = new byte[mac.GetMacSize()];
mac.DoFinal(res, 0);
AlgorithmIdentifier algId = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance);
DigestInfo dInfo = new DigestInfo(algId, res);
MacData mData = new MacData(dInfo, mSalt, itCount);
//
// output the Pfx
//
Pfx pfx = new Pfx(mainInfo, mData);
BerOutputStream berOut = new BerOutputStream(stream);
berOut.WriteObject(pfx);
}