Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@
import static io.aklivity.zilla.runtime.binding.tls.internal.types.event.TlsEventType.TLS_FAILED;
import static io.aklivity.zilla.runtime.binding.tls.internal.types.event.TlsEventType.TLS_HANDSHAKE_FAILED;
import static io.aklivity.zilla.runtime.binding.tls.internal.types.event.TlsEventType.TLS_KEY_REJECTED;
import static io.aklivity.zilla.runtime.binding.tls.internal.types.event.TlsEventType.TLS_KEY_VERIFICATION_FAILED;
import static io.aklivity.zilla.runtime.binding.tls.internal.types.event.TlsEventType.TLS_PEER_NOT_VERIFIED;
import static io.aklivity.zilla.runtime.binding.tls.internal.types.event.TlsEventType.TLS_PROTOCOL_REJECTED;
import static io.aklivity.zilla.runtime.binding.tls.internal.types.event.TlsKeyFailureType.TLS_KEY_INVALID;
import static io.aklivity.zilla.runtime.binding.tls.internal.types.event.TlsKeyFailureType.TLS_KEY_MISSING;

import java.nio.ByteBuffer;
import java.time.Clock;
Expand All @@ -29,6 +32,7 @@

import io.aklivity.zilla.runtime.binding.tls.internal.types.event.EventFW;
import io.aklivity.zilla.runtime.binding.tls.internal.types.event.TlsEventExFW;
import io.aklivity.zilla.runtime.binding.tls.internal.types.event.TlsKeyFailureType;
import io.aklivity.zilla.runtime.engine.EngineContext;
import io.aklivity.zilla.runtime.engine.binding.function.MessageConsumer;

Expand All @@ -46,6 +50,7 @@ public class TlsEventContext
private final int tlsKeyRejectedEventId;
private final int tlsPeerNotVerifiedEventId;
private final int tlsHandshakeFailedEventId;
private final int tlsKeyPairVerificationFailedEventId;
private final MessageConsumer eventWriter;
private final Clock clock;

Expand All @@ -58,6 +63,7 @@ public TlsEventContext(
this.tlsKeyRejectedEventId = context.supplyEventId("binding.tls.key.rejected");
this.tlsPeerNotVerifiedEventId = context.supplyEventId("binding.tls.peer.not.verified");
this.tlsHandshakeFailedEventId = context.supplyEventId("binding.tls.handshake.failed");
this.tlsKeyPairVerificationFailedEventId = context.supplyEventId("binding.tls.key.pair.verification.failed");
this.eventWriter = context.supplyEventWriter();
this.clock = context.clock();
}
Expand Down Expand Up @@ -166,4 +172,42 @@ public void tlsHandshakeFailed(
.build();
eventWriter.accept(tlsTypeId, event.buffer(), event.offset(), event.limit());
}

public void tlsKeyPairMissing(
long bindingId,
String keyName)
{
tlsKeyPairVerificationFailed(TLS_KEY_MISSING, bindingId, keyName);
}

public void tlsKeyPairInvalid(
long bindingId,
String keyName)
{
tlsKeyPairVerificationFailed(TLS_KEY_INVALID, bindingId, keyName);
}

private void tlsKeyPairVerificationFailed(
TlsKeyFailureType failureType,
long bindingId,
String keyName)
{
TlsEventExFW extension = tlsEventExRW
.wrap(extensionBuffer, 0, extensionBuffer.capacity())
.tlsKeyVerificationFailed(e -> e
.typeId(TLS_KEY_VERIFICATION_FAILED.value())
.failureType(t -> t.set(failureType))
.keyName(keyName)
)
.build();
EventFW event = eventRW
.wrap(eventBuffer, 0, eventBuffer.capacity())
.id(tlsKeyPairVerificationFailedEventId)
.timestamp(clock.millis())
.traceId(0L)
.namespacedId(bindingId)
.extension(extension.buffer(), extension.offset(), extension.limit())
.build();
eventWriter.accept(tlsTypeId, event.buffer(), event.offset(), event.limit());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import io.aklivity.zilla.runtime.binding.tls.internal.types.event.EventFW;
import io.aklivity.zilla.runtime.binding.tls.internal.types.event.TlsEventExFW;
import io.aklivity.zilla.runtime.binding.tls.internal.types.event.TlsKeyVerificationFailedExFW;
import io.aklivity.zilla.runtime.engine.Configuration;
import io.aklivity.zilla.runtime.engine.event.EventFormatterSpi;

Expand Down Expand Up @@ -68,6 +69,16 @@ public String format(
result = "The client and server could not negotiate the desired level of security.";
break;
}
case TLS_KEY_VERIFICATION_FAILED:
{
TlsKeyVerificationFailedExFW ex = extension.tlsKeyVerificationFailed();
result = switch (ex.failureType().get())
{
case TLS_KEY_MISSING -> String.format("Key pair (%s) is missing.", ex.keyName());
case TLS_KEY_INVALID -> String.format("Key pair (%s) is invalid.", ex.keyName());
};
break;
}
}
return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import static io.aklivity.zilla.runtime.binding.tls.internal.types.ProxyInfoType.AUTHORITY;
import static io.aklivity.zilla.runtime.binding.tls.internal.types.ProxyInfoType.SECURE;
import static io.aklivity.zilla.runtime.binding.tls.internal.types.ProxySecureInfoType.NAME;
import static java.lang.System.currentTimeMillis;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;
import static javax.net.ssl.StandardConstants.SNI_HOST_NAME;
Expand Down Expand Up @@ -53,6 +52,7 @@
import io.aklivity.zilla.runtime.binding.tls.config.TlsMutualConfig;
import io.aklivity.zilla.runtime.binding.tls.config.TlsOptionsConfig;
import io.aklivity.zilla.runtime.binding.tls.internal.TlsConfiguration;
import io.aklivity.zilla.runtime.binding.tls.internal.TlsEventContext;
import io.aklivity.zilla.runtime.binding.tls.internal.identity.TlsClientX509ExtendedKeyManager;
import io.aklivity.zilla.runtime.binding.tls.internal.types.Array32FW;
import io.aklivity.zilla.runtime.binding.tls.internal.types.ProxyAddressFW;
Expand Down Expand Up @@ -90,11 +90,13 @@ public TlsBindingConfig(

public void init(
TlsConfiguration config,
TlsEventContext events,
VaultHandler vault,
SecureRandom random)
{
TlsKeyPairVerifier verifier = new TlsKeyPairVerifier();
char[] keysPass = "generated".toCharArray();
KeyStore keys = newKeys(config, vault, keysPass, options.keys, options.signers);
KeyStore keys = newKeys(config, vault, keysPass, verifier, events, options.keys, options.signers);
KeyStore trust = newTrust(config, vault, options.trust, options.trustcacerts && kind == KindConfig.CLIENT);

Comment thread
attilakreiner marked this conversation as resolved.
try
Expand Down Expand Up @@ -408,6 +410,8 @@ private KeyStore newKeys(
TlsConfiguration config,
VaultHandler vault,
char[] password,
TlsKeyPairVerifier verifier,
TlsEventContext events,
List<String> keyNames,
List<String> signerNames)
{
Expand Down Expand Up @@ -442,14 +446,15 @@ private KeyStore newKeys(
KeyStore.PrivateKeyEntry entry = vault.key(keyName);
if (entry == null)
{
if (config.verbose())
{
System.out.printf("%d [%s] key \"%s\" not found\n",
currentTimeMillis(), this.qname, keyName);
}
events.tlsKeyPairMissing(this.id, keyName);
continue;
}
boolean valid = verifier.verify(entry);
if (!valid)
{
events.tlsKeyPairInvalid(this.id, keyName);
continue;
}

KeyStore.ProtectionParameter protection = new KeyStore.PasswordProtection(password);
store.setEntry(keyName, entry, protection);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright 2021-2023 Aklivity Inc.
*
* Aklivity licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.aklivity.zilla.runtime.binding.tls.internal.config;

import static org.agrona.LangUtil.rethrowUnchecked;

import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.util.concurrent.ThreadLocalRandom;

public class TlsKeyPairVerifier
{
private static final String ALGORITHM = "SHA256withRSA";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We discussed other key types like Elliptic Curve that would require a different algorithm, agree?


public boolean verify(
KeyStore.PrivateKeyEntry entry)
{
boolean valid = false;
try
{
PrivateKey privateKey = entry.getPrivateKey();
PublicKey publicKey = entry.getCertificate().getPublicKey();

// create a challenge
byte[] challenge = new byte[10000];
ThreadLocalRandom.current().nextBytes(challenge);

// sign using the private key
Signature sig = Signature.getInstance(ALGORITHM);
sig.initSign(privateKey);
sig.update(challenge);
byte[] signature = sig.sign();

// verify signature using the public key
sig.initVerify(publicKey);
sig.update(challenge);
valid = sig.verify(signature);
}
catch (InvalidKeyException | SignatureException ex)
{
// key invalid
}
catch (NoSuchAlgorithmException ex)
{
rethrowUnchecked(ex);
}
return valid;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ public void attach(

VaultHandler vault = supplyVault.apply(tlsBinding.vaultId);

tlsBinding.init(config, vault, random);
tlsBinding.init(config, event, vault, random);

bindings.put(binding.id, tlsBinding);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ public void attach(

VaultHandler vault = supplyVault.apply(tlsBinding.vaultId);

tlsBinding.init(config, vault, random);
tlsBinding.init(config, event, vault, random);

bindings.put(binding.id, tlsBinding);
}
Expand Down
Loading