42
42
import java .security .interfaces .DSAKey ;
43
43
import java .security .interfaces .DSAPrivateKey ;
44
44
import java .security .interfaces .DSAPublicKey ;
45
+ import java .security .spec .DSAPrivateKeySpec ;
45
46
import java .security .spec .DSAPublicKeySpec ;
46
47
import java .security .spec .InvalidKeySpecException ;
47
48
@@ -111,6 +112,7 @@ public PKeyDSA(Ruby runtime, RubyClass type, DSAPrivateKey privKey, DSAPublicKey
111
112
// a public key to be constructed incrementally, as required by the
112
113
// current implementation of Net::SSH.
113
114
// (see net-ssh-1.1.2/lib/net/ssh/transport/ossl/buffer.rb #read_keyblob)
115
+ private transient volatile BigInteger dsa_x ;
114
116
private transient volatile BigInteger dsa_y ;
115
117
private transient volatile BigInteger dsa_p ;
116
118
private transient volatile BigInteger dsa_q ;
@@ -368,85 +370,96 @@ public IRubyObject sysverify(IRubyObject arg, IRubyObject arg2) {
368
370
return getRuntime ().getNil ();
369
371
}
370
372
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 ();
379
386
}
380
- else if ( dsa_p != null ) {
381
- return BN . newBN ( getRuntime (), dsa_p ) ;
387
+ else {
388
+ return dsa_p ;
382
389
}
383
- return getRuntime ().getNil ();
390
+ }
391
+
392
+ @ JRubyMethod (name = "p" )
393
+ public IRubyObject get_p () {
394
+ return toBN (getP ());
384
395
}
385
396
386
397
@ JRubyMethod (name = "p=" )
387
398
public synchronized IRubyObject set_p (IRubyObject p ) {
388
399
return setKeySpecComponent (SPEC_P , p );
389
400
}
390
401
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 ();
399
406
}
400
- else if ( dsa_q != null ) {
401
- return BN . newBN ( getRuntime (), dsa_q ) ;
407
+ else {
408
+ return dsa_q ;
402
409
}
403
- return getRuntime ().getNil ();
410
+ }
411
+
412
+ @ JRubyMethod (name = "q" )
413
+ public IRubyObject get_q () {
414
+ return toBN (getQ ());
404
415
}
405
416
406
417
@ JRubyMethod (name = "q=" )
407
418
public synchronized IRubyObject set_q (IRubyObject q ) {
408
419
return setKeySpecComponent (SPEC_Q , q );
409
420
}
410
421
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 ();
419
426
}
420
- else if ( dsa_g != null ) {
421
- return BN . newBN ( getRuntime (), dsa_g ) ;
427
+ else {
428
+ return dsa_g ;
422
429
}
423
- return getRuntime ().getNil ();
430
+ }
431
+
432
+ @ JRubyMethod (name = "g" )
433
+ public IRubyObject get_g () {
434
+ return toBN (getG ());
424
435
}
425
436
426
437
@ JRubyMethod (name = "g=" )
427
438
public synchronized IRubyObject set_g (IRubyObject g ) {
428
439
return setKeySpecComponent (SPEC_G , g );
429
440
}
430
441
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
-
443
442
@ JRubyMethod (name = "priv_key" )
444
443
public synchronized IRubyObject get_priv_key () {
445
444
DSAPrivateKey key ;
446
445
if ((key = this .privateKey ) != null ) {
447
- return BN . newBN ( getRuntime (), key .getX ());
446
+ return toBN ( key .getX ());
448
447
}
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 );
450
463
}
451
464
452
465
@ JRubyMethod (name = "pub_key=" )
@@ -458,15 +471,38 @@ private IRubyObject setKeySpecComponent(final int index, final IRubyObject value
458
471
final BigInteger val = BN .getBigInteger (value );
459
472
460
473
switch (index ) {
474
+ case SPEC_X : this .dsa_x = val ; break ;
461
475
case SPEC_Y : this .dsa_y = val ; break ;
462
476
case SPEC_P : this .dsa_p = val ; break ;
463
477
case SPEC_Q : this .dsa_q = val ; break ;
464
478
case SPEC_G : this .dsa_g = val ; break ;
465
479
}
466
480
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 );
470
506
try {
471
507
this .publicKey = (DSAPublicKey ) SecurityHelper .getKeyFactory ("DSA" ).generatePublic (spec );
472
508
}
@@ -483,10 +519,11 @@ private IRubyObject setKeySpecComponent(final int index, final IRubyObject value
483
519
return value ;
484
520
}
485
521
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 ;
490
527
491
528
public static RaiseException newDSAError (Ruby runtime , String message ) {
492
529
return Utils .newError (runtime , _PKey (runtime ).getClass ("DSAError" ), message );
0 commit comments