Skip to content

Commit 10d1db0

Browse files
authored
Merge pull request #182 from cconlon/primeGenRetry
Add retry loop for RSA key generation on PRIME_GEN_E failure
2 parents e49b9ed + 9a6c992 commit 10d1db0

File tree

1 file changed

+86
-47
lines changed

1 file changed

+86
-47
lines changed

src/main/java/com/wolfssl/provider/jce/WolfCryptKeyPairGenerator.java

Lines changed: 86 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import com.wolfssl.wolfcrypt.Ecc;
5454
import com.wolfssl.wolfcrypt.Dh;
5555
import com.wolfssl.wolfcrypt.Rng;
56+
import com.wolfssl.wolfcrypt.WolfCryptError;
5657
import 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

Comments
 (0)