5353import com .wolfssl .wolfcrypt .Ecc ;
5454import com .wolfssl .wolfcrypt .Dh ;
5555import com .wolfssl .wolfcrypt .Rng ;
56+ import com .wolfssl .wolfcrypt .WolfCryptError ;
5657import com .wolfssl .wolfcrypt .WolfCryptException ;
5758
5859/**
@@ -426,6 +427,10 @@ public synchronized KeyPair generateKeyPair() {
426427 KeySpec privSpec = null ;
427428 KeySpec pubSpec = null ;
428429
430+ final int MAX_KEYGEN_RETRIES = 5 ;
431+ int retryCount = 0 ;
432+ WolfCryptException lastPrimeGenException = null ;
433+
429434
430435 switch (this .type ) {
431436
@@ -440,58 +445,92 @@ public synchronized KeyPair generateKeyPair() {
440445 RSAPrivateKey rsaPriv = null ;
441446 RSAPublicKey rsaPub = null ;
442447
443- Rsa rsa = new Rsa ();
444-
445- try {
446- synchronized (rngLock ) {
447- rsa .makeKey (this .keysize , this .publicExponent ,
448- this .rng );
449- }
448+ /* Retry loop for RSA key generation. Native wolfCrypt may
449+ * return PRIME_GEN_E (-251) if it fails to find a suitable
450+ * prime after the NIST FIPS 186-4 mandated number of attempts.
451+ * We retry a few times in that error case before giving up. */
452+ while (retryCount < MAX_KEYGEN_RETRIES ) {
453+ Rsa rsa = new Rsa ();
450454
451- /* private key */
452- privDer = rsa .privateKeyEncodePKCS8 ();
453- if (privDer == null ) {
454- throw new RuntimeException (
455- "Unable to get RSA private key DER" );
456- }
457- privSpec = new PKCS8EncodedKeySpec (privDer );
455+ try {
456+ synchronized (rngLock ) {
457+ rsa .makeKey (this .keysize , this .publicExponent ,
458+ this .rng );
459+ }
460+
461+ /* private key */
462+ privDer = rsa .privateKeyEncodePKCS8 ();
463+ if (privDer == null ) {
464+ throw new RuntimeException (
465+ "Unable to get RSA private key DER" );
466+ }
467+ privSpec = new PKCS8EncodedKeySpec (privDer );
468+
469+ /* public key */
470+ pubDer = rsa .exportPublicDer ();
471+ if (pubDer == null ) {
472+ throw new RuntimeException (
473+ "Unable to get RSA public key DER" );
474+ }
475+ pubSpec = new X509EncodedKeySpec (pubDer );
476+
477+ KeyFactory kf = KeyFactory .getInstance ("RSA" );
478+ rsaPriv = (RSAPrivateKey )kf .generatePrivate (privSpec );
479+ rsaPub = (RSAPublicKey )kf .generatePublic (pubSpec );
480+
481+ if (this .type == KeyType .WC_RSA_PSS ) {
482+ /* Get key specs to generate PSS keys */
483+ RSAPrivateCrtKeySpec privCrtSpec =
484+ kf .getKeySpec (rsaPriv ,
485+ RSAPrivateCrtKeySpec .class );
486+ RSAPublicKeySpec pubKeySpec =
487+ kf .getKeySpec (rsaPub , RSAPublicKeySpec .class );
488+
489+ /* Use RSASSA-PSS KeyFactory */
490+ KeyFactory pssKf =
491+ KeyFactory .getInstance ("RSASSA-PSS" );
492+ rsaPriv = (RSAPrivateKey )pssKf
493+ .generatePrivate (privCrtSpec );
494+ rsaPub = (RSAPublicKey )pssKf
495+ .generatePublic (pubKeySpec );
496+ }
497+
498+ pair = new KeyPair (rsaPub , rsaPriv );
499+
500+ /* Success, exit retry loop */
501+ break ;
502+
503+ } catch (WolfCryptException e ) {
504+ /* Only retry on PRIME_GEN_E error */
505+ if (e .getError () == WolfCryptError .PRIME_GEN_E ) {
506+ lastPrimeGenException = e ;
507+ retryCount ++;
508+ log ("RSA key generation failed to find prime, " +
509+ "retry " + retryCount + "/" +
510+ MAX_KEYGEN_RETRIES );
511+ }
512+ else {
513+ throw new RuntimeException (e );
514+ }
458515
459- /* public key */
460- pubDer = rsa .exportPublicDer ();
461- if (pubDer == null ) {
462- throw new RuntimeException (
463- "Unable to get RSA public key DER" );
464- }
465- pubSpec = new X509EncodedKeySpec (pubDer );
516+ } catch (Exception e ) {
517+ throw new RuntimeException (e );
466518
467- zeroArray (privDer );
468- zeroArray (pubDer );
469- rsa .releaseNativeStruct ();
470-
471- KeyFactory kf = KeyFactory .getInstance ("RSA" );
472- rsaPriv = (RSAPrivateKey )kf .generatePrivate (privSpec );
473- rsaPub = (RSAPublicKey )kf .generatePublic (pubSpec );
474-
475- if (this .type == KeyType .WC_RSA_PSS ) {
476- /* Get key specs to generate PSS keys */
477- RSAPrivateCrtKeySpec privCrtSpec =
478- kf .getKeySpec (rsaPriv , RSAPrivateCrtKeySpec .class );
479- RSAPublicKeySpec pubKeySpec =
480- kf .getKeySpec (rsaPub , RSAPublicKeySpec .class );
481-
482- /* Use RSASSA-PSS KeyFactory */
483- KeyFactory pssKf =
484- KeyFactory .getInstance ("RSASSA-PSS" );
485- rsaPriv = (RSAPrivateKey )pssKf
486- .generatePrivate (privCrtSpec );
487- rsaPub = (RSAPublicKey )pssKf
488- .generatePublic (pubKeySpec );
519+ } finally {
520+ /* Always clean up */
521+ zeroArray (privDer );
522+ zeroArray (pubDer );
523+ rsa .releaseNativeStruct ();
489524 }
525+ }
490526
491- pair = new KeyPair (rsaPub , rsaPriv );
492-
493- } catch (Exception e ) {
494- throw new RuntimeException (e );
527+ /* Check if we exhausted all retries */
528+ if (pair == null ) {
529+ throw new RuntimeException (
530+ "RSA key generation failed after " +
531+ MAX_KEYGEN_RETRIES +
532+ " attempts due to prime generation failure" ,
533+ lastPrimeGenException );
495534 }
496535
497536 log ("generated " +
0 commit comments