Skip to content

Commit 2185734

Browse files
committed
Use explicit locale and charset in security-utils module
Replace implicit locale and charset usage to avoid platform-dependent behavior: - Add Locale.ROOT to String.format() calls for locale-independent formatting - Replace .formatted() with String.format(Locale.ROOT, ...) - Add StandardCharsets.UTF_8 for explicit charset when converting bytes to strings
1 parent c8ca11e commit 2185734

26 files changed

Lines changed: 76 additions & 57 deletions

security-utils/src/main/java/com/yahoo/security/AutoReloadingX509KeyManager.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import java.security.cert.X509Certificate;
1515
import java.time.Duration;
1616
import java.util.List;
17+
import java.util.Locale;
1718
import java.util.concurrent.Executors;
1819
import java.util.concurrent.ScheduledExecutorService;
1920
import java.util.concurrent.TimeUnit;
@@ -87,11 +88,11 @@ private class KeyManagerReloader implements Runnable {
8788
@Override
8889
public void run() {
8990
try {
90-
log.log(Level.FINE, () -> String.format("Reloading key and certificate chain (private-key='%s', certificates='%s')", privateKeyFile, certificatesFile));
91+
log.log(Level.FINE, () -> String.format(Locale.ROOT, "Reloading key and certificate chain (private-key='%s', certificates='%s')", privateKeyFile, certificatesFile));
9192
mutableX509KeyManager.updateKeystore(createKeystore(privateKeyFile, certificatesFile), new char[0]);
9293
} catch (Throwable t) {
9394
log.log(Level.SEVERE,
94-
String.format("Failed to load X509 key manager (private-key='%s', certificates='%s'): %s",
95+
String.format(Locale.ROOT, "Failed to load X509 key manager (private-key='%s', certificates='%s'): %s",
9596
privateKeyFile, certificatesFile, t.getMessage()),
9697
t);
9798
}

security-utils/src/main/java/com/yahoo/security/BaseNCodec.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import java.math.BigInteger;
55
import java.util.Arrays;
6+
import java.util.Locale;
67

78
/**
89
* <p>
@@ -70,8 +71,7 @@ private static class Alphabet {
7071
Arrays.fill(reverseLut, -1); // -1 => invalid mapping
7172
for (int i = 0; i < alphabetChars.length; ++i) {
7273
if (reverseLut[alphabetChars[i]] != -1) {
73-
throw new IllegalArgumentException("Alphabet character '%c' occurs more than once"
74-
.formatted(alphabetChars[i]));
74+
throw new IllegalArgumentException(String.format(Locale.ROOT, "Alphabet character '%c' occurs more than once", alphabetChars[i]));
7575
}
7676
reverseLut[alphabetChars[i]] = i;
7777
}

security-utils/src/main/java/com/yahoo/security/HKDF.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import java.nio.ByteBuffer;
77
import java.security.InvalidKeyException;
88
import java.security.NoSuchAlgorithmException;
9+
import java.util.Locale;
910
import java.util.Objects;
1011

1112
/**
@@ -179,8 +180,7 @@ private void verifyWantedBytesWithinBounds(int wantedBytes) {
179180
throw new IllegalArgumentException("Requested negative or zero number of HKDF output bytes");
180181
}
181182
if (wantedBytes > MAX_OUTPUT_SIZE) {
182-
throw new IllegalArgumentException("Too many requested HKDF output bytes (max %d, got %d)"
183-
.formatted(MAX_OUTPUT_SIZE, wantedBytes));
183+
throw new IllegalArgumentException(String.format(Locale.ROOT, "Too many requested HKDF output bytes (max %d, got %d)", MAX_OUTPUT_SIZE, wantedBytes));
184184
}
185185
}
186186

security-utils/src/main/java/com/yahoo/security/KeyId.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
package com.yahoo.security;
33

44
import java.util.Arrays;
5+
import java.util.Locale;
56
import java.util.Objects;
67

78
import static com.yahoo.security.ArrayUtils.fromUtf8Bytes;
@@ -22,8 +23,7 @@ public class KeyId {
2223

2324
private KeyId(byte[] keyIdBytes) {
2425
if (keyIdBytes.length > MAX_KEY_ID_UTF8_LENGTH) {
25-
throw new IllegalArgumentException("Key ID is too large to be encoded (max is %d, got %d)"
26-
.formatted(MAX_KEY_ID_UTF8_LENGTH, keyIdBytes.length));
26+
throw new IllegalArgumentException(String.format(Locale.ROOT, "Key ID is too large to be encoded (max is %d, got %d)", MAX_KEY_ID_UTF8_LENGTH, keyIdBytes.length));
2727
}
2828
verifyByteStringRoundtripsAsValidUtf8(keyIdBytes);
2929
this.keyIdBytes = keyIdBytes;
@@ -75,7 +75,7 @@ public int hashCode() {
7575

7676
@Override
7777
public String toString() {
78-
return "KeyId(%s)".formatted(asString());
78+
return String.format(Locale.ROOT, "KeyId(%s)", asString());
7979
}
8080

8181
private static void verifyByteStringRoundtripsAsValidUtf8(byte[] byteStr) {

security-utils/src/main/java/com/yahoo/security/SealedSharedKey.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import java.nio.ByteBuffer;
55
import java.util.Arrays;
6+
import java.util.Locale;
67
import java.util.Objects;
78

89
import static com.yahoo.security.ArrayUtils.hex;
@@ -30,8 +31,7 @@ public record SealedSharedKey(int version, KeyId keyId, byte[] enc, byte[] ciphe
3031

3132
public SealedSharedKey {
3233
if (enc.length > MAX_ENC_CONTEXT_LENGTH) {
33-
throw new IllegalArgumentException("Encryption context is too large to be encoded (max is %d, got %d)"
34-
.formatted(MAX_ENC_CONTEXT_LENGTH, enc.length));
34+
throw new IllegalArgumentException(String.format(Locale.ROOT, "Encryption context is too large to be encoded (max is %d, got %d)", MAX_ENC_CONTEXT_LENGTH, enc.length));
3535
}
3636
}
3737

@@ -78,8 +78,7 @@ static SealedSharedKey fromSerializedBytes(byte[] rawTokenBytes) {
7878
// u8 token version || u8 length(key id) || key id || u8 length(enc) || enc || ciphertext
7979
int version = Byte.toUnsignedInt(decoded.get());
8080
if (version < 1 || version > CURRENT_TOKEN_VERSION) {
81-
throw new IllegalArgumentException("Token had unexpected version. Expected value in [1, %d], was %d"
82-
.formatted(CURRENT_TOKEN_VERSION, version));
81+
throw new IllegalArgumentException(String.format(Locale.ROOT, "Token had unexpected version. Expected value in [1, %d], was %d", CURRENT_TOKEN_VERSION, version));
8382
}
8483
int keyIdLen = Byte.toUnsignedInt(decoded.get());
8584
byte[] keyIdBytes = new byte[keyIdLen];

security-utils/src/main/java/com/yahoo/security/SecretSharedKey.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
package com.yahoo.security;
33

44
import javax.crypto.SecretKey;
5+
import java.util.Locale;
56

67
/**
78
* A SecretSharedKey represents a pairing of both the secret and public parts of
@@ -18,7 +19,7 @@ public record SecretSharedKey(SecretKey secretKey, SealedSharedKey sealedSharedK
1819
// via an implicitly generated method. Only print the sealed key (which is entirely public).
1920
@Override
2021
public String toString() {
21-
return "SharedSecretKey(sealed: %s)".formatted(sealedSharedKey.toTokenString());
22+
return String.format(Locale.ROOT, "SharedSecretKey(sealed: %s)", sealedSharedKey.toTokenString());
2223
}
2324

2425
/**

security-utils/src/main/java/com/yahoo/security/SharedKeyResealingSession.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.security.KeyPair;
88
import java.security.PrivateKey;
99
import java.security.interfaces.XECPublicKey;
10+
import java.util.Locale;
1011
import java.util.Optional;
1112

1213
/**
@@ -139,7 +140,7 @@ public ResealingRequest resealingRequestFor(SealedSharedKey sealedSharedKey) {
139140

140141
public static ResealingResponse reseal(ResealingRequest request, PrivateKeyProvider privateKeyProvider) {
141142
var privKey = privateKeyProvider.privateKeyForId(request.sealedKey.keyId()).orElseThrow(
142-
() -> new IllegalArgumentException("Could not find a private key for key ID '%s'".formatted(request.sealedKey.keyId())));
143+
() -> new IllegalArgumentException(String.format(Locale.ROOT, "Could not find a private key for key ID '%s'", request.sealedKey.keyId())));
143144

144145
var secretShared = SharedKeyGenerator.fromSealedKey(request.sealedKey, privKey);
145146
var resealed = SharedKeyGenerator.reseal(secretShared, request.ephemeralPubKey, KeyId.ofString("resealed-token")); // TODO key id

security-utils/src/main/java/com/yahoo/security/SslContextBuilder.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.io.UncheckedIOException;
1313
import java.nio.file.Files;
1414
import java.nio.file.Path;
15+
import java.nio.charset.StandardCharsets;
1516
import java.security.GeneralSecurityException;
1617
import java.security.KeyStore;
1718
import java.security.PrivateKey;
@@ -57,7 +58,7 @@ public SslContextBuilder withTrustStore(List<X509Certificate> caCertificates) {
5758
public SslContextBuilder withTrustStore(Path pemEncodedCaCertificates) {
5859
this.trustStoreSupplier = () -> {
5960
List<X509Certificate> caCertificates =
60-
X509CertificateUtils.certificateListFromPem(new String(Files.readAllBytes(pemEncodedCaCertificates)));
61+
X509CertificateUtils.certificateListFromPem(new String(Files.readAllBytes(pemEncodedCaCertificates), StandardCharsets.UTF_8));
6162
return createTrustStore(caCertificates);
6263
};
6364
return this;
@@ -102,8 +103,8 @@ public SslContextBuilder withKeyStore(Path file, char[] password, KeyStoreType k
102103
public SslContextBuilder withKeyStore(Path privateKeyPemFile, Path certificatesPemFile) {
103104
this.keyStoreSupplier =
104105
() -> {
105-
PrivateKey privateKey = KeyUtils.fromPemEncodedPrivateKey(new String(Files.readAllBytes(privateKeyPemFile)));
106-
List<X509Certificate> certificates = X509CertificateUtils.certificateListFromPem(new String(Files.readAllBytes(certificatesPemFile)));
106+
PrivateKey privateKey = KeyUtils.fromPemEncodedPrivateKey(new String(Files.readAllBytes(privateKeyPemFile), StandardCharsets.UTF_8));
107+
List<X509Certificate> certificates = X509CertificateUtils.certificateListFromPem(new String(Files.readAllBytes(certificatesPemFile), StandardCharsets.UTF_8));
107108
return KeyStoreBuilder.withType(KeyStoreType.JKS)
108109
.withKeyEntry("default", privateKey, certificates)
109110
.build();

security-utils/src/main/java/com/yahoo/security/hpke/Hpke.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.security.interfaces.XECPrivateKey;
66
import java.security.interfaces.XECPublicKey;
77
import java.util.Arrays;
8+
import java.util.Locale;
89

910
import static com.yahoo.security.ArrayUtils.concat;
1011
import static com.yahoo.security.hpke.Constants.BASE_NONCE_LABEL;
@@ -163,16 +164,13 @@ static void verifyPskInputs(byte mode, byte[] psk, byte[] pskId) {
163164

164165
static void verifyInputLengthRestrictions(byte[] psk, byte[] pskId, byte[] info) {
165166
if (psk.length > MAX_INPUT_LENGTH) {
166-
throw new IllegalArgumentException("Input PSK length (%d) greater than max length (%d)"
167-
.formatted(psk.length, MAX_INPUT_LENGTH));
167+
throw new IllegalArgumentException(String.format(Locale.ROOT, "Input PSK length (%d) greater than max length (%d)", psk.length, MAX_INPUT_LENGTH));
168168
}
169169
if (pskId.length > MAX_INPUT_LENGTH) {
170-
throw new IllegalArgumentException("Input PSK ID length (%d) greater than max length (%d)"
171-
.formatted(pskId.length, MAX_INPUT_LENGTH));
170+
throw new IllegalArgumentException(String.format(Locale.ROOT, "Input PSK ID length (%d) greater than max length (%d)", pskId.length, MAX_INPUT_LENGTH));
172171
}
173172
if (info.length > MAX_INPUT_LENGTH) {
174-
throw new IllegalArgumentException("Input info length (%d) greater than max length (%d)"
175-
.formatted(info.length, MAX_INPUT_LENGTH));
173+
throw new IllegalArgumentException(String.format(Locale.ROOT, "Input info length (%d) greater than max length (%d)", info.length, MAX_INPUT_LENGTH));
176174
}
177175
}
178176

security-utils/src/main/java/com/yahoo/security/tls/CapabilitySet.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.util.HashMap;
88
import java.util.HashSet;
99
import java.util.List;
10+
import java.util.Locale;
1011
import java.util.Map;
1112
import java.util.Objects;
1213
import java.util.Optional;
@@ -80,7 +81,7 @@ public static CapabilitySet fromNames(Collection<String> names) {
8081
var capability = Capability.fromName(name).orElse(null);
8182
if (capability != null) caps.add(capability);
8283
else if (predefinedSet != null) caps.addAll(predefinedSet.caps);
83-
else log.warning("Cannot find capability or capability set with name '%s'".formatted(name));
84+
else log.warning(String.format(Locale.ROOT, "Cannot find capability or capability set with name '%s'", name));
8485
}
8586
return new CapabilitySet(caps);
8687
}

0 commit comments

Comments
 (0)