@@ -102,6 +102,85 @@ private static X509Certificate2 GenerateSelfSignedCertificate(string subject, X5
102102 return x509 ;
103103 }
104104
105+ private static X509Certificate2 GenerateSelfSignedCertificate ( string subject )
106+ {
107+ const int keyStrength = 2048 ;
108+
109+ // Generating Random Numbers
110+ var randomGenerator = new CryptoApiRandomGenerator ( ) ;
111+ var random = new SecureRandom ( randomGenerator ) ;
112+
113+ // The Certificate Generator
114+ var certificateGenerator = new X509V3CertificateGenerator ( ) ;
115+
116+ // Serial Number
117+ certificateGenerator . SetSerialNumber ( BigIntegers . CreateRandomInRange ( BigInteger . One , BigInteger . ValueOf ( long . MaxValue ) , random ) ) ;
118+
119+ // Subject Public Key
120+ var keyPairGenerator = new RsaKeyPairGenerator ( ) ;
121+ var keyGenerationParameters = new KeyGenerationParameters ( random , keyStrength ) ;
122+ keyPairGenerator . Init ( keyGenerationParameters ) ;
123+ var subjectKeyPair = keyPairGenerator . GenerateKeyPair ( ) ;
124+ certificateGenerator . SetPublicKey ( subjectKeyPair . Public ) ;
125+
126+ // Subject DN
127+ certificateGenerator . SetSubjectDN ( new X509Name ( "CN=" + subject ) ) ;
128+
129+ // Subject Alternative Name
130+ var subjectAlternativeNames = new List < Asn1Encodable > ( )
131+ {
132+ new GeneralName ( GeneralName . DnsName , Environment . MachineName ) ,
133+ new GeneralName ( GeneralName . DnsName , "localhost" ) ,
134+ new GeneralName ( GeneralName . IPAddress , "127.0.0.1" ) ,
135+ } ;
136+
137+ if ( subject != "localhost" && subject != Environment . MachineName )
138+ {
139+ subjectAlternativeNames . Add ( new GeneralName ( GeneralName . DnsName , subject ) ) ;
140+ }
141+
142+ certificateGenerator . AddExtension ( X509Extensions . SubjectAlternativeName . Id , false , new DerSequence ( subjectAlternativeNames . ToArray ( ) ) ) ;
143+
144+ // Issuer
145+ certificateGenerator . SetIssuerDN ( new X509Name ( "CN=" + subject ) ) ;
146+ certificateGenerator . AddExtension ( X509Extensions . SubjectKeyIdentifier . Id , false , new SubjectKeyIdentifier ( SubjectPublicKeyInfoFactory . CreateSubjectPublicKeyInfo ( subjectKeyPair . Public ) ) ) ;
147+
148+ // Valid For
149+ var notBefore = DateTime . UtcNow . Date ;
150+ var notAfter = notBefore . AddYears ( 2 ) ;
151+ certificateGenerator . SetNotBefore ( notBefore ) ;
152+ certificateGenerator . SetNotAfter ( notAfter ) ;
153+
154+ // Add basic constraint
155+ certificateGenerator . AddExtension ( X509Extensions . BasicConstraints . Id , true , new BasicConstraints ( false ) ) ;
156+
157+ certificateGenerator . AddExtension ( X509Extensions . ExtendedKeyUsage . Id , false , new ExtendedKeyUsage ( new [ ] { KeyPurposeID . IdKPServerAuth } ) ) ;
158+
159+ // Signature Algorithm
160+ const string signatureAlgorithm = "SHA256WithRSA" ;
161+ var signatureFactory = new Asn1SignatureFactory ( signatureAlgorithm , subjectKeyPair . Private ) ;
162+
163+ // selfsign certificate
164+ var certificate = certificateGenerator . Generate ( signatureFactory ) ;
165+
166+ // correcponding private key
167+ var info = PrivateKeyInfoFactory . CreatePrivateKeyInfo ( subjectKeyPair . Private ) ;
168+
169+ // merge into X509Certificate2
170+ var x509 = new X509Certificate2 ( certificate . GetEncoded ( ) ) ;
171+ var seq = ( Asn1Sequence ) Asn1Object . FromByteArray ( info . ParsePrivateKey ( ) . GetDerEncoded ( ) ) ;
172+ if ( seq . Count != 9 )
173+ {
174+ // throw new PemException("malformed sequence in RSA private key");
175+ }
176+
177+ var rsa = RsaPrivateKeyStructure . GetInstance ( seq ) ;
178+ var rsaparams = new RsaPrivateCrtKeyParameters (
179+ rsa . Modulus , rsa . PublicExponent , rsa . PrivateExponent , rsa . Prime1 , rsa . Prime2 , rsa . Exponent1 , rsa . Exponent2 , rsa . Coefficient ) ;
180+ x509 . PrivateKey = ToDotNetKey ( rsaparams ) ; // x509.PrivateKey = DotNetUtilities.ToRSA(rsaparams);
181+ return x509 ;
182+ }
183+
105184 private static AsymmetricAlgorithm ToDotNetKey ( RsaPrivateCrtKeyParameters privateKey )
106185 {
107186 var cspParams = new CspParameters
@@ -186,18 +265,23 @@ public static X509Certificate2 GetCert(string app, string hostname = "localhost"
186265 var appPath = Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . ApplicationData ) , app ) ;
187266 var caPfx = Path . Combine ( appPath , "ca.pfx" ) ;
188267 var certPfx = Path . Combine ( appPath , "cert.pfx" ) ;
189- if ( ! File . Exists ( caPfx ) || ! File . Exists ( certPfx ) )
268+
269+ // Patch release rework of cert handling: our websocket server doesn't acept a chain!
270+ if ( File . Exists ( caPfx ) )
190271 {
191- AsymmetricCipherKeyPair caKeyPair = null ;
192- var caCert = GenerateCACertificate ( "CN=" + app + "CA" , ref caKeyPair ) ;
193- var clientCert = GenerateSelfSignedCertificate ( hostname , caCert , caKeyPair ) ;
194- var p12ca = new X509Certificate2 ( caCert . Export ( X509ContentType . Pfx ) , ( string ) null ) . Export ( X509ContentType . Pfx ) ;
272+ File . Delete ( caPfx ) ;
273+ if ( File . Exists ( certPfx ) )
274+ {
275+ File . Delete ( certPfx ) ;
276+ }
277+ }
278+
279+ if ( ! File . Exists ( certPfx ) )
280+ {
281+ var clientCert = GenerateSelfSignedCertificate ( hostname ) ;
195282 var p12cert = clientCert . Export ( X509ContentType . Pfx ) ;
196283 Directory . CreateDirectory ( appPath ) ;
197- var w = File . OpenWrite ( caPfx ) ;
198- w . Write ( p12ca , 0 , p12ca . Length ) ;
199- w . Close ( ) ;
200- w = File . OpenWrite ( certPfx ) ;
284+ var w = File . OpenWrite ( certPfx ) ;
201285 w . Write ( p12cert , 0 , p12cert . Length ) ;
202286 w . Close ( ) ;
203287 }
0 commit comments