4242import java .security .interfaces .DSAKey ;
4343import java .security .interfaces .DSAPrivateKey ;
4444import java .security .interfaces .DSAPublicKey ;
45+ import java .security .spec .DSAPrivateKeySpec ;
4546import java .security .spec .DSAPublicKeySpec ;
4647import java .security .spec .InvalidKeySpecException ;
4748
@@ -111,6 +112,7 @@ public PKeyDSA(Ruby runtime, RubyClass type, DSAPrivateKey privKey, DSAPublicKey
111112 // a public key to be constructed incrementally, as required by the
112113 // current implementation of Net::SSH.
113114 // (see net-ssh-1.1.2/lib/net/ssh/transport/ossl/buffer.rb #read_keyblob)
115+ private transient volatile BigInteger dsa_x ;
114116 private transient volatile BigInteger dsa_y ;
115117 private transient volatile BigInteger dsa_p ;
116118 private transient volatile BigInteger dsa_q ;
@@ -368,85 +370,96 @@ public IRubyObject sysverify(IRubyObject arg, IRubyObject arg2) {
368370 return getRuntime ().getNil ();
369371 }
370372
371- @ JRubyMethod (name = "p" )
372- public synchronized IRubyObject get_p () {
373- // FIXME: return only for public?
374- DSAKey key ; BigInteger param ;
375- if ((key = this .publicKey ) != null || (key = this .privateKey ) != null ) {
376- if ((param = key .getParams ().getP ()) != null ) {
377- return BN .newBN (getRuntime (), param );
378- }
373+ private DSAKey getDsaKey () {
374+ DSAKey result ;
375+ return (result = publicKey ) != null ? result : privateKey ;
376+ }
377+
378+ private IRubyObject toBN (BigInteger value ) {
379+ return value == null ? getRuntime ().getNil () : BN .newBN (getRuntime (), value );
380+ }
381+
382+ private synchronized BigInteger getP () {
383+ DSAKey key = getDsaKey ();
384+ if (key != null ) {
385+ return key .getParams ().getP ();
379386 }
380- else if ( dsa_p != null ) {
381- return BN . newBN ( getRuntime (), dsa_p ) ;
387+ else {
388+ return dsa_p ;
382389 }
383- return getRuntime ().getNil ();
390+ }
391+
392+ @ JRubyMethod (name = "p" )
393+ public IRubyObject get_p () {
394+ return toBN (getP ());
384395 }
385396
386397 @ JRubyMethod (name = "p=" )
387398 public synchronized IRubyObject set_p (IRubyObject p ) {
388399 return setKeySpecComponent (SPEC_P , p );
389400 }
390401
391- @ JRubyMethod (name = "q" )
392- public synchronized IRubyObject get_q () {
393- // FIXME: return only for public?
394- DSAKey key ; BigInteger param ;
395- if ((key = this .publicKey ) != null || (key = this .privateKey ) != null ) {
396- if ((param = key .getParams ().getQ ()) != null ) {
397- return BN .newBN (getRuntime (), param );
398- }
402+ private synchronized BigInteger getQ () {
403+ DSAKey key = getDsaKey ();
404+ if (key != null ) {
405+ return key .getParams ().getQ ();
399406 }
400- else if ( dsa_q != null ) {
401- return BN . newBN ( getRuntime (), dsa_q ) ;
407+ else {
408+ return dsa_q ;
402409 }
403- return getRuntime ().getNil ();
410+ }
411+
412+ @ JRubyMethod (name = "q" )
413+ public IRubyObject get_q () {
414+ return toBN (getQ ());
404415 }
405416
406417 @ JRubyMethod (name = "q=" )
407418 public synchronized IRubyObject set_q (IRubyObject q ) {
408419 return setKeySpecComponent (SPEC_Q , q );
409420 }
410421
411- @ JRubyMethod (name = "g" )
412- public synchronized IRubyObject get_g () {
413- // FIXME: return only for public?
414- DSAKey key ; BigInteger param ;
415- if ((key = this .publicKey ) != null || (key = this .privateKey ) != null ) {
416- if ((param = key .getParams ().getG ()) != null ) {
417- return BN .newBN (getRuntime (), param );
418- }
422+ private synchronized BigInteger getG () {
423+ DSAKey key = getDsaKey ();
424+ if (key != null ) {
425+ return key .getParams ().getG ();
419426 }
420- else if ( dsa_g != null ) {
421- return BN . newBN ( getRuntime (), dsa_g ) ;
427+ else {
428+ return dsa_g ;
422429 }
423- return getRuntime ().getNil ();
430+ }
431+
432+ @ JRubyMethod (name = "g" )
433+ public IRubyObject get_g () {
434+ return toBN (getG ());
424435 }
425436
426437 @ JRubyMethod (name = "g=" )
427438 public synchronized IRubyObject set_g (IRubyObject g ) {
428439 return setKeySpecComponent (SPEC_G , g );
429440 }
430441
431- @ JRubyMethod (name = "pub_key" )
432- public synchronized IRubyObject get_pub_key () {
433- DSAPublicKey key ;
434- if ( ( key = this .publicKey ) != null ) {
435- return BN .newBN (getRuntime (), key .getY ());
436- }
437- else if (dsa_y != null ) {
438- return BN .newBN (getRuntime (), dsa_y );
439- }
440- return getRuntime ().getNil ();
441- }
442-
443442 @ JRubyMethod (name = "priv_key" )
444443 public synchronized IRubyObject get_priv_key () {
445444 DSAPrivateKey key ;
446445 if ((key = this .privateKey ) != null ) {
447- return BN . newBN ( getRuntime (), key .getX ());
446+ return toBN ( key .getX ());
448447 }
449- return getRuntime ().getNil ();
448+ return toBN (dsa_x );
449+ }
450+
451+ @ JRubyMethod (name = "priv_key=" )
452+ public synchronized IRubyObject set_priv_key (IRubyObject priv_key ) {
453+ return setKeySpecComponent (SPEC_X , priv_key );
454+ }
455+
456+ @ JRubyMethod (name = "pub_key" )
457+ public synchronized IRubyObject get_pub_key () {
458+ DSAPublicKey key ;
459+ if ( ( key = this .publicKey ) != null ) {
460+ return toBN (key .getY ());
461+ }
462+ return toBN (dsa_y );
450463 }
451464
452465 @ JRubyMethod (name = "pub_key=" )
@@ -458,15 +471,38 @@ private IRubyObject setKeySpecComponent(final int index, final IRubyObject value
458471 final BigInteger val = BN .getBigInteger (value );
459472
460473 switch (index ) {
474+ case SPEC_X : this .dsa_x = val ; break ;
461475 case SPEC_Y : this .dsa_y = val ; break ;
462476 case SPEC_P : this .dsa_p = val ; break ;
463477 case SPEC_Q : this .dsa_q = val ; break ;
464478 case SPEC_G : this .dsa_g = val ; break ;
465479 }
466480
467- if ( dsa_y != null && dsa_p != null && dsa_q != null && dsa_g != null ) {
468- // we now have all components. create the key :
469- DSAPublicKeySpec spec = new DSAPublicKeySpec (dsa_y , dsa_p , dsa_q , dsa_g );
481+ // Don't access the dsa_p, dsa_q and dsa_g fields directly. They may
482+ // have already been consumed and cleared.
483+ BigInteger _dsa_p = getP ();
484+ BigInteger _dsa_q = getQ ();
485+ BigInteger _dsa_g = getG ();
486+
487+ if ( dsa_x != null && _dsa_p != null && _dsa_q != null && _dsa_g != null ) {
488+ // we now have all private key components. create the key :
489+ DSAPrivateKeySpec spec = new DSAPrivateKeySpec (dsa_x , _dsa_p , _dsa_q , _dsa_g );
490+ try {
491+ this .privateKey = (DSAPrivateKey ) SecurityHelper .getKeyFactory ("DSA" ).generatePrivate (spec );
492+ }
493+ catch (InvalidKeySpecException e ) {
494+ throw newDSAError (getRuntime (), "invalid keyspec" , e );
495+ }
496+ catch (NoSuchAlgorithmException e ) {
497+ throw newDSAError (getRuntime (), "unsupported key algorithm (DSA)" , e );
498+ }
499+ // clear out the specValues
500+ this .dsa_x = this .dsa_p = this .dsa_q = this .dsa_g = null ;
501+ }
502+
503+ if ( dsa_y != null && _dsa_p != null && _dsa_q != null && _dsa_g != null ) {
504+ // we now have all public key components. create the key :
505+ DSAPublicKeySpec spec = new DSAPublicKeySpec (dsa_y , _dsa_p , _dsa_q , _dsa_g );
470506 try {
471507 this .publicKey = (DSAPublicKey ) SecurityHelper .getKeyFactory ("DSA" ).generatePublic (spec );
472508 }
@@ -483,10 +519,11 @@ private IRubyObject setKeySpecComponent(final int index, final IRubyObject value
483519 return value ;
484520 }
485521
486- private static final int SPEC_Y = 0 ;
487- private static final int SPEC_P = 1 ;
488- private static final int SPEC_Q = 2 ;
489- private static final int SPEC_G = 3 ;
522+ private static final int SPEC_X = 0 ;
523+ private static final int SPEC_Y = 1 ;
524+ private static final int SPEC_P = 2 ;
525+ private static final int SPEC_Q = 3 ;
526+ private static final int SPEC_G = 4 ;
490527
491528 public static RaiseException newDSAError (Ruby runtime , String message ) {
492529 return Utils .newError (runtime , _PKey (runtime ).getClass ("DSAError" ), message );
0 commit comments