デジタル証明書を書き出し、BouncyCastleを使用して署名を検証します

当社の主力製品は、ロシア語のオンボード暗号化を備えたデバイスであるRutoken EDSです。 デバイスをブラウザーと統合するために、 Rutokenプラグインがリリースされました。 プラグインの機能のデモは、 テストサイトで表示できます 。 それらのいくつかは、デバイスに保存されたデジタル証明書の操作を伴います。 たとえば、ユーザーを登録するとき、 デモバンクはユーザー証明書を発行し、システムにログインすると、それを要求してチェックします。 これらのタスクをサーバーに実装するには、BouncyCastleライブラリが使用されます。





この記事では、PKCS#10の要求に応じて証明書を発行し、ロシアの暗号化アルゴリズムによって生成されたCMS署名を検証するための使用例について説明します。



「認証局」は、BouncyCastleライブラリに基づいています。 サイトbouncycastle.org/csharp/には、修正なしではソリューションで動作しなかった古いバージョンのライブラリが含まれていることに注意してください。 作業バージョンはgithub- https://github.com/bcgit/bc-csharpで取得できます



また、さまざまなニーズにライブラリを使用するための一連のオプションを使用したテストもあります。



これらのすべてのうち、多くは必要ありません。

-PKCS#10リクエストを処理する

-要求に応じた証明書の発行



証明書を使用してサイトへのアクセスを整理する必要がある場合は、以下で別のアルゴリズムを実装します。



ルート証明書はライブラリによって生成され、後で使用できます。 PEM形式で既にあります。 秘密鍵もあります。



お客様



私たちのシステムでは、ASP.NET web-apiを備えたIISサーバーは、PKCS#10の要求によって証明書を発行する方法で外の世界を調べます。 クライアント上、つまりデモサイト自体で、 プラグインを操作するAngularJs上のアプリケーション回転しています。 もちろん、クライアントなら何でも書くことができますが、クライアント側の仕事の本質は次のようになります。



-PKCS#10リクエストを作成するためのフィールドデータをcreatePkcs10プラグイン関数に渡し、リクエストテキストを取得します。

-PKCS#10リクエストのテキストは、ポストリクエストによってapiメソッドに送信されます。証明書を作成できない場合は、証明書またはエラーを取得します。

-受信した証明書をimportCertificateプラグイン関数に転送し、デバイスにインポートします。



Rutoken EDSデバイスで証明書を管理する機能を備えたサイトの作業バージョンは、現在、 http: //ra.rutoken.ruでスピンしています。 キーを作成し、必要なフィールドを使用してリクエストを行うことができます。 次に、トークンにインポートされるテスト証明書を書き出します。

動作するには、プラグインをインストールし、Rutoken EDSを接続する必要があります!



サーバー



しかし、サーバー側に戻ります。 そのため、PEM形式のルート証明書とプライベートキーがあります。 PKCS#10のリクエストでユーザー証明書を発行します。 要求自体も、PEM形式のテキスト形式でクライアントから送信されます。



/*    */ const string cCACert = @"-----BEGIN CERTIFICATE----- ***   *** -----END CERTIFICATE-----"; /*   */ const string cCAKey = @"-----BEGIN PRIVATE KEY----- ***  *** -----END PRIVATE KEY-----"; //    public string generateTestCert(string pkcs10text) { //    PemReader pRd = new PemReader(new StringReader(cCAKey)); AsymmetricKeyParameter _cCAKey = (AsymmetricKeyParameter)pRd.ReadObject(); pRd.Reader.Close(); //    pRd = new PemReader(new StringReader(cCACert)); var _cCACert = (X509Certificate)pRd.ReadObject(); pRd.Reader.Close(); //  : //X509CertificateParser certParser = new X509CertificateParser(); //var _caCert = certParser.ReadCertificate(Base64.Decode(cCACert.Replace("-----BEGIN CERTIFICATE-----", string.Empty).Replace("-----END CERTIFICATE-----",string.Empty))); Pkcs10CertificationRequest _pkcs10; //  pkcs10 using (StringReader _sr = new StringReader(pkcs10text)) { pRd = new PemReader(_sr); _pkcs10 = (Pkcs10CertificationRequest)pRd.ReadObject(); pRd.Reader.Close(); } //   X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator(); var requestInfo = _pkcs10.GetCertificationRequestInfo(); var subPub = _pkcs10.GetPublicKey(); var issPub = _cCACert.GetPublicKey(); //   var randomGenerator = new CryptoApiRandomGenerator(); var random = new SecureRandom(randomGenerator); var serialNumber = BigIntegers.CreateRandomInRange( BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random); v3CertGen.Reset(); v3CertGen.SetSerialNumber(serialNumber); v3CertGen.SetIssuerDN(_cCACert.IssuerDN); v3CertGen.SetNotBefore(DateTime.UtcNow); //    v3CertGen.SetNotAfter(DateTime.UtcNow.AddYears(1)); v3CertGen.SetSubjectDN(requestInfo.Subject); v3CertGen.SetPublicKey(subPub); if (issPub is ECPublicKeyParameters) { //          ,    GOST3411withECGOST3410 ECPublicKeyParameters ecPub = (ECPublicKeyParameters)issPub; if (ecPub.AlgorithmName == "ECGOST3410") { v3CertGen.SetSignatureAlgorithm("GOST3411withECGOST3410"); } else { throw new Exception("   GOST3411withECGOST3410"); } } else { throw new Exception(" GOST3411withECGOST3410"); } // extensions v3CertGen.AddExtension( X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifier(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(subPub))); v3CertGen.AddExtension( X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifier(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(issPub))); v3CertGen.AddExtension( X509Extensions.BasicConstraints, false, new BasicConstraints(false)); X509Certificate _cert = v3CertGen.Generate(_cCAKey); _cert.CheckValidity(); _cert.Verify(issPub); var s = new StringWriter(); PemWriter pw = new PemWriter(s); pw.WriteObject(_cert); pw.Writer.Close(); return s.ToString(); }
      
      







サーバー上の署名済みCMSの検証



クライアントでCMSを生成し、サーバーに送信します。サーバーで署名と証明書のチェーンを検証します。



BouncyCastleから以下を使用します。

-署名検証署名済みCMS

-証​​明書チェーンの構築



すべての検証は、署名の検証、およびルートとそれに発行されたユーザーを含む証明書チェーンの構築に限定されます。 簡単にするために、中間証明書を使用せず、CRLで動作しませんが、もちろんライブラリには失効した証明書のリストをチェックする機能があります。



署名済みCMSの検証は次のように行います。



 //    public void verifyCert(X509Certificate cert) { try { //    var pRd = new PemReader(new StringReader(cCACert)); var _cCACert = (X509Certificate)pRd.ReadObject(); pRd.Reader.Close(); //     IList certList = new ArrayList(); certList.Add(_cCACert); certList.Add(cert); IX509Store x509CertStore = X509StoreFactory.Create( "Certificate/Collection", new X509CollectionStoreParameters(certList)); //   ,     ISet trust = new HashSet(); trust.Add(new TrustAnchor(_cCACert, null)); PkixCertPathBuilder cpb = new PkixCertPathBuilder(); X509CertStoreSelector targetConstraints = new X509CertStoreSelector(); targetConstraints.Subject = cert.SubjectDN; PkixBuilderParameters parameters = new PkixBuilderParameters(trust, targetConstraints); parameters.AddStore(x509CertStore); //   crl parameters.IsRevocationEnabled = false; //  ,   -  PkixCertPathBuilderResult result = cpb.Build(parameters); } catch (PkixCertPathBuilderException certPathEx) { throw new PkixCertPathBuilderException(string.Format("  , {0}", certPathEx.Message)); } catch (Exception ex) { throw new Exception(string.Format("  : {0}", cert.SubjectDN), ex); } } //  signed CMS public string verifyCms(string cmsText) { CmsSignedData cms = new CmsSignedData(Base64.Decode(cmsText)); SignerInformationStore sif = cms.GetSignerInfos(); var signers = sif.GetSigners(); var ucrts = cms.GetCertificates("collection"); //var crl = cms.GetCrls("collection"); //   ,     signer    foreach (SignerInformation signer in signers) { ICollection certCollection = ucrts.GetMatches(signer.SignerID); IEnumerator certEnum = certCollection.GetEnumerator(); certEnum.MoveNext(); X509Certificate cert = (X509Certificate)certEnum.Current; if (!signer.Verify(cert)) { throw new CertificateException("   "); } verifyCert(cert); } return "ok"; }
      
      







繰り返しになりますが、この例はロシアの証明書で機能するソリューションのテストまたは実証に適しています



All Articles