diff --git a/pom.xml b/pom.xml
index e81d2d8..0cb793e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -221,6 +221,10 @@
tools.jackson.core
jackson-databind
+
+ tools.jackson.dataformat
+ jackson-dataformat-toml
+
diff --git a/src/main/java/land/oras/auth/RegistriesConf.java b/src/main/java/land/oras/auth/RegistriesConf.java
new file mode 100644
index 0000000..1226745
--- /dev/null
+++ b/src/main/java/land/oras/auth/RegistriesConf.java
@@ -0,0 +1,136 @@
+/*-
+ * =LICENSE=
+ * ORAS Java SDK
+ * ===
+ * Copyright (C) 2024 - 2025 ORAS
+ * ===
+ * Licensed 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.
+ * =LICENSEEND=
+ */
+
+package land.oras.auth;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Objects;
+import land.oras.exception.OrasException;
+import land.oras.utils.JsonUtils;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Handle registries.conf configuration
+ */
+@NullMarked
+public class RegistriesConf {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RegistriesConf.class);
+
+ /**
+ * The internal config
+ */
+ private final Config config;
+
+ /**
+ * Constructor for RegistriesConf.
+ *
+ * @param config configuration instance.
+ */
+ RegistriesConf(Config config) {
+ this.config = Objects.requireNonNull(config, "Config cannot be null");
+ }
+
+ /**
+ * Create a new RegistriesConf instance by loading configuration from the specified paths.
+ * @param configPaths The list of paths to load configuration from.
+ * @return A new RegistriesConf instance.
+ */
+ public static RegistriesConf newConf(List configPaths) {
+ List files = new ArrayList<>();
+ for (Path configPath : configPaths) {
+ if (Files.exists(configPath)) {
+ ConfigFile configFile = JsonUtils.fromJson(configPath, ConfigFile.class);
+ LOG.debug("Loaded registries config file: {}", configPath);
+ files.add(configFile);
+ }
+ }
+ return new RegistriesConf(Config.load(files));
+ }
+
+ /**
+ * Create a new RegistriesConf instance by loading configuration from standard paths.
+ * @return A new RegistriesConf instance.
+ */
+ public static RegistriesConf newConf() {
+ Path globalPath = Path.of("/etc/containers/registries.conf");
+ List paths = List.of(
+ globalPath,
+ System.getenv("HOME") != null
+ ? Path.of(System.getenv("HOME"), ".config", "containers", "registries.conf")
+ : globalPath);
+ return newConf(paths);
+ }
+
+ /**
+ * The model of the config file
+ *
+ */
+ record ConfigFile(@Nullable List unqualifiedRegistries) {}
+
+ /**
+ * Get the list of unclassified registries.
+ * @return an unmodifiable list of unclassified registries.
+ */
+ public List getUnclassifiedRegistries() {
+ return Collections.unmodifiableList(config.unqualifiedRegistries);
+ }
+
+ /**
+ * Nested Config class for configuration management.
+ */
+ static class Config {
+
+ /**
+ * Private constructor to prevent instantiation.
+ */
+ private Config() {}
+
+ /**
+ * List of unqualified registries.
+ */
+ private final List unqualifiedRegistries = new LinkedList<>();
+
+ /**
+ * Loads the configuration from a JSON file at the specified path and populates registries configuration
+ *
+ * @param configFiles The config files
+ * @return A {@code Config} object populated with config
+ * @throws OrasException If an error occurs while reading or parsing the TOML file.
+ */
+ public static Config load(List configFiles) throws OrasException {
+ Config config = new Config();
+ for (ConfigFile configFile : configFiles) {
+ if (configFile.unqualifiedRegistries != null) {
+ config.unqualifiedRegistries.addAll(configFile.unqualifiedRegistries);
+ }
+ }
+ return config;
+ }
+ }
+}
diff --git a/src/main/java/land/oras/utils/TomlUtils.java b/src/main/java/land/oras/utils/TomlUtils.java
new file mode 100644
index 0000000..d56b019
--- /dev/null
+++ b/src/main/java/land/oras/utils/TomlUtils.java
@@ -0,0 +1,101 @@
+/*-
+ * =LICENSE=
+ * ORAS Java SDK
+ * ===
+ * Copyright (C) 2024 - 2025 ORAS
+ * ===
+ * Licensed 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.
+ * =LICENSEEND=
+ */
+
+package land.oras.utils;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import land.oras.exception.OrasException;
+import org.jspecify.annotations.NullMarked;
+import tools.jackson.core.JacksonException;
+import tools.jackson.databind.ObjectMapper;
+import tools.jackson.dataformat.toml.TomlMapper;
+
+/**
+ * Utility class for TOML operations.
+ * Use Jackson 3 internally for TOML operations
+ */
+@NullMarked
+public final class TomlUtils {
+
+ /**
+ * TOML mapper instance
+ */
+ private static final ObjectMapper tomlMapper;
+
+ /**
+ * Utils class
+ */
+ private TomlUtils() {
+ // Hide constructor
+ }
+
+ static {
+ tomlMapper = TomlMapper.builder().build();
+ }
+
+ /**
+ * Convert an object to a TOML string
+ * @param object The object to convert
+ * @return The TOML string
+ */
+ public static String toToml(Object object) {
+ try {
+ return tomlMapper.writeValueAsString(object);
+ } catch (JacksonException e) {
+ throw new OrasException("Unable to convert object to TOML string", e);
+ }
+ }
+
+ /**
+ * Convert a TOML string to an object
+ * @param toml The TOML string
+ * @param clazz The class of the object
+ * @param The type of the object
+ * @return The object
+ */
+ public static T fromToml(String toml, Class clazz) {
+ try {
+ return tomlMapper.readValue(toml, clazz);
+ } catch (JacksonException e) {
+ throw new OrasException("Unable to parse TOML string", e);
+ }
+ }
+
+ /**
+ * Convert a TOML string to an object
+ * of the TOML string is not important.
+ * @param path The path to the TOML file
+ * @param clazz The class of the object
+ * @param The type of the object
+ * @return The object
+ */
+ public static T fromToml(Path path, Class clazz) {
+ try {
+ return tomlMapper.readValue(Files.readString(path, StandardCharsets.UTF_8), clazz);
+ } catch (IOException e) {
+ throw new OrasException("Unable to read TOML file due to IO error", e);
+ } catch (JacksonException e) {
+ throw new OrasException("Unable to parse TOML file", e);
+ }
+ }
+}
diff --git a/src/test/java/land/oras/utils/TomlUtilsTest.java b/src/test/java/land/oras/utils/TomlUtilsTest.java
new file mode 100644
index 0000000..0e4810a
--- /dev/null
+++ b/src/test/java/land/oras/utils/TomlUtilsTest.java
@@ -0,0 +1,63 @@
+/*-
+ * =LICENSE=
+ * ORAS Java SDK
+ * ===
+ * Copyright (C) 2024 - 2025 ORAS
+ * ===
+ * Licensed 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.
+ * =LICENSEEND=
+ */
+
+package land.oras.utils;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.nio.file.Path;
+import java.util.Map;
+import land.oras.exception.OrasException;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.CleanupMode;
+import org.junit.jupiter.api.io.TempDir;
+import org.junit.jupiter.api.parallel.Execution;
+import org.junit.jupiter.api.parallel.ExecutionMode;
+
+@Execution(ExecutionMode.CONCURRENT)
+public class TomlUtilsTest {
+
+ /**
+ * Temporary dir
+ */
+ @TempDir(cleanup = CleanupMode.ON_SUCCESS)
+ private static Path dir;
+
+ @Test
+ void failToParseTomlString() {
+ assertThrows(OrasException.class, () -> TomlUtils.fromToml("not a toml", Object.class));
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ void shouldParseToml() {
+ String tomlMap = """
+ key1 = "value1"
+ key2 = "value2"
+ """;
+ Map map = TomlUtils.fromToml(tomlMap, Map.class);
+ assertNotNull(map);
+ assertEquals(2, map.size());
+ assertEquals("value1", map.get("key1"));
+ assertEquals("value2", map.get("key2"));
+ }
+}