17478601 provide a pkg(5) private module to compute SHA512/256
authorYiteng Zhang <yiteng.zhang@oracle.com>
Fri, 04 Apr 2014 18:29:53 -0700
changeset 3053 7c1dfe878489
parent 3052 443449993da1
child 3054 37c6fdddacac
17478601 provide a pkg(5) private module to compute SHA512/256
src/depot.py
src/modules/digest.py
src/modules/misc.py
src/modules/server/depot.py
src/modules/sha512_t.c
src/pkg/manifests/package:pkg.p5m
src/setup.py
src/tests/api/t_sha512_t.py
src/tests/cli/t_pkg_install.py
src/tests/cli/t_pkg_revert.py
src/tests/cli/t_pkg_search.py
src/tests/cli/t_pkg_sysrepo.py
src/tests/cli/t_pkgrecv.py
src/tests/cli/t_pkgrepo.py
src/tests/cli/t_pkgsend.py
src/tests/cli/t_pkgsign.py
src/tests/pkg5unittest.py
--- a/src/depot.py	Wed Apr 02 17:51:09 2014 -0700
+++ b/src/depot.py	Fri Apr 04 18:29:53 2014 -0700
@@ -19,7 +19,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
 #
 
 # pkg.depotd - package repository daemon
@@ -168,7 +168,7 @@
         --debug         The name of a debug feature to enable; or a whitespace
                         or comma separated list of features to enable.
                         Possible values are: headers, hash=sha1+sha256,
-                        hash=sha256
+                        hash=sha256, hash=sha1+sha512_256, hash=sha512_256
         --image-root    The path to the image whose file information will be
                         used as a cache for file data.
         --log-access    The destination for any access related information
--- a/src/modules/digest.py	Wed Apr 02 17:51:09 2014 -0700
+++ b/src/modules/digest.py	Fri Apr 04 18:29:53 2014 -0700
@@ -21,10 +21,15 @@
 #
 
 #
-# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
 #
 
 import hashlib
+try:
+        import pkg.sha512_t
+        sha512_supported = True
+except ImportError:
+        sha512_supported = False
 
 # When running the test suite, we alter our behaviour depending on certain
 # debug flags.
@@ -70,7 +75,16 @@
 # using the "most preferred" hash. See get_preferred_hash(..),
 # get_least_preferred_hash(..) and get_common_preferred_hash(..)
 #
-if DebugValues["hash"] == "sha1+sha256":
+if DebugValues["hash"] == "sha1+sha512_256":
+        # Simulate pkg(5) where SHA-1 and SHA-512/256 are used for publication
+        DEFAULT_HASH_ATTRS = ["hash", "pkg.hash.sha512_256"]
+        DEFAULT_CHASH_ATTRS = ["chash", "pkg.chash.sha512_256"]
+        DEFAULT_CONTENT_HASH_ATTRS = ["elfhash", "pkg.content-hash.sha512_256"]
+        DEFAULT_CHAIN_ATTRS = ["chain", "pkg.chain.sha512_256"]
+        DEFAULT_CHAIN_CHASH_ATTRS = ["chain.chashes",
+            "pkg.chain.chashes.sha512_256"]
+
+elif DebugValues["hash"] == "sha1+sha256":
         # Simulate pkg(5) where SHA-1 and SHA-256 are used for publication
         DEFAULT_HASH_ATTRS = ["hash", "pkg.hash.sha256"]
         DEFAULT_CHASH_ATTRS = ["chash", "pkg.chash.sha256"]
@@ -79,6 +93,14 @@
         DEFAULT_CHAIN_CHASH_ATTRS = ["chain.chashes",
             "pkg.chain.chashes.sha256"]
 
+elif DebugValues["hash"] == "sha512_256":
+        # Simulate pkg(5) where SHA-1 is no longer used for publication
+        DEFAULT_HASH_ATTRS = ["pkg.hash.sha512_256"]
+        DEFAULT_CHASH_ATTRS = ["pkg.chash.sha512_256"]
+        DEFAULT_CONTENT_HASH_ATTRS = ["pkg.content-hash.sha512_256"]
+        DEFAULT_CHAIN_ATTRS = ["pkg.chain.sha512_256"]
+        DEFAULT_CHAIN_CHASH_ATTRS = ["pkg.chain.chashes.sha512_256"]
+
 elif DebugValues["hash"] == "sha256":
         # Simulate pkg(5) where SHA-1 is no longer used for publication
         DEFAULT_HASH_ATTRS = ["pkg.hash.sha256"]
@@ -111,7 +133,7 @@
 # value being computed with this data, along with a 'hexdigest()' method to
 # return the hexadecimal value of the hash.
 #
-# At present, these are all hashlib factory methods. When maintaining these
+# At present, some of these are hashlib factory methods. When maintaining these
 # dictionaries, it is important to *never remove* entries from them, otherwise
 # clients with installed packages will not be able to verify their content when
 # pkg(5) is updated.
@@ -126,6 +148,9 @@
             "pkg.hash.sha256": hashlib.sha256,
         }
 
+        if sha512_supported:
+                HASH_ALGS["pkg.hash.sha512_256"] = pkg.sha512_t.SHA512_t
+
 # A dictionary of the compressed hash attributes we know about.
 CHASH_ALGS = {}
 for key in HASH_ALGS:
@@ -164,13 +189,21 @@
 if DebugValues["hash"] == "sha1":
         RANKED_HASH_ATTRS = ("hash")
 elif DebugValues["hash"] == "sha2":
-        RANKED_HASH_ATTRS = ("pkg.hash.sha256")
+        if sha512_supported:
+                RANKED_HASH_ATTRS = ("pkg.hash.sha512_256",)
+        else:
+                RANKED_HASH_ATTRS = ("pkg.hash.sha256",)
 else:
         RANKED_HASH_ATTRS = (
             "pkg.hash.sha256",
             "hash",
         )
 
+        if sha512_supported:
+                RANKED_HASH_ATTRS = (
+                    "pkg.hash.sha512_256",
+                ) + RANKED_HASH_ATTRS
+
 RANKED_CHASH_ATTRS = tuple(key.replace("hash", "chash")
     for key in RANKED_HASH_ATTRS)
 _content_hash_attrs = []
--- a/src/modules/misc.py	Wed Apr 02 17:51:09 2014 -0700
+++ b/src/modules/misc.py	Fri Apr 04 18:29:53 2014 -0700
@@ -560,8 +560,7 @@
         for this data. The keys must be present in 'hash_algs', a dictionary
         mapping keys to the factory methods that are used to create objects
         to compute them. The factory method must take no parameters, and must
-        return an object that has 'update()' and 'hexdigest()' methods. In the
-        current implementation, these are all hashlib factory methods.
+        return an object that has 'update()' and 'hexdigest()' methods.
 
         'hash_func' is provided as a convenience to simply hash the data with
         a single hash algorithm. The value of 'hash_func' should be the factory
@@ -581,7 +580,7 @@
                 length = os.stat(data).st_size
 
         # Setup our results dictionary so that each attribute maps to a
-        # new hashlib object.
+        # new hash object.
         if hash_func:
                 hsh = hash_func()
         else:
@@ -618,7 +617,7 @@
                 return hsh.hexdigest(), content.read()
 
         # The returned dictionary can now be populated with the hexdigests
-        # instead of the hashlib objects themselves.
+        # instead of the hash objects themselves.
         for attr in hash_results:
                 hash_results[attr] = hash_results[attr].hexdigest()
         return hash_results, content.read()
--- a/src/modules/server/depot.py	Wed Apr 02 17:51:09 2014 -0700
+++ b/src/modules/server/depot.py	Fri Apr 04 18:29:53 2014 -0700
@@ -21,7 +21,7 @@
 #
 
 #
-# Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
 #
 
 import cherrypy
@@ -2373,7 +2373,8 @@
                     cfg.PropDefined("cfg_file", allowed=["", "<pathname>"]),
                     cfg.Property("content_root"),
                     cfg.PropList("debug", allowed=["", "headers",
-                        "hash=sha256", "hash=sha1+sha256"]),
+                        "hash=sha256", "hash=sha1+sha256", "hash=sha512_256",
+                        "hash=sha1+sha512_256"]),
                     cfg.PropList("disable_ops"),
                     cfg.PropDefined("image_root", allowed=["",
                         "<abspathname>"]),
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/modules/sha512_t.c	Fri Apr 04 18:29:53 2014 -0700
@@ -0,0 +1,272 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ *  Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <Python.h>
+#include <sha2.h>
+#include "structmember.h"
+
+/*
+ * A hash module computes SHA512/t. Now it only supports SHA512/256 and
+ * SHA512/224.
+ *
+ * The default hash function is SHA512/256. Change your hash function to
+ * SHA512/224 with the argument t=224 when you create a hash object.
+ *
+ * Hash objects have methods update(arg), digest() and hexdigest(), and an
+ * attribute hash_size.
+ *
+ * For example:
+ *
+ * >>> import pkg.sha512_t
+ * >>> a = pkg.sha512_t.SHA512_t()
+ * >>> a.update("abc")
+ * >>> a.digest()
+ * 'S\x04\x8e&\x81\x94\x1e\xf9\x9b.)\xb7kL}\xab\xe4\xc2\xd0\xc64\xfcmF\xe0\xe2
+ * \xf11\x07\xe7\xaf#'
+ * More condensed:
+ *
+ * >>> pkg.sha512_t.SHA512_t("abc").hexdigest()
+ * '53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23'
+ *
+ * >>> pkg.sha512_t.SHA512_t(t=224).hexdigest()
+ * '4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa'
+ *
+ */
+
+typedef struct {
+	PyObject_HEAD
+	SHA512_CTX shc;
+	int hash_size;
+} SHA512_t_Object;
+
+static void
+py_dealloc(SHA512_t_Object* self)
+{
+	self->ob_type->tp_free((PyObject*)self);
+}
+
+/*
+ * Create an SHA512_t object, with optional arguments: string message and
+ * hash size.
+ *
+ */
+
+/*ARGSUSED*/
+static int
+py_init(SHA512_t_Object *self, PyObject *args, PyObject *kwds)
+{
+	PyObject *strObj = NULL;
+	char *message;
+	/* Default hash algorithm is SHA512/256. */
+	self->hash_size = 256;
+	static char *kwlist[] = {"message", "t", NULL};
+
+	if (PyArg_ParseTupleAndKeywords(args, kwds, "|Si", kwlist,
+	    &strObj, &self->hash_size) == 0)
+		return (-1);
+
+	if (self->hash_size != 256 && self->hash_size != 224) {
+		PyErr_SetString(PyExc_ValueError, "The module "
+		    "only supports SHA512/256 or SHA512/224.\n");
+		return (-1);
+	}
+
+	SHA512_t_Init(self->hash_size, &self->shc);
+	if (strObj != NULL) {
+		if ((message = PyBytes_AsString(strObj)) == NULL)
+			return (-1);
+		SHA512_t_Update(&self->shc, message, strlen(message));
+	}
+	return (0);
+}
+
+/*
+ * Update the hash object with a string object. Repeated calls are equivalent
+ * to a single call with the concatenation of all the strings.
+ *
+ */
+
+static char py_update_doc[] = "\n\
+Update the hash object with the string arguments.\n\
+\n\
+@param message: input message to digest\n\
+\n\
+@return: None\n\
+";
+
+/*ARGSUSED*/
+static PyObject *
+py_update(SHA512_t_Object* self, PyObject *args)
+{
+	PyObject *strObj = NULL;
+	char *message;
+
+	if (!PyArg_ParseTuple(args, "S", &strObj))
+		return (NULL);
+
+	if (strObj != NULL) {
+		if ((message = PyBytes_AsString(strObj)) == NULL)
+			return (NULL);
+		SHA512_t_Update(&self->shc, message, strlen(message));
+	}
+	Py_RETURN_NONE;
+}
+
+/*
+ * Return the digest of the strings passed to the py_update() method so far.
+ *
+ */
+
+static char py_digest_doc[] = "\n\
+Return the digest of the strings passed to the update() method so far.\n\
+\n\
+@return: string of digest of messages\n\
+";
+
+/*ARGSUSED*/
+static PyObject *
+py_digest(SHA512_t_Object* self, PyObject *args)
+{
+	int size = self->hash_size / 8;
+	unsigned char buffer[size];
+	SHA512_CTX shc;
+	shc = self->shc;
+	SHA512_t_Final(buffer, &shc);
+	return (PyString_FromStringAndSize((const char *)buffer, size));
+}
+
+/*
+ * Return a string with a hex representation of the digest of the strings
+ * passed to the py_update() method so far.
+ *
+ */
+
+static char py_hexdigest_doc[] = "\n\
+Return hexadecimal digest of the strings passed to the update() method\
+so far.\n\
+\n\
+@return: string of double length and hexadecimal digest of the messages\n\
+";
+
+/*ARGSUSED*/
+static PyObject *
+py_hexdigest(SHA512_t_Object* self, PyObject *args)
+{
+	int i;
+	int buffer_size = self->hash_size / 8;
+	int result_size = self->hash_size / 4;
+	unsigned char buffer[buffer_size];
+	unsigned char result[result_size];
+	char hexchars[16] = "0123456789abcdef";
+	SHA512_CTX shc;
+	shc = self->shc;
+	SHA512_t_Final(buffer, &shc);
+	for (i = 0; i < buffer_size; i++) {
+		result[2 * i] = \
+		    hexchars[(buffer[i] & 0xf0) >> 4];
+		result[2 * i + 1] = \
+		    hexchars[buffer[i] & 0x0f];
+	}
+	return (PyString_FromStringAndSize((const char *)result, result_size));
+}
+
+static PyMemberDef SHA512_t_members[] = {
+	{ "hash_size", T_INT, offsetof(SHA512_t_Object, hash_size), 0,
+	    "hash size"},
+	{ NULL }  /* Sentinel */
+};
+
+static PyMethodDef SHA512_t_methods[] = {
+	{ "update", (PyCFunction)py_update, METH_VARARGS,
+	    py_update_doc },
+	{ "digest", (PyCFunction)py_digest, METH_NOARGS,
+	    py_digest_doc },
+	{ "hexdigest", (PyCFunction)py_hexdigest, METH_NOARGS,
+	    py_hexdigest_doc },
+	{ NULL }  /* Sentinel */
+};
+
+static PyTypeObject SHA512_t_Type = {
+	PyObject_HEAD_INIT(NULL)
+	0,	/* ob_size */
+	"sha512_t.SHA512_t",	/* tp_name */
+	sizeof (SHA512_t_Object),	/* tp_basicsize */
+	0,	/* tp_itemsize */
+	(destructor)py_dealloc,	/* tp_dealloc */
+	0,	/* tp_print */
+	0,	/* tp_getattr */
+	0,	/* tp_setattr */
+	0,	/* tp_compare */
+	0,	/* tp_repr */
+	0,	/* tp_as_number */
+	0,	/* tp_as_sequence */
+	0,	/* tp_as_mapping */
+	0,	/* tp_hash */
+	0,	/* tp_call */
+	0,	/* tp_str */
+	0,	/* tp_getattro */
+	0,	/* tp_setattro */
+	0,	/* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+	"SHA512/t objects",	/* tp_doc */
+	0,	/* tp_traverse */
+	0,	/* tp_clear */
+	0,	/* tp_richcompare */
+	0,	/* tp_weaklistoffset */
+	0,	/* tp_iter */
+	0,	/* tp_iternext */
+	SHA512_t_methods,	/* tp_methods */
+	SHA512_t_members,	/* tp_members */
+	0,	/* tp_getset */
+	0,	/* tp_base */
+	0,	/* tp_dict */
+	0,	/* tp_descr_get */
+	0,	/* tp_descr_set */
+	0,	/* tp_dictoffset */
+	(initproc)py_init,	/* tp_init */
+};
+
+static PyMethodDef sha512_t_methods[] = {
+	{ NULL }  /* Sentinel */
+};
+
+PyMODINIT_FUNC
+initsha512_t(void)
+{
+	PyObject* m;
+
+	SHA512_t_Type.tp_new = PyType_GenericNew;
+	if (PyType_Ready(&SHA512_t_Type) < 0)
+		return;
+
+	m = Py_InitModule3("sha512_t", sha512_t_methods,
+	    "This module provides SHA512_t hashing.");
+
+	if (m == NULL)
+		return;
+
+	Py_INCREF(&SHA512_t_Type);
+	PyModule_AddObject(m, "SHA512_t", (PyObject *)&SHA512_t_Type);
+}
--- a/src/pkg/manifests/package:pkg.p5m	Wed Apr 02 17:51:09 2014 -0700
+++ b/src/pkg/manifests/package:pkg.p5m	Fri Apr 04 18:29:53 2014 -0700
@@ -34,6 +34,7 @@
 file path=$(PYDIRVP)/pkg-0.1-py2.6.egg-info
 dir  path=$(PYDIRVP)/pkg/64
 file path=$(PYDIRVP)/pkg/64/_varcet.so
+file path=$(PYDIRVP)/pkg/64/sha512_t.so
 file path=$(PYDIRVP)/pkg/64/sysattr.so
 file path=$(PYDIRVP)/pkg/__init__.py
 file path=$(PYDIRVP)/pkg/_varcet.so
@@ -193,6 +194,7 @@
 file path=$(PYDIRVP)/pkg/server/query_parser.py
 file path=$(PYDIRVP)/pkg/server/repository.py
 file path=$(PYDIRVP)/pkg/server/transaction.py
+file path=$(PYDIRVP)/pkg/sha512_t.so
 file path=$(PYDIRVP)/pkg/smf.py
 file path=$(PYDIRVP)/pkg/solver.so
 file path=$(PYDIRVP)/pkg/sysattr.so
--- a/src/setup.py	Wed Apr 02 17:51:09 2014 -0700
+++ b/src/setup.py	Fri Apr 04 18:29:53 2014 -0700
@@ -383,6 +383,9 @@
 pkg_locales = \
     'ar ca cs de es fr he hu id it ja ko nl pl pt_BR ru sk sv zh_CN zh_HK zh_TW'.split()
 
+sha512_t_srcs = [
+        'modules/sha512_t.c'
+        ]
 sysattr_srcs = [
         'modules/sysattr.c'
         ]
@@ -573,6 +576,12 @@
                             ['-I' + self.escape(get_python_inc())] + \
                             ["%s%s" % ("-l", k) for k in sysattr_libraries] + \
                             sysattr_srcs
+                        sha512_tcmd = lint + lint_flags + \
+                            ['-D_FILE_OFFSET_BITS=64'] + \
+                            ["%s%s" % ("-I", k) for k in include_dirs] + \
+                            ['-I' + self.escape(get_python_inc())] + \
+                            ["%s%s" % ("-l", k) for k in sha512_t_libraries] + \
+                            sha512_t_srcs
 
                         print(" ".join(archcmd))
                         os.system(" ".join(archcmd))
@@ -590,6 +599,8 @@
                         os.system(" ".join(syscallatcmd))
                         print(" ".join(sysattrcmd))
                         os.system(" ".join(sysattrcmd))
+                        print(" ".join(sha512_tcmd))
+                        os.system(" ".join(sha512_tcmd))
 
 
 # Runs both C and Python lint
@@ -1441,6 +1452,7 @@
         ]
 elf_libraries = None
 sysattr_libraries = None
+sha512_t_libraries = None
 data_files = web_files
 cmdclasses = {
         'install': install_func,
@@ -1527,6 +1539,7 @@
         if osname == 'sunos':
             elf_libraries += [ 'md' ]
             sysattr_libraries = [ 'nvpair' ]
+            sha512_t_libraries = [ 'md' ]
             ext_modules += [
                     Extension(
                             'arch',
@@ -1562,6 +1575,16 @@
                             define_macros = [('_FILE_OFFSET_BITS', '64')],
                             build_64 = True
                             ),
+                    Extension(
+                            'sha512_t',
+                            sha512_t_srcs,
+                            include_dirs = include_dirs,
+                            libraries = sha512_t_libraries,
+                            extra_compile_args = compile_args,
+                            extra_link_args = link_args,
+                            define_macros = [('_FILE_OFFSET_BITS', '64')],
+                            build_64 = True
+                            ),
                     ]
         else:
             elf_libraries += [ 'ssl' ]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/api/t_sha512_t.py	Fri Apr 04 18:29:53 2014 -0700
@@ -0,0 +1,131 @@
+#!/usr/bin/python
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+#
+
+import testutils
+if __name__ == "__main__":
+        testutils.setup_environment("../../../proto")
+import pkg5unittest
+
+import unittest
+import pkg.sha512_t as sha512_t
+
+class TestPkgSha(pkg5unittest.Pkg5TestCase):
+        """A class tests the sha512_t module."""
+
+        def test_basic(self):
+                # The expected values are from the examples:
+                # http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA512_224.pdf
+                # http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA512_256.pdf
+
+                # Test SHA512/256
+                # Test hexdigest()
+                a = sha512_t.SHA512_t()
+                a.update("abc")
+                expected = "53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23"
+                output = a.hexdigest()
+                self.assertEqualDiff(expected, output)
+                
+                a = sha512_t.SHA512_t("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")
+                expected = "3928e184fb8690f840da3988121d31be65cb9d3ef83ee6146feac861e19b563a"
+                output = a.hexdigest()
+                self.assertEqualDiff(expected, output)
+
+                # Test the length of the output of hexdigest()
+                output = len(sha512_t.SHA512_t("0.861687995815").hexdigest()) 
+                self.assertEqualDiff(64, output)
+                output = len(sha512_t.SHA512_t("0.861687995815", 224).hexdigest()) 
+                self.assertEqualDiff(56, output)
+
+                # Test digest()
+                a = sha512_t.SHA512_t()
+                a.update("abc")
+                expected = "S\x04\x8e&\x81\x94\x1e\xf9\x9b.)\xb7kL}\xab\xe4\xc2\xd0\xc64\xfcmF\xe0\xe2\xf11\x07\xe7\xaf#"
+                output = a.digest()
+                self.assertEqualDiff(expected, output)
+
+                # Test the length of the output of digest()
+                output = len(sha512_t.SHA512_t("0.861687995815").digest()) 
+                self.assertEqualDiff(32, output)
+                output = len(sha512_t.SHA512_t("0.861687995815", 224).digest()) 
+                self.assertEqualDiff(28, output)
+
+                # Test update()
+                a = sha512_t.SHA512_t("a")
+                a.update("bc")
+                expected = "53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23"
+                output = a.hexdigest()
+                self.assertEqualDiff(expected, output)
+
+                a = sha512_t.SHA512_t("a")
+                a.digest()
+                a.update("b")
+                a.hexdigest()
+                a.update("c")
+                output = a.hexdigest()
+                self.assertEqualDiff(expected, output)
+
+                # Test hash_size
+                a = sha512_t.SHA512_t()
+                self.assertEqualDiff("256", a.hash_size)
+
+                # Test SHA512/224
+                a = sha512_t.SHA512_t(t=224)
+                a.update("abc")
+                expected = "4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa"
+                output = a.hexdigest()
+                self.assertEqualDiff(expected, output)
+
+                a = sha512_t.SHA512_t("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", t=224)
+                expected = "23fec5bb94d60b23308192640b0c453335d664734fe40e7268674af9"
+                output = a.hexdigest()
+                self.assertEqualDiff(expected, output)
+
+                # Test positional arguments
+                a = sha512_t.SHA512_t("abc", 224)
+                expected = "4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa"
+                output = a.hexdigest()
+                self.assertEqualDiff(expected, output)
+
+                # Test keyword arguments
+                a = sha512_t.SHA512_t(message="abc", t=224)
+                expected = "4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa"
+                output = a.hexdigest()
+                self.assertEqualDiff(expected, output)
+
+                # Test scalability
+                a = sha512_t.SHA512_t()
+                for i in xrange(1000000):
+                        a.update("abc")
+                a.hexdigest()
+
+                # Test bad input
+                self.assertRaises(TypeError, sha512_t.SHA512_t, 8)
+                self.assertRaises(ValueError, sha512_t.SHA512_t, t=160)
+                self.assertRaises(TypeError, sha512_t.SHA512_t.update, 8)
+
+
+if __name__ == "__main__":
+        unittest.main()
--- a/src/tests/cli/t_pkg_install.py	Wed Apr 02 17:51:09 2014 -0700
+++ b/src/tests/cli/t_pkg_install.py	Fri Apr 04 18:29:53 2014 -0700
@@ -3589,16 +3589,22 @@
                 contains more hash attributes than the old action, that the
                 upgrade works."""
 
+                self.many_hashalgs_helper("install", "sha256")
+                self.many_hashalgs_helper("install", "sha512_256")
+                self.many_hashalgs_helper("exact-install", "sha256")
+                self.many_hashalgs_helper("exact-install", "sha512_256")
+
+        def many_hashalgs_helper(self, install_cmd, hash_alg):
                 self.pkgsend_bulk(self.rurl, (self.iron10))
                 self.image_create(self.rurl, destroy=True)
                 self.pkg("install [email protected]")
                 self.pkg("contents -m iron")
                 # We have not enabled SHA2 hash publication yet.
-                self.assert_("pkg.hash.sha256" not in self.output)
+                self.assert_(("pkg.hash.%s" % hash_alg) not in self.output)
 
                 # publish with SHA1 and SHA2 hashes
                 self.pkgsend_bulk(self.rurl, self.iron20,
-                    debug_hash="sha1+sha256")
+                    debug_hash="sha1+%s" % hash_alg)
 
                 # verify that a non-SHA2 aware client can install these bits
                 self.pkg("-D hash=sha1 update")
@@ -3609,10 +3615,11 @@
                 # most-preferred hash.
                 self.pkg("install [email protected]")
                 self.pkg("contents -m iron")
-                self.assert_("pkg.hash.sha256" in self.output)
+                self.assert_("pkg.hash.%s" % hash_alg in self.output)
 
                 # publish with only SHA-2 hashes
-                self.pkgsend_bulk(self.rurl, self.iron20, debug_hash="sha256")
+                self.pkgsend_bulk(self.rurl, self.iron20,
+                    debug_hash="%s" % hash_alg)
 
                 # verify that a non-SHA2 aware client cannot install these bits
                 # since there are no SHA1 hashes present
@@ -3621,12 +3628,13 @@
                     "No file could be found for the specified hash name: "
                     "'NOHASH'" in self.errout)
 
-                # Make sure we've been publishing only with sha256 by removing
+                # Make sure we've been publishing only with SHA2 by removing
                 # those known attributes, then checking for the presence of
                 # the SHA-1 attributes.
-                self.pkg("-D hash=sha256 update")
+                self.pkg("-D hash=%s update" % hash_alg)
                 self.pkg("contents -m iron")
-                for attr in ["pkg.hash.sha256", "pkg.chash.sha256"]:
+                for attr in ["pkg.hash.%s" % hash_alg,
+                    "pkg.chash.%s" % hash_alg]:
                         self.output = self.output.replace(attr, "")
                 self.assert_("hash" not in self.output)
                 self.assert_("chash" not in self.output)
--- a/src/tests/cli/t_pkg_revert.py	Wed Apr 02 17:51:09 2014 -0700
+++ b/src/tests/cli/t_pkg_revert.py	Fri Apr 04 18:29:53 2014 -0700
@@ -21,7 +21,7 @@
 #
 
 #
-# Copyright (c) 2011, 2013 Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2014 Oracle and/or its affiliates. All rights reserved.
 #
 
 import testutils
@@ -44,10 +44,7 @@
             add file etc/file1 mode=0555 owner=root group=bin path=etc/file1
             close
             # [email protected] is published as part of pkgs2
-            open [email protected],5.11-0
-            add dir mode=0755 owner=root group=bin path=etc
-            add file etc/file3 mode=0555 owner=root group=bin path=etc/file3 revert-tag=bob revert-tag=ted
-            close
+            # [email protected] is published as part of pkgs3
             open [email protected],5.11-0
             add dir mode=0755 owner=root group=bin path=etc
             add file etc/file4 mode=0555 owner=root group=bin path=etc/file4 revert-tag=bob revert-tag=ted revert-tag=carol
@@ -100,6 +97,14 @@
             close
             """
 
+        # A set of packages that we publish with additional hash attributes
+        pkgs3 = """
+            open [email protected],5.11-0
+            add dir mode=0755 owner=root group=bin path=etc
+            add file etc/file3 mode=0555 owner=root group=bin path=etc/file3 revert-tag=bob revert-tag=ted
+            close
+            """
+
         misc_files = ["etc/file1", "etc/file2", "etc/file3", "etc/file4",
 		      "etc/file5"]
 
@@ -181,6 +186,8 @@
                 self.plist = self.pkgsend_bulk(self.rurl, self.pkgs)
                 self.plist.extend(self.pkgsend_bulk(self.rurl, self.pkgs2,
                     debug_hash="sha1+sha256"))
+                self.plist.extend(self.pkgsend_bulk(self.rurl, self.pkgs3,
+                    debug_hash="sha1+sha512_256"))
 
         def test_revert(self):
                 self.image_create(self.rurl)
@@ -202,6 +209,9 @@
                 self.pkg("verify B", exit=1)
                 self.assert_(sha2 in self.output)
 
+                self.pkg("-D hash=sha1+sha512_256 verify C", exit=1)
+                sha2 = "13729cb7183961b48ce300c2588c86ad123e7c636f38a0f3c8408a75fd079d09"
+                self.assert_(sha2 in self.output, self.output)
                 self.pkg("verify C", exit=1)
                 self.pkg("verify D", exit=1)
 
@@ -233,19 +243,26 @@
                 self.pkg("revert -n --parsable=0 --tagged bob")
                 self.debug("\n".join(self.plist))
                 self.assertEqualParsable(self.output,
-                    affect_packages=[self.plist[10], self.plist[1],
-                    self.plist[2]])
+                    affect_packages=[self.plist[9], self.plist[12],
+                    self.plist[1]])
                 # When reverting damage, we always verify using the
                 # most-preferred hash, but retrieve content with the
-                # least-preferred hash: -D hash=sha1+sha256 should have no
-                # effect here whatsoever, but -D hash=sha256 should fail because
+                # least-preferred hash: -D hash=sha1+sha256 and
+                # -D hash=sha1+sha512_256 should have no effect here whatsoever,
+                # but -D hash=sha256 and -D hash=sha512_256 should fail because
                 # our repository stores its files by the SHA1 hash.
                 self.pkg("-D hash=sha256 revert --parsable=0 --tagged bob",
                     exit=1)
+                self.pkg("-D hash=sha512_256 revert --parsable=0 --tagged ted",
+                    exit=1)
+                self.pkg("-D hash=sha1+512_256 revert -n --parsable=0 \
+                    --tagged ted")
+                self.assertEqualParsable(self.output,
+                    affect_packages=[self.plist[12], self.plist[1]])
                 self.pkg("-D hash=sha1+sha256 revert --parsable=0 --tagged bob")
                 self.assertEqualParsable(self.output,
-                    affect_packages=[self.plist[10], self.plist[1],
-                    self.plist[2]])
+                    affect_packages=[self.plist[9], self.plist[12],
+                    self.plist[1]])
                 self.pkg("verify A", exit=1)
                 self.pkg("verify B")
                 self.pkg("verify C")
--- a/src/tests/cli/t_pkg_search.py	Wed Apr 02 17:51:09 2014 -0700
+++ b/src/tests/cli/t_pkg_search.py	Fri Apr 04 18:29:53 2014 -0700
@@ -21,7 +21,7 @@
 #
 
 #
-# Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
 #
 
 import testutils
@@ -42,6 +42,7 @@
 import pkg.fmri as fmri
 import pkg.indexer as indexer
 import pkg.portable as portable
+import pkg.sha512_t as sha512_t
 
 
 class TestPkgSearchBasics(pkg5unittest.SingleDepotTestCase):
@@ -1058,13 +1059,6 @@
                 self.pkgsend_bulk(self.durl1, self.same_pub1, refresh_index=True)
                 self.durl2 = self.dcs[2].get_depot_url()
                 self.rurl2 = self.dcs[2].get_repo_url()
-                # our 2nd depot gets the package published with multiple hash
-                # attributes, but served from a single-hash-aware depot
-                # (the fact that it's single-hash-aware should make no
-                # difference to the content it serves so long as the index was
-                # generated while we were aware of multiple hashes.
-                self.pkgsend_bulk(self.rurl2, self.same_pub2,
-                    refresh_index=True, debug_hash="sha1+sha256")
 
         def test_7140657(self):
                 """ Check that pkg search with -s works as intended when there are
@@ -1122,7 +1116,7 @@
                 expected = self.reduceSpaces(expected_out2)
                 self.assertEqualDiff(expected, actual)
 
-        def test_search_multi_hash(self):
+        def test_search_multi_hash_1(self):
                 """Check that when searching a repository with multiple
                 hashes, all hash attributes are indexed and we can search
                 against all hash attributes.
@@ -1130,13 +1124,32 @@
                 This test depends on pkg.digest having DebugValue settings
                 that add sha256 hashes to the set of hashes we append to
                 actions at publication time."""
+                self.base_search_multi_hash("sha256", hashlib.sha256)
 
+        def test_search_multi_hash_2(self):
+                """Check that when searching a repository with multiple
+                hashes, all hash attributes are indexed and we can search
+                against all hash attributes.
+
+                This test depends on pkg.digest having DebugValue settings
+                that add sha512/256 hashes to the set of hashes we append to
+                actions at publication time."""
+                self.base_search_multi_hash("sha512_256", sha512_t.SHA512_t)
+
+        def base_search_multi_hash(self, hash_alg, hash_fun):
+                # our 2nd depot gets the package published with multiple hash
+                # attributes, but served from a single-hash-aware depot
+                # (the fact that it's single-hash-aware should make no
+                # difference to the content it serves so long as the index was
+                # generated while we were aware of multiple hashes.
+                self.pkgsend_bulk(self.rurl2, self.same_pub2,
+                    refresh_index=True, debug_hash="sha1+%s" % hash_alg)
                 self.image_create(self.durl2, prefix="samepub")
 
                 # manually calculate the hashes, in case of bugs in
                 # pkg.misc.get_data_digest
                 sha1_hash = hashlib.sha1("magic").hexdigest()
-                sha2_hash = hashlib.sha256("magic").hexdigest()
+                sha2_hash = hash_fun("magic").hexdigest()
 
                 self.pkg("search %s" % sha1_hash)
                 self.pkg("search %s" % sha2_hash)
@@ -1153,7 +1166,7 @@
 
                 self.pkg("search -H -o search.match_type %s" % sha2_hash)
                 self.assertEqualDiff(
-                    self.reduceSpaces(self.output), "pkg.hash.sha256\n")
+                    self.reduceSpaces(self.output), "pkg.hash.%s\n" % hash_alg)
 
                 # check that both searches match the same action
                 self.pkg("search -o action.raw %s" % sha1_hash)
@@ -1166,7 +1179,8 @@
                 # check that the same searches in the non-multihash-aware
                 # repository only return a result for the sha-1 hash
                 # (which checks that we're only setting multiple hashes
-                # on actions when hash=sha1+sha256 is set)
+                # on actions when hash=sha1+sha256 or hash=sha1+sha512_256
+                # is set)
                 self.pkg("search -s %s %s" % (self.durl1, sha1_hash))
                 self.pkg("search -s %s %s" % (self.durl1, sha2_hash), exit=1)
 
--- a/src/tests/cli/t_pkg_sysrepo.py	Wed Apr 02 17:51:09 2014 -0700
+++ b/src/tests/cli/t_pkg_sysrepo.py	Fri Apr 04 18:29:53 2014 -0700
@@ -21,7 +21,7 @@
 #
 
 #
-# Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
 #
 
 import testutils
@@ -93,11 +93,16 @@
 
         baz10 = """
             open [email protected],5.11-0
-            add file tmp/example_three mode=0555 owner=root group=bin path=/usr/bin/another
+            add file tmp/example_three mode=0555 owner=root group=bin path=/usr/bin/another_1
+            close"""
+
+        caz10 = """
+            open [email protected],5.11-0
+            add file tmp/example_four mode=0555 owner=root group=bin path=/usr/bin/another_2
             close"""
 
         misc_files = ["tmp/example_file", "tmp/example_two",
-            "tmp/example_three"]
+            "tmp/example_three", "tmp/example_four"]
 
         expected_all_access =  """\
 PUBLISHER\tSTICKY\tSYSPUB\tENABLED\tTYPE\tSTATUS\tURI\tPROXY
@@ -160,6 +165,8 @@
                     debug_hash="sha1+sha256")
                 self.pkgsend_bulk(self.rurl3, self.baz10,
                     debug_hash="sha1+sha256")
+                self.pkgsend_bulk(self.rurl3, self.caz10,
+                    debug_hash="sha1+sha512_256")
                 self.pkgsend_bulk(self.rurl4, self.bar10)
                 self.pkgsend_bulk(self.rurl5, self.foo11)
 
@@ -614,6 +621,9 @@
                 self.pkg("install baz")
                 self.pkg("contents -m baz")
                 self.assert_("pkg.hash.sha256" in self.output)
+                self.pkg("install caz")
+                self.pkg("contents -m caz")
+                self.assert_("pkg.hash.sha512_256" in self.output)
 
         def test_02_communication(self):
                 """Test that the transport for communicating with the depots is
@@ -949,6 +959,7 @@
                 expected = """\
 bar (test3) 1.0-0 ---
 baz (test3) 1.0-0 ---
+caz (test3) 1.0-0 ---
 example_pkg 1.0-0 ---
 """
                 self.__check_package_lists(expected)
@@ -977,6 +988,7 @@
                 expected = """\
 bar (test3) 1.0-0 ---
 baz (test3) 1.0-0 ---
+caz (test3) 1.0-0 ---
 example_pkg 1.0-0 ---
 """
                 self.__check_package_lists(expected)
--- a/src/tests/cli/t_pkgrecv.py	Wed Apr 02 17:51:09 2014 -0700
+++ b/src/tests/cli/t_pkgrecv.py	Fri Apr 04 18:29:53 2014 -0700
@@ -21,7 +21,7 @@
 #
 
 #
-# Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
 #
 
 import testutils
@@ -916,9 +916,11 @@
                 """Tests that we can recv to and from repositories with
                 multi-hash support, interoperating with repositories without
                 multi-hash support."""
+                self.base_12_multihash("sha256")
+                self.base_12_multihash("sha512_256")
 
+        def base_12_multihash(self, hash_alg):
                 f = fmri.PkgFmri(self.published[3], None)
-
                 # We create an image simply so we can use "contents -g" to
                 # inspect the repository.
                 self.image_create()
@@ -926,39 +928,40 @@
                 # First, recv the package and verify it has no extended hashes
                 self.pkgrecv(self.durl1, "-d %s %s" % (self.durl3, f))
                 self.pkg("contents -g %s -m %s" % (self.durl3, f))
-                self.assert_("pkg.hash.sha256" not in self.output)
+                self.assert_("pkg.hash.%s" % hash_alg not in self.output)
 
                 # Now stop and start the repository as multi-hash aware, and
                 # recv it again, making sure that we do not get multiple hashes
                 # added (because modifying the manifest would break signatures)
                 self.dcs[3].stop()
-                self.dcs[3].set_debug_feature("hash=sha1+sha256")
+                self.dcs[3].set_debug_feature("hash=sha1+%s" % hash_alg)
                 self.dcs[3].start()
                 self.pkgrecv(self.durl1, "-d %s %s" % (self.durl3, f))
                 self.pkg("contents -g %s -m %s" % (self.durl3, f))
-                self.assert_("pkg.hash.sha256" not in self.output)
+                self.assert_("pkg.hash.%s" % hash_alg not in self.output)
 
                 # Now check the reverse - that a package with multiple hashes
                 # can be received into a repository that is not multi-hash aware
                 b = "[email protected],5.11-0"
                 self.pkgsend_bulk(self.durl3, self.bronze10)
                 self.pkg("contents -g %s -m %s" % (self.durl3, b))
-                self.assert_("pkg.hash.sha256" in self.output)
+                self.assert_("pkg.hash.%s" % hash_alg in self.output)
                 self.pkgrecv(self.durl3, "-d %s %s" % (self.durl4, b))
                 self.pkg("contents -g %s -m %s" % (self.durl4, b))
-                self.assert_("pkg.hash.sha256" in self.output)
+                self.assert_("pkg.hash.%s" % hash_alg in self.output)
 
                 # Ensure that we can recv multi-hash packages into p5p files
-                p5p_path = os.path.join(self.test_root, "multi-hash.p5p")
+                p5p_path = os.path.join(self.test_root,
+                    "multi-hash-%s.p5p" % hash_alg)
                 self.pkgrecv(self.durl3, "-ad %s %s" % (p5p_path, b))
                 self.pkg("contents -g %s -m %s" % (p5p_path, b))
-                self.assert_("pkg.hash.sha256" in self.output)
+                self.assert_("pkg.hash.%s" % hash_alg in self.output)
 
                 # Finally, stop and start our scratch repository to clear the
                 # debug feature. If this doesn't happen because we've failed
                 # before now, it's not the end of the world.
                 self.dcs[3].stop()
-                self.dcs[3].unset_debug_feature("hash=sha1+sha256")
+                self.dcs[3].unset_debug_feature("hash=sha1+%s" % hash_alg)
                 self.dcs[3].start()
 
         def test_13_output(self):
--- a/src/tests/cli/t_pkgrepo.py	Wed Apr 02 17:51:09 2014 -0700
+++ b/src/tests/cli/t_pkgrepo.py	Fri Apr 04 18:29:53 2014 -0700
@@ -1384,37 +1384,39 @@
                                 continue
                         self.assert_(not os.listdir(rstore.file_root))
 
-                # Reset the src_repo for the rest of the test.
-                shutil.rmtree(src_repo)
-                self.create_repo(src_repo)
-                self.pkgrepo("set -s %s publisher/prefix=test" % src_repo)
-
-                published = self.pkgsend_bulk(src_repo, (self.tree10),
-                    debug_hash="sha1+sha256")
-
-                # Verify that we only have SHA-1 hashes in the rstore
-                repo = self.get_repo(src_repo)
-                known_hashes = self.fhashes.values()
-                for rstore in repo.rstores:
-                        if not rstore.publisher:
-                                continue
-                        for dir, dnames, fnames in os.walk(rstore.file_root):
-                                for f in fnames:
-                                        if f not in known_hashes:
-                                                self.assert_(False,
-                                                    "Unexpected content in "
-                                                    "repodir: %s" % f)
-
-                # Verify that when a repository has been published with multiple
-                # hashes, on removal, we only attempt to remove files using the
-                # least-preferred hash.
-                self.pkgrepo("remove -s %s tree" % src_repo)
-
-                # Verify repository file_root is empty.
-                for rstore in repo.rstores:
-                        if not rstore.publisher:
-                                continue
-                        self.assert_(not os.listdir(rstore.file_root))
+                for hash_alg in ["sha256", "sha512_256"]:
+                        # Reset the src_repo for the rest of the test.
+                        shutil.rmtree(src_repo)
+                        self.create_repo(src_repo)
+                        self.pkgrepo("set -s %s publisher/prefix=test" %
+                            src_repo)
+                        published = self.pkgsend_bulk(src_repo, (self.tree10),
+                            debug_hash="sha1+%s" % hash_alg)
+
+                        # Verify that we only have SHA-1 hashes in the rstore
+                        repo = self.get_repo(src_repo)
+                        known_hashes = self.fhashes.values()
+                        for rstore in repo.rstores:
+                                if not rstore.publisher:
+                                        continue
+                                for dir, dnames, fnames in \
+                                    os.walk(rstore.file_root):
+                                        for f in fnames:
+                                                if f not in known_hashes:
+                                                        self.assert_(False,
+                                                            "Unexpected content "
+                                                            "in repodir: %s" % f)
+
+                        # Verify that when a repository has been published with
+                        # multiple hashes, on removal, we only attempt to remove
+                        # files using the least-preferred hash.
+                        self.pkgrepo("remove -s %s tree" % src_repo)
+
+                        # Verify repository file_root is empty.
+                        for rstore in repo.rstores:
+                                if not rstore.publisher:
+                                        continue
+                                self.assert_(not os.listdir(rstore.file_root))
 
                 # Cleanup.
                 shutil.rmtree(src_repo)
@@ -1951,36 +1953,40 @@
                 self.assert_(bad_gzip_path in self.output)
 
                 # Check that when verifying content, we always use the most
-                # preferred hash. Remove all existing packages first.
-                self.pkgrepo("-s %s remove %s" % (repo_path, " ".join(fmris)))
-                fmris = self.pkgsend_bulk(repo_path, (self.tree10),
-                    debug_hash="sha1+sha256")
-                self.pkgrepo("-s %s verify" % repo_path, exit=0)
-
-                # break a file in the repository and ensure we spot it.
-                bad_hash_path = self.__inject_badhash("tmp/truck1")
-                bad_basename = os.path.basename(bad_hash_path)
-
-                self.pkgrepo("-s %s verify" % repo_path, exit=1)
-                self.assert_(
-                    self.output.count("ERROR: Invalid file hash") == 1)
-
-                # We should be verifying using the SHA-2 hash, and so we should
-                # only see the SHA-1 value in the output once, when printing
-                # the path to the file in the repository, not when reporting
-                # the computed or expected hash.
-                self.assert_(self.output.count(bad_basename) == 1)
-
-                # Verify that when we publish using SHA-1 only, that we get
-                # the SHA-1 value printed twice: once when printing the path
-                # to the file in the repository, and once when printing the
-                # expected hash.
-                self.pkgrepo("-s %s remove %s" % (repo_path, " ".join(fmris)))
-                fmris = self.pkgsend_bulk(repo_path, (self.tree10))
-                self.__inject_badhash("tmp/truck1")
-
-                self.pkgrepo("-s %s verify" % repo_path, exit=1)
-                self.assert_(self.output.count(bad_basename) == 2)
+                # preferred hash.
+                for hash_alg in ["sha256", "sha512_256"]:
+                        # Remove all existing packages first.
+                        self.pkgrepo("-s %s remove %s" % (repo_path,
+                            " ".join(fmris)))
+                        fmris = self.pkgsend_bulk(repo_path, (self.tree10),
+                            debug_hash="sha1+%s" % hash_alg)
+                        self.pkgrepo("-s %s verify" % repo_path, exit=0)
+
+                        # break a file in the repository and ensure we spot it.
+                        bad_hash_path = self.__inject_badhash("tmp/truck1")
+                        bad_basename = os.path.basename(bad_hash_path)
+
+                        self.pkgrepo("-s %s verify" % repo_path, exit=1)
+                        self.assert_(
+                            self.output.count("ERROR: Invalid file hash") == 1)
+
+                        # We should be verifying using the SHA-2 hash, and so we
+                        # should only see the SHA-1 value in the output once,
+                        # when printing the path to the file in the repository,
+                        # not when reporting the computed or expected hash.
+                        self.assert_(self.output.count(bad_basename) == 1)
+
+                        # Verify that when we publish using SHA-1 only, that we
+                        # get the SHA-1 value printed twice: once when printing
+                        # the path to the file in the repository, and once when
+                        # printing the expected hash.
+                        self.pkgrepo("-s %s remove %s" % (repo_path,
+                            " ".join(fmris)))
+                        fmris = self.pkgsend_bulk(repo_path, (self.tree10))
+                        self.__inject_badhash("tmp/truck1")
+
+                        self.pkgrepo("-s %s verify" % repo_path, exit=1)
+                        self.assert_(self.output.count(bad_basename) == 2)
 
         def test_12_verify_badmanifest(self):
                 """Test that verify finds bad manifests."""
--- a/src/tests/cli/t_pkgsend.py	Wed Apr 02 17:51:09 2014 -0700
+++ b/src/tests/cli/t_pkgsend.py	Fri Apr 04 18:29:53 2014 -0700
@@ -20,7 +20,7 @@
 # CDDL HEADER END
 #
 
-# Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
 
 import testutils
 if __name__ == "__main__":
@@ -1295,6 +1295,10 @@
                 and only if they match the hash attributes we know how to
                 compute, other attributes are left alone."""
 
+                self.base_26_pkgsend_multihash("sha256")
+                self.base_26_pkgsend_multihash("sha512_256")
+
+        def base_26_pkgsend_multihash(self, hash_alg):
                 # we use a file:// URI rather than the repo URI so we don't have
                 # to worry about starting the depot in SHA-2 mode. Other tests
                 # in the test suite ensure SHA-2 publication is working over
@@ -1306,20 +1310,21 @@
                 with open(mfpath, "wb") as mf:
                         mf.write("""
 set name=pkg.fmri value=pkg:/[email protected]
-file %s path=/foo owner=root group=sys mode=0644 pkg.hash.sha256=spaghetti \
+file %s path=/foo owner=root group=sys mode=0644 pkg.hash.%s=spaghetti \
     pkg.hash.rot13=caesar
-""" % payload)
+""" % (payload, hash_alg))
                 self.pkgsend("", "-s %s publish %s" % (furi, mfpath))
                 self.image_create(furi)
                 self.pkg("contents -rm multihash")
-                self.assert_("pkg.hash.sha256=spaghetti" in self.output)
+                self.assert_("pkg.hash.%s=spaghetti" % hash_alg in self.output)
 
                 self.pkgsend("", "-s %s publish %s" % (furi, mfpath),
-                    debug_hash="sha1+sha256")
+                    debug_hash="sha1+%s" % hash_alg)
                 self.pkg("refresh")
 
                 self.pkg("contents -rm multihash")
-                self.assert_("pkg.hash.sha256=spaghetti" not in self.output)
+                self.assert_("pkg.hash.%s=spaghetti" % hash_alg
+                    not in self.output)
                 self.assert_("pkg.hash.rot13=caesar" in self.output)
 
 
--- a/src/tests/cli/t_pkgsign.py	Wed Apr 02 17:51:09 2014 -0700
+++ b/src/tests/cli/t_pkgsign.py	Fri Apr 04 18:29:53 2014 -0700
@@ -21,7 +21,7 @@
 #
 
 #
-# Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
 #
 
 import testutils
@@ -527,6 +527,10 @@
                 """Test that having a package signed with more than one
                 signature doesn't cause anything to break."""
 
+                self.base_multiple_signatures("sha256")
+                self.base_multiple_signatures("sha512_256")
+
+        def base_multiple_signatures(self, hash_alg):
                 plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
 
                 sign_args = "-k %(key)s -c %(cert)s -i %(i1)s -i %(i2)s " \
@@ -552,7 +556,8 @@
                             "ch5_ta1_cert.pem"),
                         "pkg": plist[0]
                     }
-                self.pkgsign(self.rurl1, sign_args, debug_hash="sha1+sha256")
+                self.pkgsign(self.rurl1, sign_args,
+                    debug_hash="sha1+%s" % hash_alg)
 
                 sign_args = "-k %(key)s -c %(cert)s %(name)s" % {
                     "name": plist[0],
@@ -569,7 +574,7 @@
 
                 # Make sure we've got exactly 1 signature with SHA2 hashes
                 self.pkg("contents -m")
-                self.assert_(self.output.count("pkg.chain.sha256") == 1)
+                self.assert_(self.output.count("pkg.chain.%s" % hash_alg) == 1)
                 self.assert_(self.output.count("pkg.chain.chashes") == 1)
                 # and SHA1 hashes on both signatures
                 self.assert_(self.output.count("chain=") == 2)
@@ -2375,26 +2380,29 @@
                 with open(mp, "wb") as fh:
                         for l in s:
                                 fh.write(l)
-                # Rebuild the catalog so that hash verification for the manifest
-                # won't cause problems.
-                r.rebuild()
-                # This should fail because the manifest already has identical
-                # signature actions in it.
-                self.pkgsign_simple(self.rurl1, plist[0], exit=1)
-
-                # The addition of SHA-256 hashes should still result in us
-                # believing the signatures are identical
-                self.pkgsign_simple(self.rurl1, plist[0], exit=1,
-                    debug_hash="sha1+sha256")
-
-                self.pkg_image_create(self.rurl1)
-                self.seed_ta_dir("ta3")
-                self.pkg("set-property signature-policy verify")
-
-                # This fails because the manifest contains duplicate signatures.
-                api_obj = self.get_img_api_obj()
-                self.assertRaises(apx.UnverifiedSignature, self._api_install,
-                    api_obj, ["example_pkg"])
+
+                for hash_alg in ["sha256", "sha512_256"]:
+                        # Rebuild the catalog so that hash verification for the
+                        # manifest won't cause problems.
+                        r.rebuild()
+                        # This should fail because the manifest already has
+                        # identical signature actions in it.
+                        self.pkgsign_simple(self.rurl1, plist[0], exit=1)
+
+                        # The addition of SHA-256 hashes should still result in
+                        # us believing the signatures are identical.
+                        self.pkgsign_simple(self.rurl1, plist[0], exit=1,
+                            debug_hash="sha1+%s" % hash_alg)
+
+                        self.pkg_image_create(self.rurl1)
+                        self.seed_ta_dir("ta3")
+                        self.pkg("set-property signature-policy verify")
+
+                        # This fails because the manifest contains duplicate
+                        # signatures.
+                        api_obj = self.get_img_api_obj()
+                        self.assertRaises(apx.UnverifiedSignature,
+                                self._api_install, api_obj, ["example_pkg"])
 
         def test_bug_16867_hashes_1(self):
                 """Test whether signing a package a second time with hashes
--- a/src/tests/pkg5unittest.py	Wed Apr 02 17:51:09 2014 -0700
+++ b/src/tests/pkg5unittest.py	Fri Apr 04 18:29:53 2014 -0700
@@ -2642,7 +2642,7 @@
 
                 # debug_hash lets us choose the type of hash attributes that
                 # should be added to this package on publication. Valid values
-                # are: sha1, sha1+sha256, sha256
+                # are: sha1, sha256, sha1+sha256, sha512_256, sha1+sha512_256
                 if debug_hash:
                         args.append("-D hash=%s" % debug_hash)