私はXamarinとBouncyCastleでpfxファイルを作成するのに苦労しています。 私は、次の設定/仕様BouncycastleでPKCS#12 Container(pfx)を保存
- .NET持っている:PCLの.NET Framework 4.5.1
- Xamarin:4.5.0.476
- はBouncyCastle:はBouncyCastle署名1.7.0.1(NuGet Package)
自分のモバイルクライアントが自分のサーバーに対して自分自身を認証するための自己署名付き証明書を生成したいと考えています。 BouncyCastleを使って作成がうまく動作します。私の問題はPKCS#12(pfx)コンテナとして秘密鍵を使って証明書を保存し、そのコンテナからそれを復元して私のWeb要求を送信し、例外がスローされてInput data cannot be coded as a valide certificate
と伝えたいときです。
ここでは、証明書、鍵を作成し、pfxコンテナを保存する手順を示します。
鍵のペアを作成します。
public void CreatePfxFile()
{
var certificate = this.GetCertificate();
var certEntry = new X509CertificateEntry(certificate);
string friendlyName = certificate.SubjectDN.ToString();
var privateKey = this.ReadPrivateKey();
PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKey);
byte[] keyBytes = info.ToAsn1Object().GetEncoded();
var store = new Pkcs12StoreBuilder().Build();
var keyEntry = new AsymmetricKeyEntry(privateKey,);
////store.SetCertificateEntry(Core.Constants.CertificateAlias, certEntry);
store.SetKeyEntry(Core.Constants.PrivateKeyAlias, new AsymmetricKeyEntry(privateKey), new X509CertificateEntry[] { certEntry });
MemoryStream stream = new MemoryStream();
store.Save(stream, Core.Constants.Password.ToCharArray(), new SecureRandom());
var pfxBytes = stream.ToArray();
var base64 = Convert.ToBase64String(pfxBytes);
this.StorePfxContainer(base64);
}
:
public void CreateCertificate()
{
var random = new SecureRandom();
var keyPair = this.GenerateKeyPair();
// generate certificate generator and set public key.
var generator = new X509V3CertificateGenerator();
generator.SetPublicKey(keyPair.Public);
// generate and set serial number
BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(long.MaxValue), random);
generator.SetSerialNumber(serialNumber);
// set signing algorithm.
generator.SetSignatureAlgorithm(Core.Constants.SignatureAlgorithmName);
// set name
string fullQualifiedName = $"CN=dummy,O=DummyOrg,OU=Dummy";
var name = new X509Name(fullQualifiedName);
generator.SetSubjectDN(name);
generator.SetIssuerDN(name);
// set valide time
generator.SetNotBefore(DateTime.UtcNow.AddHours(-1));
generator.SetNotAfter(DateTime.UtcNow.AddYears(10));
// add extensions.
var authorityKeyIdentifier = new AuthorityKeyIdentifier(
SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyPair.Public).GetEncoded(),
new GeneralNames(new GeneralName(name)),
serialNumber);
var subjectKeyIdentifier = new SubjectKeyIdentifier(
SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyPair.Public).GetEncoded());
generator.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, authorityKeyIdentifier);
generator.AddExtension(X509Extensions.SubjectKeyIdentifier, false, subjectKeyIdentifier);
generator.AddExtension(X509Extensions.BasicConstraints.Id, true, new BasicConstraints(0));
// generate and validate certificate.
var cert = generator.Generate(keyPair.Private, random);
cert.CheckValidity(DateTime.UtcNow);
cert.Verify(keyPair.Public);
// generate pem string
using (var stringWriter = new StringWriter())
{
var writer = new PemWriter(stringWriter);
var pog = new PemObject("CERTIFICATE", cert.GetEncoded());
writer.WriteObject(pog);
// pem value
var value = stringWriter.ToString();
this.StoreCertificate(value);
}
// store the private key
using (var stringWriter = new StringWriter())
{
var writer = new PemWriter(stringWriter);
PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private);
var pog = new PemObject("RSA PRIVATE KEY", info.ToAsn1Object().GetEncoded());
writer.WriteObject(pog);
// pem value
var value = stringWriter.ToString();
this.StorePrivateKey(value);
}
try
{
this.CreatePfxFile();
}
catch (Exception ex)
{
throw;
}
}
PFXコンテナを作成します。
private AsymmetricCipherKeyPair GenerateKeyPair()
{
var random = new SecureRandom();
var keyGenerationParameter = new KeyGenerationParameters(random, 4096);
var keyPairGenerator = new RsaKeyPairGenerator();
keyPairGenerator.Init(keyGenerationParameter);
var keyPair = keyPairGenerator.GenerateKeyPair();
return keyPair;
}
は、キーを作成するために呼び出すと、コンテナを作成する証明書を作成します
GetCertificate()
およびReadPrivateKey()
のメソッドは、X509Certificate
およびAsymmetricKeyParameter
である。 メソッドStorePfxContainer
は、base64文字列を設定変数に格納するだけです。
注:私は、store.SetCertificateEntry(Core.Constants.CertificateAlias, certEntry);
という行を削除しました。これは、pfxコンテナが証明書を2回含むためです。
私たちはBouncyCastleのものを使用しているので、今は使用しないでください。
私の要求に署名するには、次のコードを使用します。パラメータcert
は、設定からbase64文字列を取得し、Convert.FromBase64String(settingsValue)
を使用してバイトを取得することによって作成されます。今、私たちは、ネット(System.Security.Cryptography.X509Certificates.X509Certificate2)からの証明書を使用している
private void SetCertificate(HttpWebRequest request, byte[] cert)
{
try
{
System.Security.Cryptography.X509Certificates.X509Certificate2 certificate =
new System.Security.Cryptography.X509Certificates.X509Certificate2(cert, Core.Constants.Password); // <-- throws the exception
request.ClientCertificates.Add(certificate);
}
catch (Exception ex)
{
string message = ex.Message;
}
}
。私は、証明書をロードする際
x509Certifcate2
のコンストラクタでスローされる例外はMono.Security
によってスロー Input data cannot be coded as a valide certificate
である私も、私は私のPEMからPFXコンテナを生成しようとしました、OpenSSLので証明書と鍵をテスト証明書とpem秘密鍵も正常に動作します。私のコードの中で証明書を読み込むときだけ、それは動作しません。だから私は、コンテナの作成は私が今考え出していないバグがあると思う。
ありがとうございました。