Skip to content

Commit

Permalink
Allow applications to block until NonceUtil's SecureRandom is seeded (#…
Browse files Browse the repository at this point in the history
…804)

fixes #803
  • Loading branch information
kevinherron committed Mar 20, 2021
1 parent f3290a1 commit 60ac9eb
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 5 deletions.
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 the Eclipse Milo Authors
* Copyright (c) 2021 the Eclipse Milo Authors
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand All @@ -18,6 +18,9 @@
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.eclipse.milo.opcua.sdk.server.OpcUaServer;
Expand All @@ -37,6 +40,7 @@
import org.eclipse.milo.opcua.stack.core.types.enumerated.MessageSecurityMode;
import org.eclipse.milo.opcua.stack.core.types.structured.BuildInfo;
import org.eclipse.milo.opcua.stack.core.util.CertificateUtil;
import org.eclipse.milo.opcua.stack.core.util.NonceUtil;
import org.eclipse.milo.opcua.stack.core.util.SelfSignedCertificateGenerator;
import org.eclipse.milo.opcua.stack.core.util.SelfSignedHttpsCertificateBuilder;
import org.eclipse.milo.opcua.stack.server.EndpointConfiguration;
Expand All @@ -56,6 +60,13 @@ public class ExampleServer {
static {
// Required for SecurityPolicy.Aes256_Sha256_RsaPss
Security.addProvider(new BouncyCastleProvider());

try {
NonceUtil.blockUntilSecureRandomSeeded(10, TimeUnit.SECONDS);
} catch (ExecutionException | InterruptedException | TimeoutException e) {
e.printStackTrace();
System.exit(-1);
}
}

public static void main(String[] args) throws Exception {
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 the Eclipse Milo Authors
* Copyright (c) 2021 the Eclipse Milo Authors
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand All @@ -12,8 +12,12 @@

import java.security.SecureRandom;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;

import org.bouncycastle.util.Arrays;
Expand All @@ -34,6 +38,8 @@ public class NonceUtil {

private static volatile boolean SECURE_RANDOM_ENABLED = true;

private static final CompletableFuture<Void> SEED_FUTURE = new CompletableFuture<>();

private static final AtomicReference<SecureRandom> SECURE_RANDOM = new AtomicReference<>();

static {
Expand All @@ -50,8 +56,47 @@ public class NonceUtil {

LoggerFactory.getLogger(NonceUtil.class).info(
"SecureRandom seeded in {}ms.",
TimeUnit.MILLISECONDS.convert(delta, TimeUnit.NANOSECONDS));
}, "NonceUtilSecureRandom").start();
TimeUnit.MILLISECONDS.convert(delta, TimeUnit.NANOSECONDS)
);

SEED_FUTURE.complete(null);
}, "milo-nonce-util-secure-random").start();
}

/**
* Block until the {@link SecureRandom} instance has been seeded.
*
* @throws ExecutionException if seeding completed exceptionally.
* @throws InterruptedException if the current thread was interrupted.
*/
public static void blockUntilSecureRandomSeeded() throws ExecutionException, InterruptedException {
SEED_FUTURE.get();
}

/**
* Block for at most {@code timeout} waiting for the {@link SecureRandom} instance to be seeded.
*
* @param timeout the maximum time to wait.
* @param unit the {@link TimeUnit} of the {@code timeout} argument.
* @throws ExecutionException if seeding completed exceptionally.
* @throws InterruptedException if the current thread was interrupted.
* @throws TimeoutException if the wait timed out.
*/
public static void blockUntilSecureRandomSeeded(
long timeout,
TimeUnit unit
) throws ExecutionException, InterruptedException, TimeoutException {

SEED_FUTURE.get(timeout, unit);
}

/**
* Get a {@link CompletionStage} that is completed when the {@link SecureRandom} instance has been seeded.
*
* @return a {@link CompletionStage} that is completed when the {@link SecureRandom} instance has been seeded.
*/
public static CompletionStage<Void> secureRandomSeeded() {
return SEED_FUTURE;
}

/**
Expand All @@ -75,6 +120,13 @@ public static boolean isSecureRandomEnabled() {
return SECURE_RANDOM_ENABLED;
}

/**
* @return {@code true} if the {@link SecureRandom} instance is seeded and available.
*/
public static boolean isSecureRandomSeeded() {
return SECURE_RANDOM.get() != null;
}

/**
* @param length the length of the nonce to generate.
* @return a nonce of the given length.
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 the Eclipse Milo Authors
* Copyright (c) 2021 the Eclipse Milo Authors
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand All @@ -17,6 +17,7 @@

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertThrows;
import static org.testng.Assert.assertTrue;

public class NonceUtilTest {

Expand Down Expand Up @@ -60,4 +61,11 @@ public void testZeroLengthNonceValidation() throws UaException {
NonceUtil.validateNonce(ByteString.of(new byte[0]), 0);
}

@Test
public void blockUntilSecureRandomSeeded() throws Exception {
NonceUtil.blockUntilSecureRandomSeeded();

assertTrue(NonceUtil.isSecureRandomSeeded());
}

}

0 comments on commit 60ac9eb

Please sign in to comment.