diff --git a/Makefile b/Makefile
index ceecda2749..3009f618d5 100644
--- a/Makefile
+++ b/Makefile
@@ -512,7 +512,7 @@ validate.completions:
 .PHONY: run-docker-py-tests
 run-docker-py-tests:
 	touch test/__init__.py
-	pytest test/python/docker/
+	env CONTAINERS_CONF=$(CURDIR)/test/apiv2/containers.conf pytest test/python/docker/
 	-rm test/__init__.py
 
 .PHONY: localunit
@@ -594,8 +594,8 @@ remotesystem:
 .PHONY: localapiv2
 localapiv2:
 	env PODMAN=./bin/podman ./test/apiv2/test-apiv2
-	env PODMAN=./bin/podman ${PYTHON} -m unittest discover -v ./test/apiv2/python
-	env PODMAN=./bin/podman ${PYTHON} -m unittest discover -v ./test/python/docker
+	env CONTAINERS_CONF=$(CURDIR)/test/apiv2/containers.conf PODMAN=./bin/podman ${PYTHON} -m unittest discover -v ./test/apiv2/python
+	env CONTAINERS_CONF=$(CURDIR)/test/apiv2/containers.conf PODMAN=./bin/podman ${PYTHON} -m unittest discover -v ./test/python/docker
 
 .PHONY: remoteapiv2
 remoteapiv2:
diff --git a/go.mod b/go.mod
index 0e1ea3a7e8..82dc3dfc38 100644
--- a/go.mod
+++ b/go.mod
@@ -12,9 +12,9 @@ require (
 	github.com/containernetworking/cni v1.0.1
 	github.com/containernetworking/plugins v1.0.1
 	github.com/containers/buildah v1.23.1
-	github.com/containers/common v0.46.1-0.20211122213330-d4e7724a0c58
+	github.com/containers/common v0.46.1-0.20211125160015-ccf46abecd91
 	github.com/containers/conmon v2.0.20+incompatible
-	github.com/containers/image/v5 v5.17.0
+	github.com/containers/image/v5 v5.17.1-0.20211129144953-4f6d0b45be6c
 	github.com/containers/ocicrypt v1.1.2
 	github.com/containers/psgo v1.7.1
 	github.com/containers/storage v1.37.1-0.20211122214631-59ba58582415
diff --git a/go.sum b/go.sum
index 67eb41af1d..09a30d2a79 100644
--- a/go.sum
+++ b/go.sum
@@ -199,7 +199,6 @@ github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo
 github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI=
 github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s=
 github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
-github.com/containerd/containerd v1.5.4/go.mod h1:sx18RgvW6ABJ4iYUw7Q5x7bgFOAB9B6G7+yO0XBc4zw=
 github.com/containerd/containerd v1.5.5/go.mod h1:oSTh0QpT1w6jYcGmbiSbxv9OSQYaa88mPyWIuU79zyo=
 github.com/containerd/containerd v1.5.7 h1:rQyoYtj4KddB3bxG6SAqd4+08gePNyJjRqvOIfV3rkM=
 github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
@@ -263,14 +262,14 @@ github.com/containernetworking/plugins v1.0.1/go.mod h1:QHCfGpaTwYTbbH+nZXKVTxNB
 github.com/containers/buildah v1.23.1 h1:Tpc9DsRuU+0Oofewpxb6OJVNQjCu7yloN/obUqzfDTY=
 github.com/containers/buildah v1.23.1/go.mod h1:4WnrN0yrA7ab0ppgunixu2WM1rlD2rG8QLJAKbEkZlQ=
 github.com/containers/common v0.44.2/go.mod h1:7sdP4vmI5Bm6FPFxb3lvAh1Iktb6tiO1MzjUzhxdoGo=
-github.com/containers/common v0.46.1-0.20211122213330-d4e7724a0c58 h1:d99ZfYePYt1gU5dPvtIdnORNtv/7mkAZUHhCJzR5D5k=
-github.com/containers/common v0.46.1-0.20211122213330-d4e7724a0c58/go.mod h1:GrXYaGvQtdKA+fCQLudCTOSGRwZ06MVmRnC7KlI+syY=
+github.com/containers/common v0.46.1-0.20211125160015-ccf46abecd91 h1:h9SrSLSQkvluH/sEJ8X1rlBqCoGJtLvSOu4OGK0Qtuw=
+github.com/containers/common v0.46.1-0.20211125160015-ccf46abecd91/go.mod h1:PHwsa3UBgbvn2/MwpTQvyHXvVpuwfBrlDBx3GpIRPDQ=
 github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
 github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
 github.com/containers/image/v5 v5.16.0/go.mod h1:XgTpfAPLRGOd1XYyCU5cISFr777bLmOerCSpt/v7+Q4=
-github.com/containers/image/v5 v5.16.1/go.mod h1:mCvIFdzyyP1B0NBcZ80OIuaYqFn/OpFpaOMOMn1kU2M=
-github.com/containers/image/v5 v5.17.0 h1:KS5pro80CCsSp5qDBTMmSAWQo+xcBX19zUPExmYX2OQ=
 github.com/containers/image/v5 v5.17.0/go.mod h1:GnYVusVRFPMMTAAUkrcS8NNSpBp8oyrjOUe04AAmRr4=
+github.com/containers/image/v5 v5.17.1-0.20211129144953-4f6d0b45be6c h1:WfMOQlq3CDvVe5ONUGfj9/MajskqUHnbo24j24Xg2ZM=
+github.com/containers/image/v5 v5.17.1-0.20211129144953-4f6d0b45be6c/go.mod h1:boW5ckkT0wu9obDEiOIxrtWQmz1znMuHiVMQPcpHnk0=
 github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDplZ7U33NwHZkrVELsZP5fYj9pM5WBZB2GE=
 github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
 github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc=
diff --git a/pkg/api/handlers/compat/containers_create.go b/pkg/api/handlers/compat/containers_create.go
index d5abb6e442..8837e08cac 100644
--- a/pkg/api/handlers/compat/containers_create.go
+++ b/pkg/api/handlers/compat/containers_create.go
@@ -52,6 +52,13 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
+	imageName, err := utils.NormalizeToDockerHub(r, body.Config.Image)
+	if err != nil {
+		utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+		return
+	}
+	body.Config.Image = imageName
+
 	newImage, resolvedName, err := runtime.LibimageRuntime().LookupImage(body.Config.Image, nil)
 	if err != nil {
 		if errors.Cause(err) == storage.ErrImageUnknown {
diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go
index 0b7ba8bee8..af8b6b63d0 100644
--- a/pkg/api/handlers/compat/images.go
+++ b/pkg/api/handlers/compat/images.go
@@ -12,7 +12,6 @@ import (
 	"github.com/containers/common/libimage"
 	"github.com/containers/common/pkg/config"
 	"github.com/containers/image/v5/manifest"
-	"github.com/containers/image/v5/pkg/shortnames"
 	"github.com/containers/image/v5/types"
 	"github.com/containers/podman/v3/libpod"
 	"github.com/containers/podman/v3/pkg/api/handlers"
@@ -56,6 +55,12 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
 	defer os.Remove(tmpfile.Name())
 
 	name := utils.GetName(r)
+	possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, name)
+	if err != nil {
+		utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+		return
+	}
+
 	imageEngine := abi.ImageEngine{Libpod: runtime}
 
 	saveOptions := entities.ImageSaveOptions{
@@ -63,7 +68,7 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
 		Output: tmpfile.Name(),
 	}
 
-	if err := imageEngine.Save(r.Context(), name, nil, saveOptions); err != nil {
+	if err := imageEngine.Save(r.Context(), possiblyNormalizedName, nil, saveOptions); err != nil {
 		if errors.Cause(err) == storage.ErrImageUnknown {
 			utils.ImageNotFound(w, name, errors.Wrapf(err, "failed to find image %s", name))
 			return
@@ -87,9 +92,6 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
 }
 
 func CommitContainer(w http.ResponseWriter, r *http.Request) {
-	var (
-		destImage string
-	)
 	decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
 	runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
 
@@ -98,12 +100,12 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
 		Changes   string `schema:"changes"`
 		Comment   string `schema:"comment"`
 		Container string `schema:"container"`
+		Pause     bool   `schema:"pause"`
+		Repo      string `schema:"repo"`
+		Tag       string `schema:"tag"`
 		// fromSrc   string  # fromSrc is currently unused
-		Pause bool   `schema:"pause"`
-		Repo  string `schema:"repo"`
-		Tag   string `schema:"tag"`
 	}{
-		// This is where you can override the golang default value for one of fields
+		Tag: "latest",
 	}
 
 	if err := decoder.Decode(&query, r.URL.Query()); err != nil {
@@ -116,7 +118,6 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	sc := runtime.SystemContext()
-	tag := "latest"
 	options := libpod.ContainerCommitOptions{
 		Pause: true,
 	}
@@ -133,9 +134,6 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	if len(query.Tag) > 0 {
-		tag = query.Tag
-	}
 	options.Message = query.Comment
 	options.Author = query.Author
 	options.Pause = query.Pause
@@ -146,9 +144,15 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	// I know mitr hates this ... but doing for now
+	var destImage string
 	if len(query.Repo) > 1 {
-		destImage = fmt.Sprintf("%s:%s", query.Repo, tag)
+		destImage = fmt.Sprintf("%s:%s", query.Repo, query.Tag)
+		possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, destImage)
+		if err != nil {
+			utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+			return
+		}
+		destImage = possiblyNormalizedName
 	}
 
 	commitImage, err := ctr.Commit(r.Context(), destImage, options)
@@ -156,7 +160,7 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
 		utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "CommitFailure"))
 		return
 	}
-	utils.WriteResponse(w, http.StatusOK, handlers.IDResponse{ID: commitImage.ID()}) // nolint
+	utils.WriteResponse(w, http.StatusCreated, handlers.IDResponse{ID: commitImage.ID()}) // nolint
 }
 
 func CreateImageFromSrc(w http.ResponseWriter, r *http.Request) {
@@ -195,12 +199,22 @@ func CreateImageFromSrc(w http.ResponseWriter, r *http.Request) {
 		}
 	}
 
+	reference := query.Repo
+	if query.Repo != "" {
+		possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, reference)
+		if err != nil {
+			utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+			return
+		}
+		reference = possiblyNormalizedName
+	}
+
 	platformSpecs := strings.Split(query.Platform, "/")
 	opts := entities.ImageImportOptions{
 		Source:    source,
 		Changes:   query.Changes,
 		Message:   query.Message,
-		Reference: query.Repo,
+		Reference: reference,
 		OS:        platformSpecs[0],
 	}
 	if len(platformSpecs) > 1 {
@@ -250,13 +264,9 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	fromImage := mergeNameAndTagOrDigest(query.FromImage, query.Tag)
-
-	// without this early check this function would return 200 but reported error via body stream soon after
-	// it's better to let caller know early via HTTP status code that request cannot be processed
-	_, err := shortnames.Resolve(runtime.SystemContext(), fromImage)
+	possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, mergeNameAndTagOrDigest(query.FromImage, query.Tag))
 	if err != nil {
-		utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrap(err, "failed to resolve image name"))
+		utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
 		return
 	}
 
@@ -291,7 +301,7 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
 
 	pullResChan := make(chan pullResult)
 	go func() {
-		pulledImages, err := runtime.LibimageRuntime().Pull(r.Context(), fromImage, config.PullPolicyAlways, pullOptions)
+		pulledImages, err := runtime.LibimageRuntime().Pull(r.Context(), possiblyNormalizedName, config.PullPolicyAlways, pullOptions)
 		pullResChan <- pullResult{images: pulledImages, err: err}
 	}()
 
@@ -371,7 +381,13 @@ func GetImage(w http.ResponseWriter, r *http.Request) {
 	// 404 no such
 	// 500 internal
 	name := utils.GetName(r)
-	newImage, err := utils.GetImage(r, name)
+	possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, name)
+	if err != nil {
+		utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+		return
+	}
+
+	newImage, err := utils.GetImage(r, possiblyNormalizedName)
 	if err != nil {
 		// Here we need to fiddle with the error message because docker-py is looking for "No
 		// such image" to determine on how to raise the correct exception.
@@ -483,7 +499,16 @@ func ExportImages(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	images := query.Names
+	images := make([]string, len(query.Names))
+	for i, img := range query.Names {
+		possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, img)
+		if err != nil {
+			utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+			return
+		}
+		images[i] = possiblyNormalizedName
+	}
+
 	tmpfile, err := ioutil.TempFile("", "api.tar")
 	if err != nil {
 		utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile"))
diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go
index ac5934c139..bc53e93123 100644
--- a/pkg/api/handlers/compat/images_build.go
+++ b/pkg/api/handlers/compat/images_build.go
@@ -118,7 +118,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
 		SecurityOpt            string   `schema:"securityopt"`
 		ShmSize                int      `schema:"shmsize"`
 		Squash                 bool     `schema:"squash"`
-		Tag                    []string `schema:"t"`
+		Tags                   []string `schema:"t"`
 		Target                 string   `schema:"target"`
 		Timestamp              int64    `schema:"timestamp"`
 		Ulimits                string   `schema:"ulimits"`
@@ -144,6 +144,9 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
 		}
 	}
 
+	// convert tag formats
+	tags := query.Tags
+
 	// convert addcaps formats
 	var addCaps = []string{}
 	if _, found := r.URL.Query()["addcaps"]; found {
@@ -240,8 +243,13 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
 	}
 
 	var output string
-	if len(query.Tag) > 0 {
-		output = query.Tag[0]
+	if len(tags) > 0 {
+		possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, tags[0])
+		if err != nil {
+			utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+			return
+		}
+		output = possiblyNormalizedName
 	}
 	format := buildah.Dockerv2ImageManifest
 	registry := query.Registry
@@ -257,9 +265,14 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
 			}
 		}
 	}
-	var additionalTags []string
-	if len(query.Tag) > 1 {
-		additionalTags = query.Tag[1:]
+	var additionalTags []string // nolint
+	for i := 1; i < len(tags); i++ {
+		possiblyNormalizedTag, err := utils.NormalizeToDockerHub(r, tags[i])
+		if err != nil {
+			utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+			return
+		}
+		additionalTags = append(additionalTags, possiblyNormalizedTag)
 	}
 
 	var buildArgs = map[string]string{}
@@ -404,6 +417,22 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
 	}
 	defer auth.RemoveAuthfile(authfile)
 
+	fromImage := query.From
+	if fromImage != "" {
+		possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, fromImage)
+		if err != nil {
+			utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+			return
+		}
+		fromImage = possiblyNormalizedName
+	}
+
+	systemContext := &types.SystemContext{
+		AuthFilePath:     authfile,
+		DockerAuthConfig: creds,
+	}
+	utils.PossiblyEnforceDockerHub(r, systemContext)
+
 	// Channels all mux'ed in select{} below to follow API build protocol
 	stdout := channel.NewWriter(make(chan []byte))
 	defer stdout.Close()
@@ -458,7 +487,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
 		Err:                            auxout,
 		Excludes:                       excludes,
 		ForceRmIntermediateCtrs:        query.ForceRm,
-		From:                           query.From,
+		From:                           fromImage,
 		IgnoreUnrecognizedInstructions: query.Ignore,
 		Isolation:                      isolation,
 		Jobs:                           &jobs,
@@ -481,10 +510,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
 		RusageLogFile:                  query.RusageLogFile,
 		Squash:                         query.Squash,
 		Target:                         query.Target,
-		SystemContext: &types.SystemContext{
-			AuthFilePath:     authfile,
-			DockerAuthConfig: creds,
-		},
+		SystemContext:                  systemContext,
 	}
 
 	for _, platformSpec := range query.Platform {
@@ -590,7 +616,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
 						logrus.Warnf("Failed to json encode error %v", err)
 					}
 					flush()
-					for _, tag := range query.Tag {
+					for _, tag := range tags {
 						m.Stream = fmt.Sprintf("Successfully tagged %s\n", tag)
 						if err := enc.Encode(m); err != nil {
 							logrus.Warnf("Failed to json encode error %v", err)
diff --git a/pkg/api/handlers/compat/images_history.go b/pkg/api/handlers/compat/images_history.go
index 0c6b9fa888..fb3c2ebd25 100644
--- a/pkg/api/handlers/compat/images_history.go
+++ b/pkg/api/handlers/compat/images_history.go
@@ -14,9 +14,15 @@ func HistoryImage(w http.ResponseWriter, r *http.Request) {
 	runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
 	name := utils.GetName(r)
 
-	newImage, _, err := runtime.LibimageRuntime().LookupImage(name, nil)
+	possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, name)
 	if err != nil {
-		utils.Error(w, "Something went wrong.", http.StatusNotFound, errors.Wrapf(err, "failed to find image %s", name))
+		utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+		return
+	}
+
+	newImage, _, err := runtime.LibimageRuntime().LookupImage(possiblyNormalizedName, nil)
+	if err != nil {
+		utils.ImageNotFound(w, possiblyNormalizedName, errors.Wrapf(err, "failed to find image %s", possiblyNormalizedName))
 		return
 	}
 	history, err := newImage.History(r.Context())
diff --git a/pkg/api/handlers/compat/images_push.go b/pkg/api/handlers/compat/images_push.go
index 8b6d3d56ae..5ecb429ae3 100644
--- a/pkg/api/handlers/compat/images_push.go
+++ b/pkg/api/handlers/compat/images_push.go
@@ -61,12 +61,24 @@ func PushImage(w http.ResponseWriter, r *http.Request) {
 	if query.Tag != "" {
 		imageName += ":" + query.Tag
 	}
+
 	if _, err := utils.ParseStorageReference(imageName); err != nil {
 		utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
 			errors.Wrapf(err, "image source %q is not a containers-storage-transport reference", imageName))
 		return
 	}
 
+	possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, imageName)
+	if err != nil {
+		utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+		return
+	}
+	imageName = possiblyNormalizedName
+	if _, _, err := runtime.LibimageRuntime().LookupImage(possiblyNormalizedName, nil); err != nil {
+		utils.ImageNotFound(w, imageName, errors.Wrapf(err, "failed to find image %s", imageName))
+		return
+	}
+
 	authconf, authfile, key, err := auth.GetCredentials(r)
 	if err != nil {
 		utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse %q header for %s", key, r.URL.String()))
diff --git a/pkg/api/handlers/compat/images_remove.go b/pkg/api/handlers/compat/images_remove.go
index 2dc247c1fd..5c06d8de0a 100644
--- a/pkg/api/handlers/compat/images_remove.go
+++ b/pkg/api/handlers/compat/images_remove.go
@@ -34,12 +34,18 @@ func RemoveImage(w http.ResponseWriter, r *http.Request) {
 		}
 	}
 	name := utils.GetName(r)
+	possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, name)
+	if err != nil {
+		utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+		return
+	}
+
 	imageEngine := abi.ImageEngine{Libpod: runtime}
 
 	options := entities.ImageRemoveOptions{
 		Force: query.Force,
 	}
-	report, rmerrors := imageEngine.Remove(r.Context(), []string{name}, options)
+	report, rmerrors := imageEngine.Remove(r.Context(), []string{possiblyNormalizedName}, options)
 	if len(rmerrors) > 0 && rmerrors[0] != nil {
 		err := rmerrors[0]
 		if errors.Cause(err) == storage.ErrImageUnknown {
diff --git a/pkg/api/handlers/compat/images_tag.go b/pkg/api/handlers/compat/images_tag.go
index 5d413a8219..3fe13e2f54 100644
--- a/pkg/api/handlers/compat/images_tag.go
+++ b/pkg/api/handlers/compat/images_tag.go
@@ -14,12 +14,16 @@ import (
 func TagImage(w http.ResponseWriter, r *http.Request) {
 	runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
 
-	// /v1.xx/images/(name)/tag
 	name := utils.GetName(r)
+	possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, name)
+	if err != nil {
+		utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+		return
+	}
 
 	// Allow tagging manifest list instead of resolving instances from manifest
 	lookupOptions := &libimage.LookupImageOptions{ManifestList: true}
-	newImage, _, err := runtime.LibimageRuntime().LookupImage(name, lookupOptions)
+	newImage, _, err := runtime.LibimageRuntime().LookupImage(possiblyNormalizedName, lookupOptions)
 	if err != nil {
 		utils.ImageNotFound(w, name, errors.Wrapf(err, "failed to find image %s", name))
 		return
@@ -35,7 +39,14 @@ func TagImage(w http.ResponseWriter, r *http.Request) {
 	}
 	repo := r.Form.Get("repo")
 	tagName := fmt.Sprintf("%s:%s", repo, tag)
-	if err := newImage.Tag(tagName); err != nil {
+
+	possiblyNormalizedTag, err := utils.NormalizeToDockerHub(r, tagName)
+	if err != nil {
+		utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+		return
+	}
+
+	if err := newImage.Tag(possiblyNormalizedTag); err != nil {
 		utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
 		return
 	}
diff --git a/pkg/api/handlers/utils/images.go b/pkg/api/handlers/utils/images.go
index d5eb71aa15..d874165e35 100644
--- a/pkg/api/handlers/utils/images.go
+++ b/pkg/api/handlers/utils/images.go
@@ -3,19 +3,61 @@ package utils
 import (
 	"fmt"
 	"net/http"
+	"strings"
 
 	"github.com/containers/common/libimage"
 	"github.com/containers/common/pkg/filters"
 	"github.com/containers/image/v5/docker"
-	"github.com/containers/image/v5/storage"
+	storageTransport "github.com/containers/image/v5/storage"
 	"github.com/containers/image/v5/transports/alltransports"
 	"github.com/containers/image/v5/types"
 	"github.com/containers/podman/v3/libpod"
 	api "github.com/containers/podman/v3/pkg/api/types"
+	"github.com/containers/podman/v3/pkg/util"
+	"github.com/containers/storage"
+	"github.com/docker/distribution/reference"
 	"github.com/gorilla/schema"
 	"github.com/pkg/errors"
 )
 
+// NormalizeToDockerHub normalizes the specified nameOrID to Docker Hub if the
+// request is for the compat API and if containers.conf set the specific mode.
+// If nameOrID is a (short) ID for a local image, the full ID will be returned.
+func NormalizeToDockerHub(r *http.Request, nameOrID string) (string, error) {
+	if IsLibpodRequest(r) || !util.DefaultContainerConfig().Engine.CompatAPIEnforceDockerHub {
+		return nameOrID, nil
+	}
+
+	// Try to lookup the input to figure out if it was an ID or not.
+	runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
+	img, _, err := runtime.LibimageRuntime().LookupImage(nameOrID, nil)
+	if err != nil {
+		if errors.Cause(err) != storage.ErrImageUnknown {
+			return "", fmt.Errorf("normalizing name for compat API: %v", err)
+		}
+	} else if strings.HasPrefix(img.ID(), nameOrID) {
+		return img.ID(), nil
+	}
+
+	// No ID, so we can normalize.
+	named, err := reference.ParseNormalizedNamed(nameOrID)
+	if err != nil {
+		return "", fmt.Errorf("normalizing name for compat API: %v", err)
+	}
+
+	return named.String(), nil
+}
+
+// PossiblyEnforceDockerHub sets fields in the system context to enforce
+// resolving short names to Docker Hub if the request is for the compat API and
+// if containers.conf set the specific mode.
+func PossiblyEnforceDockerHub(r *http.Request, sys *types.SystemContext) {
+	if IsLibpodRequest(r) || !util.DefaultContainerConfig().Engine.CompatAPIEnforceDockerHub {
+		return
+	}
+	sys.PodmanOnlyShortNamesIgnoreRegistriesConfAndForceDockerHub = true
+}
+
 // IsRegistryReference checks if the specified name points to the "docker://"
 // transport.  If it points to no supported transport, we'll assume a
 // non-transport reference pointing to an image (e.g., "fedora:latest").
@@ -35,13 +77,13 @@ func IsRegistryReference(name string) error {
 // `types.ImageReference` and enforces it to refer to a
 // containers-storage-transport reference.
 func ParseStorageReference(name string) (types.ImageReference, error) {
-	storagePrefix := fmt.Sprintf("%s:", storage.Transport.Name())
+	storagePrefix := storageTransport.Transport.Name()
 	imageRef, err := alltransports.ParseImageName(name)
 	if err == nil && imageRef.Transport().Name() != docker.Transport.Name() {
 		return nil, errors.Errorf("reference %q must be a storage reference", name)
 	} else if err != nil {
 		origErr := err
-		imageRef, err = alltransports.ParseImageName(fmt.Sprintf("%s%s", storagePrefix, name))
+		imageRef, err = alltransports.ParseImageName(fmt.Sprintf("%s:%s", storagePrefix, name))
 		if err != nil {
 			return nil, errors.Wrapf(origErr, "reference %q must be a storage reference", name)
 		}
diff --git a/test/apiv2/12-imagesMore.at b/test/apiv2/12-imagesMore.at
index 144b83194e..3a5d5c0969 100644
--- a/test/apiv2/12-imagesMore.at
+++ b/test/apiv2/12-imagesMore.at
@@ -47,8 +47,7 @@ t POST "images/localhost:5000/myrepo/push?tlsVerify=false&tag=mytag" 200
 t POST "libpod/images/$iid/untag?repo=localhost:5000/myrepo&tag=mytag" 201
 
 # Try to push non-existing image
-t POST "images/localhost:5000/idonotexist/push?tlsVerify=false" 200
-jq -re 'select(.errorDetail)' <<<"$output" &>/dev/null || echo -e "${red}not ok: error message not found in output${nc}" 1>&2
+t POST "images/localhost:5000/idonotexist/push?tlsVerify=false" 404
 
 t GET libpod/images/$IMAGE/json 200 \
   .RepoTags[-1]=$IMAGE
diff --git a/test/apiv2/70-short-names.at b/test/apiv2/70-short-names.at
new file mode 100644
index 0000000000..a5087c1150
--- /dev/null
+++ b/test/apiv2/70-short-names.at
@@ -0,0 +1,148 @@
+# -*- sh -*-
+#
+# Tests for exercising short-name resolution in the compat API.
+#
+
+# Pull the libpod/quay image which is used in all tests below.
+t POST "images/create?fromImage=quay.io/libpod/alpine:latest" 200 .error~null .status~".*Download complete.*"
+
+
+########## TAG
+
+t POST   "images/quay.io/libpod/alpine/tag?repo=foo"  201
+t DELETE "images/foo"                                 200
+
+
+########## BUILD
+
+function test_build {
+    from=$1
+    tag=$2
+    fqn=$3
+
+    TMPD=$(mktemp -d podman-apiv2-test.build.XXXXXXXX)
+    CONTAINERFILE_TAR="${TMPD}/containerfile.tar"
+    cat > $TMPD/containerfile << EOF
+FROM $from
+RUN  touch /foo
+EOF
+    tar --format=posix -C $TMPD -cvf ${CONTAINERFILE_TAR} containerfile &> /dev/null
+
+    curl -XPOST --data-binary @<(cat $CONTAINERFILE_TAR) \
+        -H "content-type: application/x-tar" \
+        --dump-header "${TMPD}/headers.txt" \
+        -o "${TMPD}/response.txt" \
+        "http://$HOST:$PORT/build?dockerfile=containerfile&t=$tag" &> /dev/null
+
+    if ! grep -q '200 OK' "${TMPD}/headers.txt"; then
+        cat "${TMPD}/headers.txt"
+        cat "${TMPD}/response.txt"
+        echo -e "${red}NOK: Image build from tar failed response was not 200 OK (application/x-tar)"
+        exit 1
+    fi
+
+    rm -rf $TMPD
+    t DELETE "images/$fqn" 200
+}
+
+t POST   "images/quay.io/libpod/alpine/tag?repo=foo" 201
+test_build foo bar "docker.io/library/bar:latest"
+t DELETE "images/foo"                                200
+
+
+########## TAG
+
+# Looking up 'alpine' will fail as it gets normalized to docker.io.
+t POST "images/alpine/tag?repo=foo" 404 .cause="image not known"
+
+# The libpod endpoint will resolve to it without issues.
+t GET "libpod/images/alpine/exists" 204
+
+# Now let's tag the image with 'foo'.  Remember, it will be normalized to
+# docker.io/library/foo.
+t GET  "libpod/images/docker.io/library/foo/exists" 404
+t POST "images/quay.io/libpod/alpine/tag?repo=foo"  201
+t GET  "libpod/images/docker.io/library/foo/exists" 204
+
+
+########## REMOVE
+
+t DELETE "images/alpine" 404 .cause="image not known" # fails since docker.io/library/alpine does not exist
+t DELETE "images/foo"    200                          # removes the previously tagged image
+
+
+########## GET
+
+# Same procedure as above but with the /get endpoint.
+t GET    "images/alpine/get"                         404 .cause="image not known"
+t POST   "images/quay.io/libpod/alpine/tag?repo=foo" 201
+t GET    "images/foo/get"                            200 '[POSIX tar archive]'
+t DELETE "images/foo"                                200
+
+
+########## HISTORY
+
+t GET    "images/alpine/history"                     404 .cause="image not known"
+t GET    "images/quay.io/libpod/alpine/history"      200
+t POST   "images/quay.io/libpod/alpine/tag?repo=foo" 201
+t GET    "libpod/images/foo/history"                 200
+t DELETE "images/foo"                                200
+
+
+########## PUSH
+
+t POST   "images/alpine/push?destination=localhost:9999/do/not:exist"                404 .cause="image not known"
+t POST   "images/quay.io/libpod/alpine/push?destination=localhost:9999/do/not:exist" 200 # Error is in the response
+t POST   "images/quay.io/libpod/alpine/tag?repo=foo"                                 201
+t POST   "images/foo/push?destination=localhost:9999/do/not:exist"                   200 # Error is in the response
+t DELETE "images/foo"                                                                200
+
+
+########## CREATE A CONTAINER
+
+t POST   "containers/create"                         Image=alpine                       404 .cause="image not known"
+t POST   "containers/create"                         Image=quay.io/libpod/alpine:latest 201
+cid=$(jq -r '.Id' <<<"$output")
+t POST   "images/quay.io/libpod/alpine/tag?repo=foo"                                    201
+t POST   "containers/create"                         Image=foo                          201
+cid=$(jq -r '.Id' <<<"$output")
+t DELETE "images/foo"                                                                   200
+t DELETE "containers/$cid"                                                              204
+
+########## COMMIT CONTAINER
+
+t POST   "containers/create"                      Image=quay.io/libpod/alpine:latest 201
+cid=$(jq -r '.Id' <<<"$output")
+t GET    "images/alpine/get"                                                         404 .cause="image not known"
+t POST   "commit?container=$cid&repo=foo&tag=tag"                                    201
+t GET    "images/foo/get"                                                            404 .cause="image not known"
+t GET    "images/foo:tag/get"                                                        200
+t DELETE "images/docker.io/library/foo:tag"                                          200
+t DELETE "containers/$cid"                                                           204
+
+
+######### SMOKE TESTS WITHOUT DOCKER.IO ENFORCEMENT
+
+# Note that we need to restart the service with a custom containers.conf to
+# disable the docker.io enforcement.
+
+stop_service
+CONTAINERS_CONF=$(pwd)/test/apiv2/containers.conf start_service
+
+t POST   "images/create?fromImage=quay.io/libpod/alpine:latest"       200 .error~null .status~".*Download complete.*"
+t POST   "images/alpine/tag?repo=foo"                                 201
+t GET    "images/localhost/foo:latest/get"                            200
+t DELETE "images/foo"                                                 200
+t GET    "images/alpine/history"                                      200
+t POST   "images/alpine/push?destination=localhost:9999/do/not:exist" 200 # Error is in the response
+t POST   "containers/create" Image=alpine                             201
+cid=$(jq -r '.Id' <<<"$output")
+t POST   "commit?container=$cid&repo=foo&tag=tag"                     201
+t DELETE "images/localhost/foo:tag"                                   200
+t DELETE "containers/$cid"                                            204
+
+test_build alpine bar "localhost/bar:latest"
+
+
+stop_service
+start_service
diff --git a/test/apiv2/containers.conf b/test/apiv2/containers.conf
new file mode 100644
index 0000000000..24762192f6
--- /dev/null
+++ b/test/apiv2/containers.conf
@@ -0,0 +1,8 @@
+# This containers.conf file is used to test enforcing short-name resolution to
+# docker.io for Podman's *compat* API.  By default, the compat API defaults to
+# resolving to docker.io only.  The behavior can be altered by configuring the
+# containers.conf as done below in which case short names are subject to aliases,
+# "localhost/" and the unqualified-search registries.
+
+[engine]
+compat_api_enforce_docker_hub=false
diff --git a/vendor/github.com/containers/common/libimage/search.go b/vendor/github.com/containers/common/libimage/search.go
index ece81531a4..33a4776ce3 100644
--- a/vendor/github.com/containers/common/libimage/search.go
+++ b/vendor/github.com/containers/common/libimage/search.go
@@ -58,6 +58,10 @@ type SearchOptions struct {
 	InsecureSkipTLSVerify types.OptionalBool
 	// ListTags returns the search result with available tags
 	ListTags bool
+	// Registries to search if the specified term does not include a
+	// registry.  If set, the unqualified-search registries in
+	// containers-registries.conf(5) are ignored.
+	Registries []string
 }
 
 // SearchFilter allows filtering images while searching.
@@ -105,6 +109,10 @@ func ParseSearchFilter(filter []string) (*SearchFilter, error) {
 	return sFilter, nil
 }
 
+// Search searches term.  If term includes a registry, only this registry will
+// be used for searching.  Otherwise, the unqualified-search registries in
+// containers-registries.conf(5) or the ones specified in the options will be
+// used.
 func (r *Runtime) Search(ctx context.Context, term string, options *SearchOptions) ([]SearchResult, error) {
 	if options == nil {
 		options = &SearchOptions{}
@@ -117,10 +125,14 @@ func (r *Runtime) Search(ctx context.Context, term string, options *SearchOption
 	// that we cannot use the reference parser from the containers/image
 	// library as the search term may container arbitrary input such as
 	// wildcards.  See bugzilla.redhat.com/show_bug.cgi?id=1846629.
-	if spl := strings.SplitN(term, "/", 2); len(spl) > 1 {
-		searchRegistries = append(searchRegistries, spl[0])
+	spl := strings.SplitN(term, "/", 2)
+	switch {
+	case len(spl) > 1:
+		searchRegistries = []string{spl[0]}
 		term = spl[1]
-	} else {
+	case len(options.Registries) > 0:
+		searchRegistries = options.Registries
+	default:
 		regs, err := sysregistriesv2.UnqualifiedSearchRegistries(r.systemContextCopy())
 		if err != nil {
 			return nil, err
diff --git a/vendor/github.com/containers/image/v5/copy/copy.go b/vendor/github.com/containers/image/v5/copy/copy.go
index e1649ba8e1..317f8922a5 100644
--- a/vendor/github.com/containers/image/v5/copy/copy.go
+++ b/vendor/github.com/containers/image/v5/copy/copy.go
@@ -80,13 +80,13 @@ type copier struct {
 
 // imageCopier tracks state specific to a single image (possibly an item of a manifest list)
 type imageCopier struct {
-	c                  *copier
-	manifestUpdates    *types.ManifestUpdateOptions
-	src                types.Image
-	diffIDsAreNeeded   bool
-	canModifyManifest  bool
-	canSubstituteBlobs bool
-	ociEncryptLayers   *[]int
+	c                          *copier
+	manifestUpdates            *types.ManifestUpdateOptions
+	src                        types.Image
+	diffIDsAreNeeded           bool
+	cannotModifyManifestReason string // The reason the manifest cannot be modified, or an empty string if it can
+	canSubstituteBlobs         bool
+	ociEncryptLayers           *[]int
 }
 
 const (
@@ -129,10 +129,14 @@ type Options struct {
 	DestinationCtx   *types.SystemContext
 	ProgressInterval time.Duration                 // time to wait between reports to signal the progress channel
 	Progress         chan types.ProgressProperties // Reported to when ProgressInterval has arrived for a single artifact+offset.
+
+	// Preserve digests, and fail if we cannot.
+	PreserveDigests bool
 	// manifest MIME type of image set by user. "" is default and means use the autodetection to the the manifest MIME type
 	ForceManifestMIMEType string
 	ImageListSelection    ImageListSelection // set to either CopySystemImage (the default), CopyAllImages, or CopySpecificImages to control which instances we copy when the source reference is a list; ignored if the source reference is not a list
 	Instances             []digest.Digest    // if ImageListSelection is CopySpecificImages, copy only these instances and the list itself
+
 	// If OciEncryptConfig is non-nil, it indicates that an image should be encrypted.
 	// The encryption options is derived from the construction of EncryptConfig object.
 	// Note: During initial encryption process of a layer, the resultant digest is not known
@@ -410,7 +414,36 @@ func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signatur
 			return nil, errors.Wrapf(err, "Can not copy signatures to %s", transports.ImageName(c.dest.Reference()))
 		}
 	}
-	canModifyManifestList := (len(sigs) == 0)
+
+	// If the destination is a digested reference, make a note of that, determine what digest value we're
+	// expecting, and check that the source manifest matches it.
+	destIsDigestedReference := false
+	if named := c.dest.Reference().DockerReference(); named != nil {
+		if digested, ok := named.(reference.Digested); ok {
+			destIsDigestedReference = true
+			matches, err := manifest.MatchesDigest(manifestList, digested.Digest())
+			if err != nil {
+				return nil, errors.Wrapf(err, "computing digest of source image's manifest")
+			}
+			if !matches {
+				return nil, errors.New("Digest of source image's manifest would not match destination reference")
+			}
+		}
+	}
+
+	// Determine if we're allowed to modify the manifest list.
+	// If we can, set to the empty string. If we can't, set to the reason why.
+	// Compare, and perhaps keep in sync with, the version in copyOneImage.
+	cannotModifyManifestListReason := ""
+	if len(sigs) > 0 {
+		cannotModifyManifestListReason = "Would invalidate signatures"
+	}
+	if destIsDigestedReference {
+		cannotModifyManifestListReason = "Destination specifies a digest"
+	}
+	if options.PreserveDigests {
+		cannotModifyManifestListReason = "Instructed to preserve digests"
+	}
 
 	// Determine if we'll need to convert the manifest list to a different format.
 	forceListMIMEType := options.ForceManifestMIMEType
@@ -425,8 +458,8 @@ func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signatur
 		return nil, errors.Wrapf(err, "determining manifest list type to write to destination")
 	}
 	if selectedListType != originalList.MIMEType() {
-		if !canModifyManifestList {
-			return nil, errors.Errorf("manifest list must be converted to type %q to be written to destination, but that would invalidate signatures", selectedListType)
+		if cannotModifyManifestListReason != "" {
+			return nil, errors.Errorf("Manifest list must be converted to type %q to be written to destination, but we cannot modify it: %q", selectedListType, cannotModifyManifestListReason)
 		}
 	}
 
@@ -510,8 +543,8 @@ func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signatur
 
 		// If we can't just use the original value, but we have to change it, flag an error.
 		if !bytes.Equal(attemptedManifestList, originalManifestList) {
-			if !canModifyManifestList {
-				return nil, errors.Errorf(" manifest list must be converted to type %q to be written to destination, but that would invalidate signatures", thisListType)
+			if cannotModifyManifestListReason != "" {
+				return nil, errors.Errorf("Manifest list must be converted to type %q to be written to destination, but we cannot modify it: %q", thisListType, cannotModifyManifestListReason)
 			}
 			logrus.Debugf("Manifest list has been updated")
 		} else {
@@ -629,13 +662,27 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
 		}
 	}
 
+	// Determine if we're allowed to modify the manifest.
+	// If we can, set to the empty string. If we can't, set to the reason why.
+	// Compare, and perhaps keep in sync with, the version in copyMultipleImages.
+	cannotModifyManifestReason := ""
+	if len(sigs) > 0 {
+		cannotModifyManifestReason = "Would invalidate signatures"
+	}
+	if destIsDigestedReference {
+		cannotModifyManifestReason = "Destination specifies a digest"
+	}
+	if options.PreserveDigests {
+		cannotModifyManifestReason = "Instructed to preserve digests"
+	}
+
 	ic := imageCopier{
 		c:               c,
 		manifestUpdates: &types.ManifestUpdateOptions{InformationOnly: types.ManifestUpdateInformation{Destination: c.dest}},
 		src:             src,
 		// diffIDsAreNeeded is computed later
-		canModifyManifest: len(sigs) == 0 && !destIsDigestedReference,
-		ociEncryptLayers:  options.OciEncryptLayers,
+		cannotModifyManifestReason: cannotModifyManifestReason,
+		ociEncryptLayers:           options.OciEncryptLayers,
 	}
 	// Ensure _this_ copy sees exactly the intended data when either processing a signed image or signing it.
 	// This may be too conservative, but for now, better safe than sorry, _especially_ on the SignBy path:
@@ -643,7 +690,7 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
 	// We do intend the RecordDigestUncompressedPair calls to only work with reliable data, but at least there’s a risk
 	// that the compressed version coming from a third party may be designed to attack some other decompressor implementation,
 	// and we would reuse and sign it.
-	ic.canSubstituteBlobs = ic.canModifyManifest && options.SignBy == ""
+	ic.canSubstituteBlobs = ic.cannotModifyManifestReason == "" && options.SignBy == ""
 
 	if err := ic.updateEmbeddedDockerReference(); err != nil {
 		return nil, "", "", err
@@ -710,10 +757,10 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
 		}
 		// If the original MIME type is acceptable, determineManifestConversion always uses it as preferredManifestMIMEType.
 		// So if we are here, we will definitely be trying to convert the manifest.
-		// With !ic.canModifyManifest, that would just be a string of repeated failures for the same reason,
+		// With ic.cannotModifyManifestReason != "", that would just be a string of repeated failures for the same reason,
 		// so let’s bail out early and with a better error message.
-		if !ic.canModifyManifest {
-			return nil, "", "", errors.Wrap(err, "Writing manifest failed (and converting it is not possible, image is signed or the destination specifies a digest)")
+		if ic.cannotModifyManifestReason != "" {
+			return nil, "", "", errors.Wrapf(err, "Writing manifest failed and we cannot try conversions: %q", cannotModifyManifestReason)
 		}
 
 		// errs is a list of errors when trying various manifest types. Also serves as an "upload succeeded" flag when set to nil.
@@ -813,9 +860,9 @@ func (ic *imageCopier) updateEmbeddedDockerReference() error {
 		return nil // No reference embedded in the manifest, or it matches destRef already.
 	}
 
-	if !ic.canModifyManifest {
-		return errors.Errorf("Copying a schema1 image with an embedded Docker reference to %s (Docker reference %s) would change the manifest, which is not possible (image is signed or the destination specifies a digest)",
-			transports.ImageName(ic.c.dest.Reference()), destRef.String())
+	if ic.cannotModifyManifestReason != "" {
+		return errors.Errorf("Copying a schema1 image with an embedded Docker reference to %s (Docker reference %s) would change the manifest, which we cannot do: %q",
+			transports.ImageName(ic.c.dest.Reference()), destRef.String(), ic.cannotModifyManifestReason)
 	}
 	ic.manifestUpdates.EmbeddedDockerReference = destRef
 	return nil
@@ -833,7 +880,7 @@ func isTTY(w io.Writer) bool {
 	return false
 }
 
-// copyLayers copies layers from ic.src/ic.c.rawSource to dest, using and updating ic.manifestUpdates if necessary and ic.canModifyManifest.
+// copyLayers copies layers from ic.src/ic.c.rawSource to dest, using and updating ic.manifestUpdates if necessary and ic.cannotModifyManifestReason == "".
 func (ic *imageCopier) copyLayers(ctx context.Context) error {
 	srcInfos := ic.src.LayerInfos()
 	numLayers := len(srcInfos)
@@ -844,8 +891,8 @@ func (ic *imageCopier) copyLayers(ctx context.Context) error {
 	srcInfosUpdated := false
 	// If we only need to check authorization, no updates required.
 	if updatedSrcInfos != nil && !reflect.DeepEqual(srcInfos, updatedSrcInfos) {
-		if !ic.canModifyManifest {
-			return errors.Errorf("Copying this image requires changing layer representation, which is not possible (image is signed or the destination specifies a digest)")
+		if ic.cannotModifyManifestReason != "" {
+			return errors.Errorf("Copying this image would require changing layer representation, which we cannot do: %q", ic.cannotModifyManifestReason)
 		}
 		srcInfos = updatedSrcInfos
 		srcInfosUpdated = true
@@ -975,8 +1022,8 @@ func layerDigestsDiffer(a, b []types.BlobInfo) bool {
 func (ic *imageCopier) copyUpdatedConfigAndManifest(ctx context.Context, instanceDigest *digest.Digest) ([]byte, digest.Digest, error) {
 	pendingImage := ic.src
 	if !ic.noPendingManifestUpdates() {
-		if !ic.canModifyManifest {
-			return nil, "", errors.Errorf("Internal error: copy needs an updated manifest but that was known to be forbidden")
+		if ic.cannotModifyManifestReason != "" {
+			return nil, "", errors.Errorf("Internal error: copy needs an updated manifest but that was known to be forbidden: %q", ic.cannotModifyManifestReason)
 		}
 		if !ic.diffIDsAreNeeded && ic.src.UpdatedImageNeedsLayerDiffIDs(*ic.manifestUpdates) {
 			// We have set ic.diffIDsAreNeeded based on the preferred MIME type returned by determineManifestConversion.
@@ -1359,7 +1406,7 @@ func (ic *imageCopier) copyLayerFromStream(ctx context.Context, srcStream io.Rea
 		}
 	}
 
-	blobInfo, err := ic.c.copyBlobFromStream(ctx, srcStream, srcInfo, getDiffIDRecorder, ic.canModifyManifest, false, toEncrypt, bar, layerIndex, emptyLayer) // Sets err to nil on success
+	blobInfo, err := ic.c.copyBlobFromStream(ctx, srcStream, srcInfo, getDiffIDRecorder, ic.cannotModifyManifestReason == "", false, toEncrypt, bar, layerIndex, emptyLayer) // Sets err to nil on success
 	return blobInfo, diffIDChan, err
 	// We need the defer … pipeWriter.CloseWithError() to happen HERE so that the caller can block on reading from diffIDChan
 }
diff --git a/vendor/github.com/containers/image/v5/copy/manifest.go b/vendor/github.com/containers/image/v5/copy/manifest.go
index b97edbf08b..86ec8863ae 100644
--- a/vendor/github.com/containers/image/v5/copy/manifest.go
+++ b/vendor/github.com/containers/image/v5/copy/manifest.go
@@ -79,10 +79,10 @@ func (ic *imageCopier) determineManifestConversion(ctx context.Context, destSupp
 	if _, ok := supportedByDest[srcType]; ok {
 		prioritizedTypes.append(srcType)
 	}
-	if !ic.canModifyManifest {
-		// We could also drop the !ic.canModifyManifest check and have the caller
+	if ic.cannotModifyManifestReason != "" {
+		// We could also drop this check and have the caller
 		// make the choice; it is already doing that to an extent, to improve error
-		// messages.  But it is nice to hide the “if !ic.canModifyManifest, do no conversion”
+		// messages.  But it is nice to hide the “if we can't modify, do no conversion”
 		// special case in here; the caller can then worry (or not) only about a good UI.
 		logrus.Debugf("We can't modify the manifest, hoping for the best...")
 		return srcType, []string{}, nil // Take our chances - FIXME? Or should we fail without trying?
diff --git a/vendor/github.com/containers/image/v5/pkg/shortnames/shortnames.go b/vendor/github.com/containers/image/v5/pkg/shortnames/shortnames.go
index fb0a15b993..46c10ff631 100644
--- a/vendor/github.com/containers/image/v5/pkg/shortnames/shortnames.go
+++ b/vendor/github.com/containers/image/v5/pkg/shortnames/shortnames.go
@@ -118,6 +118,7 @@ type Resolved struct {
 }
 
 func (r *Resolved) addCandidate(named reference.Named) {
+	named = reference.TagNameOnly(named) // Make sure to add ":latest" if needed
 	r.PullCandidates = append(r.PullCandidates, PullCandidate{named, false, r})
 }
 
@@ -138,6 +139,8 @@ const (
 	rationaleUSR
 	// Resolved value has been selected by the user (via the prompt).
 	rationaleUserSelection
+	// Resolved value has been enforced to use Docker Hub (via SystemContext).
+	rationaleEnforcedDockerHub
 )
 
 // Description returns a human-readable description about the resolution
@@ -152,6 +155,8 @@ func (r *Resolved) Description() string {
 		return fmt.Sprintf("Resolved %q as an alias (%s)", r.userInput, r.originDescription)
 	case rationaleUSR:
 		return fmt.Sprintf("Resolving %q using unqualified-search registries (%s)", r.userInput, r.originDescription)
+	case rationaleEnforcedDockerHub:
+		return fmt.Sprintf("Resolving %q to docker.io (%s)", r.userInput, r.originDescription)
 	case rationaleUserSelection, rationaleNone:
 		fallthrough
 	default:
@@ -265,8 +270,20 @@ func Resolve(ctx *types.SystemContext, name string) (*Resolved, error) {
 		return nil, err
 	}
 	if !isShort { // no short name
-		named := reference.TagNameOnly(shortRef) // Make sure to add ":latest" if needed
+		resolved.addCandidate(shortRef)
+		return resolved, nil
+	}
+
+	// Resolve to docker.io only if enforced by the caller (e.g., Podman's
+	// Docker-compatible REST API).
+	if ctx != nil && ctx.PodmanOnlyShortNamesIgnoreRegistriesConfAndForceDockerHub {
+		named, err := reference.ParseNormalizedNamed(name)
+		if err != nil {
+			return nil, errors.Wrapf(err, "cannot normalize input: %q", name)
+		}
 		resolved.addCandidate(named)
+		resolved.rationale = rationaleEnforcedDockerHub
+		resolved.originDescription = "enforced by caller"
 		return resolved, nil
 	}
 
@@ -295,9 +312,6 @@ func Resolve(ctx *types.SystemContext, name string) (*Resolved, error) {
 				return nil, err
 			}
 		}
-		// Make sure to add ":latest" if needed
-		namedAlias = reference.TagNameOnly(namedAlias)
-
 		resolved.addCandidate(namedAlias)
 		resolved.rationale = rationaleAlias
 		resolved.originDescription = aliasOriginDescription
@@ -325,9 +339,6 @@ func Resolve(ctx *types.SystemContext, name string) (*Resolved, error) {
 		if err != nil {
 			return nil, errors.Wrapf(err, "creating reference with unqualified-search registry %q", reg)
 		}
-		// Make sure to add ":latest" if needed
-		named = reference.TagNameOnly(named)
-
 		resolved.addCandidate(named)
 	}
 
@@ -412,6 +423,23 @@ func ResolveLocally(ctx *types.SystemContext, name string) ([]reference.Named, e
 
 	var candidates []reference.Named
 
+	// Complete the candidates with the specified registries.
+	completeCandidates := func(registries []string) ([]reference.Named, error) {
+		for _, reg := range registries {
+			named, err := reference.ParseNormalizedNamed(fmt.Sprintf("%s/%s", reg, name))
+			if err != nil {
+				return nil, errors.Wrapf(err, "creating reference with unqualified-search registry %q", reg)
+			}
+			named = reference.TagNameOnly(named) // Make sure to add ":latest" if needed
+			candidates = append(candidates, named)
+		}
+		return candidates, nil
+	}
+
+	if ctx != nil && ctx.PodmanOnlyShortNamesIgnoreRegistriesConfAndForceDockerHub {
+		return completeCandidates([]string{"docker.io"})
+	}
+
 	// Strip off the tag to normalize the short name for looking it up in
 	// the config files.
 	isTagged, isDigested, shortNameRepo, tag, digest := splitUserInput(shortRef)
@@ -434,9 +462,7 @@ func ResolveLocally(ctx *types.SystemContext, name string) ([]reference.Named, e
 				return nil, err
 			}
 		}
-		// Make sure to add ":latest" if needed
-		namedAlias = reference.TagNameOnly(namedAlias)
-
+		namedAlias = reference.TagNameOnly(namedAlias) // Make sure to add ":latest" if needed
 		candidates = append(candidates, namedAlias)
 	}
 
@@ -447,16 +473,5 @@ func ResolveLocally(ctx *types.SystemContext, name string) ([]reference.Named, e
 	}
 
 	// Note that "localhost" has precedence over the unqualified-search registries.
-	for _, reg := range append([]string{"localhost"}, unqualifiedSearchRegistries...) {
-		named, err := reference.ParseNormalizedNamed(fmt.Sprintf("%s/%s", reg, name))
-		if err != nil {
-			return nil, errors.Wrapf(err, "creating reference with unqualified-search registry %q", reg)
-		}
-		// Make sure to add ":latest" if needed
-		named = reference.TagNameOnly(named)
-
-		candidates = append(candidates, named)
-	}
-
-	return candidates, nil
+	return completeCandidates(append([]string{"localhost"}, unqualifiedSearchRegistries...))
 }
diff --git a/vendor/github.com/containers/image/v5/types/types.go b/vendor/github.com/containers/image/v5/types/types.go
index c98a6c6fda..dcff8caf76 100644
--- a/vendor/github.com/containers/image/v5/types/types.go
+++ b/vendor/github.com/containers/image/v5/types/types.go
@@ -561,6 +561,11 @@ type SystemContext struct {
 	UserShortNameAliasConfPath string
 	// If set, short-name resolution in pkg/shortnames must follow the specified mode
 	ShortNameMode *ShortNameMode
+	// If set, short names will resolve in pkg/shortnames to docker.io only, and unqualified-search registries and
+	// short-name aliases in registries.conf are ignored.  Note that this field is only intended to help enforce
+	// resolving to Docker Hub in the Docker-compatible REST API of Podman; it should never be used outside this
+	// specific context.
+	PodmanOnlyShortNamesIgnoreRegistriesConfAndForceDockerHub bool
 	// If not "", overrides the default path for the authentication file, but only new format files
 	AuthFilePath string
 	// if not "", overrides the default path for the authentication file, but with the legacy format;
diff --git a/vendor/github.com/containers/image/v5/version/version.go b/vendor/github.com/containers/image/v5/version/version.go
index ffb2a4ce25..17639f0d4e 100644
--- a/vendor/github.com/containers/image/v5/version/version.go
+++ b/vendor/github.com/containers/image/v5/version/version.go
@@ -8,10 +8,10 @@ const (
 	// VersionMinor is for functionality in a backwards-compatible manner
 	VersionMinor = 17
 	// VersionPatch is for backwards-compatible bug fixes
-	VersionPatch = 0
+	VersionPatch = 1
 
 	// VersionDev indicates development branch. Releases will be empty string.
-	VersionDev = ""
+	VersionDev = "-dev"
 )
 
 // Version is the specification version that the package types support.
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 701c3f73a2..a104465c67 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -106,7 +106,7 @@ github.com/containers/buildah/pkg/rusage
 github.com/containers/buildah/pkg/sshagent
 github.com/containers/buildah/pkg/util
 github.com/containers/buildah/util
-# github.com/containers/common v0.46.1-0.20211122213330-d4e7724a0c58
+# github.com/containers/common v0.46.1-0.20211125160015-ccf46abecd91
 ## explicit
 github.com/containers/common/libimage
 github.com/containers/common/libimage/manifests
@@ -142,7 +142,7 @@ github.com/containers/common/version
 # github.com/containers/conmon v2.0.20+incompatible
 ## explicit
 github.com/containers/conmon/runner/config
-# github.com/containers/image/v5 v5.17.0
+# github.com/containers/image/v5 v5.17.1-0.20211129144953-4f6d0b45be6c
 ## explicit
 github.com/containers/image/v5/copy
 github.com/containers/image/v5/directory