#
# 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
# 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
#
#
#
import hashlib
import six
try:
except ImportError:
# When running the test suite, we alter our behaviour depending on certain
# debug flags.
# pkg(7) uses cryptographic hash functions for a number of tasks. We define the
# default hash function, along with the hash name here. Note that the use of
# hashes in package metadata is *not* governed by this value, since multiple
# hashes are supported for payload-bearing actions in a package.
#
# Some uses of hashes are image-format specific, and may require image version
# increments, in which case the required algorithm is hardcoded where it is
# used, along with with an appropriate comment.
#
# Other uses are essentially volatile, and the hash used has no persistence
# (e.g. saving the hash to a file in a temporary directory, when the hash gets
# regenerated on service restart). For those volatile uses, DEFAULT_HASH_FUNC is
# recommended.
# DEFAULT_XXX_ATTRS are the attributes added to actions by the packaging system
# at publication time.
#
# Notably, the hashes we add to an action at publication *do not* need to
# correspond to the hashes we may use to verify action payload during install or
# update, allowing an upgrade path where we could choose to drop publication
# support for a certain hash algorithm, but still retain the ability to install
# actions using that hash.
#
# The order of these lists of attributes is significant only to the
# extent that the repository code will store the file in the repository using
# the first hash value in the list when using the *old* publication model (ie.
# a transaction, with multiple add_file(..) methods to add content)
#
# Otherwise, when publishing, we always store files in the repository
# using the "least preferred" hash for maximum backwards compatibility with
# older packaging tools that expect to be able to find those hashes in the
# repository, but do add additional hashes to the action metadata.
#
# When using the transport to download content from a repository, we use the
# least preferred_hash for file retrieval, but verify the installed content
# using the "most preferred" hash. See get_preferred_hash(..),
# get_least_preferred_hash(..) and get_common_preferred_hash(..)
#
RANKED_HASHES = []
if DebugValues["hash"]:
else:
if alg == "sha512t_256":
if not sha512_supported:
continue
DEFAULT_HASH_ATTRS = []
DEFAULT_CHASH_ATTRS = []
DEFAULT_CHAIN_ATTRS = []
if "sha1" in RANKED_HASHES:
if PREFERRED_HASH != "sha1":
}
# The types of hashes we compute or consult for actions.
# In the dictionaries below, we map the action attributes to the name of the
# class or factory-method that returns an object used to compute that attribute.
# The class or factory-method takes a 0-parameter constructor to return an
# object which must have an 'update(data)' method , used to update the hash
# value being computed with this data, along with a 'hexdigest()' method to
# return the hexadecimal value of the hash.
#
# 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(7) is updated.
# Dictionaries of the pkg(7) hash and content-hash attributes we know about.
# Simulate older non-SHA2 aware pkg(7) code
else:
HASH_ALGS = {
}
GELF_HASH_ALGS = {
}
if sha512_supported:
# A dictionary of the compressed hash attributes we know about.
CHASH_ALGS = {}
# A dictionary of signature action chain hash attributes we know about.
CHAIN_ALGS = {}
# A dictionary of signature action chain chash attributes we know about.
CHAIN_CHASH_ALGS = {}
"""Tells whether or not the named attribute contains a hash value."""
return attr_name in ALL_HASH_ATTRS
"""Based on the 'hash_type', return a tuple describing the ranking of
hash attributes from "most preferred" to "least preferred" and a mapping
of those attributes to the hash algorithms that are used to
compute those attributes.
If 'reverse' is true, return the rank_tuple in reverse order, from least
preferred hash to most preferred hash.
"""
elif hash_type == CHAIN_CHASH:
else:
hash_attrs = None
hash_dic = None
return hash_attrs, hash_dic
"""This class breaks out the stringified tuples from
pkg.content-hash
"extract_method:hash_alg:hash_val"
into a dict with entries
"extract_method:hash_alg": "hash_val"
"""
for v in vals:
"""Returns a tuple of the form (hash_attr, hash_val, hash_func)
where 'hash_attr' is the preferred hash attribute name, 'hash_val'
is the the preferred hash value, and 'hash_func' is the function
used to compute the preferred hash based on the available
pkg.content-hash or pkg.*hash.* attributes declared in the action."""
if not (hash_attrs and hash_dic):
raise ValueError("Unknown hash_type {0} passed to "
else:
if reversed:
else:
for alg in ranked_hashes:
if alg == "sha1":
# The corresponding hash attr should be in the
# first position if "sha1" is enabled.
if not action:
else:
# Currently only HASH, HASH_GELF and CHASH support
# pkg.content-hash.
attr = "pkg.content-hash"
if not action:
# The corresponding hash attr should be in the
# last position if sha2 or higher algorithm is enabled.
# fallback to the default hash member since it's not in action.attrs
# an action can legitimately have no chash
# an action can legitimately have no GELF content-hash if it's not a
# file type we know about
return None, None, None
# an action can legitimately have no chain
return None, None, None
# an action can legitimately have no chain_chash
if hash_type == CHAIN_CHASH:
return None, None, None
# This should never happen.
if reversed:
raise Exception("Error determining the least preferred hash "
else:
raise Exception("Error determining the preferred hash for "
"""Returns a tuple of the least preferred hash attribute name, the hash
value that should result when we compute the hash, and the function used
to compute the hash based on the available hash and pkg.*hash.*
attributes declared in the action."""
cmp_policy=None):
"""Returns the most preferred hash attribute of those present
action. We return the name of the hash attribute, the new and
original values of that attribute, and the function used
to compute the hash.
The pkg.content-hash attribute may be multi-valued. When
selecting this attribute, a secondary selection will be made
based on a ranked list of value prefixes. The most preferred
value will then be returned.
Normally, payload comparisons should only be made based on
hashes that include signatures in the extracted data. This
constraint can be relaxed by setting cmp_policy=CMP_UNSIGNED. In
this case, the most preferred hash will be selected first, and
then we'll check for unsigned versions of that hash on both
actions. When both actions have that unsigned hash, its values
will be returned in place of the signed values.
If no common attribute is found, we fallback to the legacy
<Action>.hash member assuming it is not None for the new and
orig actions, and specify hashlib.sha1 as the algorithm. If no
'hash' member is set, we return a tuple of None objects.
"""
if not old_action:
return None, None, None, None
else:
if not (hash_attrs and hash_dic):
raise ValueError("Unknown hash_type {0} passed to "
for alg in RANKED_HASHES:
if alg == "sha1":
# The corresponding hash attr should be in the
# first position if "sha1" is enabled.
if attr not in all_hashes:
continue
# Currently only HASH, HASH_GELF and CHASH support
# pkg.content-hash.
attr = "pkg.content-hash"
if attr not in all_hashes:
continue
nh = ContentHash(
oh = ContentHash(
continue
# Here we've matched a ranked hash type in at
# least one of the pkg.content-hash value
# sets, so we know we'll be returning. If
# we're allowing comparison on unsigned hash
# values, and both value sets have this hash
# type, and both value sets have a
# corresponding unsigned hash, swap in those
# unsigned hash values.
# The corresponding hash attr should be in the
# last position if sha2 or higher algorithm is enabled.
if attr not in all_hashes:
continue
return None, None, None, None