3232import java .io .StringWriter ;
3333import java .math .BigInteger ;
3434import java .security .KeyFactory ;
35+ import java .security .KeyPair ;
3536import java .security .NoSuchAlgorithmException ;
3637import java .security .PrivateKey ;
3738import java .security .PublicKey ;
3839import java .util .HashMap ;
3940
4041import java .security .SecureRandom ;
4142import java .security .spec .InvalidKeySpecException ;
43+ import javax .crypto .interfaces .DHPrivateKey ;
44+ import javax .crypto .interfaces .DHPublicKey ;
4245import javax .crypto .spec .DHParameterSpec ;
4346import javax .crypto .spec .DHPrivateKeySpec ;
4447import javax .crypto .spec .DHPublicKeySpec ;
@@ -117,6 +120,11 @@ public PKeyDH(Ruby runtime, RubyClass clazz) {
117120 this .dh_g = spec .getG ();
118121 }
119122
123+ PKeyDH (Ruby runtime , javax .crypto .interfaces .DHPublicKey publicKey , javax .crypto .interfaces .DHPrivateKey privateKey ) {
124+ this (runtime );
125+ initKey (publicKey , privateKey );
126+ }
127+
120128 @ Override
121129 @ JRubyMethod
122130 public RubyString oid () {
@@ -192,11 +200,17 @@ public synchronized IRubyObject initialize(final ThreadContext context, final IR
192200 try {
193201 DHParameterSpec spec = PEMInputOutput .readDHParameters (new StringReader (str .toString ()));
194202 if (spec == null ) {
195- spec = org .jruby .ext .openssl .impl .PKey .readDHParameter (str .getByteList ().bytes ());
196- }
197- if (spec == null ) {
198- throw runtime .newArgumentError ("invalid DH PARAMETERS" );
203+ try {
204+ spec = org .jruby .ext .openssl .impl .PKey .readDHParameter (str .getByteList ().bytes ());
205+ }
206+ catch (IOException e ) { // not parameters - a PKCS#8 or SubjectPublicKeyInfo DH key then
207+ if (!initFromKey (context , str )) throw e ;
208+ return this ;
209+ }
199210 }
211+
212+ if (spec == null ) throw runtime .newArgumentError ("invalid DH PARAMETERS" );
213+
200214 this .dh_p = spec .getP ();
201215 this .dh_g = spec .getG ();
202216 }
@@ -213,6 +227,35 @@ public synchronized IRubyObject initialize(final ThreadContext context, final IR
213227 return this ;
214228 }
215229
230+ // a DH key (not just parameters) is a plain PKCS#8 PrivateKeyInfo or SubjectPublicKeyInfo
231+ private boolean initFromKey (final ThreadContext context , final RubyString str ) {
232+ try {
233+ KeyPair keyPair = PKey .readPrivateKey (str , null );
234+ if (keyPair != null && keyPair .getPrivate () instanceof DHPrivateKey ) {
235+ initKey ((DHPublicKey ) keyPair .getPublic (), (DHPrivateKey ) keyPair .getPrivate ());
236+ return true ;
237+ }
238+ }
239+ catch (Exception e ) { /* not a DH private key */ }
240+ try {
241+ PublicKey pubKey = org .jruby .ext .openssl .impl .PKey .readPublicKey (StringHelper .readX509PEM (context , str ));
242+ if (pubKey instanceof DHPublicKey ) {
243+ initKey ((DHPublicKey ) pubKey , null );
244+ return true ;
245+ }
246+ }
247+ catch (Exception e ) { /* not a DH public key */ }
248+ return false ;
249+ }
250+
251+ private void initKey (DHPublicKey publicKey , DHPrivateKey privateKey ) {
252+ final DHParameterSpec params = privateKey != null ? privateKey .getParams () : publicKey .getParams ();
253+ this .dh_p = params .getP ();
254+ this .dh_g = params .getG ();
255+ if (privateKey != null ) this .dh_x = privateKey .getX ();
256+ if (publicKey != null ) this .dh_y = publicKey .getY ();
257+ }
258+
216259 private void generate (final Ruby runtime , final IRubyObject bits , final int gval ) {
217260 BigInteger p ;
218261 try {
0 commit comments