#
# 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 getopt
import gettext
import hashlib
import locale
import os
import shutil
import sys
import tempfile
import traceback
else:
import pkg
# pkg exit codes
repo_cache = {}
"""Emit an error message prefixed by the command name """
if cmd:
else:
# If the message starts with whitespace, assume that it should come
# *before* the command-name prefix.
# This has to be a constant value as we can't reliably get our actual
# program name on all platforms.
"""Emit a usage message and optionally prefix it with a more specific
error message. Causes program to exit."""
if usage_error:
emsg (_("""\
Usage:
pkgsign -s path_or_uri [-acikn] [--no-index] [--no-catalog]
(fmri|pattern) ...
"""))
"""Fetch the catalog from src_uri."""
# Create a temporary directory for catalog.
try:
except (ValueError, IOError) as e:
"be a PEM certificate but it could not be read.").format(
pth))
return fp
def main_func():
try:
["help", "no-index", "no-catalog"])
except getopt.GetoptError as e:
sig_alg = "rsa-sha256"
cert_path = None
key_path = None
chain_certs = []
if opt == "-a":
elif opt == "-c":
usage(_("{0} was expected to be a certificate "
elif opt == "-i":
usage(_("{0} was expected to be a certificate "
"but isn't a file.").format(p))
elif opt == "-k":
usage(_("{0} was expected to be a key file "
elif opt == "-n":
elif opt == "-s":
elif opt == "--help":
elif opt == "--no-catalog":
elif opt == "-D":
try:
except (AttributeError, ValueError):
error(_("{opt} takes argument of form "
"name=value, not {arg}").format(
if show_usage:
if not repo_uri:
usage(_("a repository must be provided"))
usage(_("If a key is given to sign with, its associated "
"certificate must be given."))
usage(_("If a certificate is given, its associated key must be "
"given."))
if chain_certs and not cert_path:
usage(_("Intermediate certificates are only valid if a key "
"and certificate are also provided."))
if not pargs:
usage(_("At least one fmri or pattern must be provided to "
"sign."))
sig_alg = "sha256"
if h is None:
sig_alg))
if s and not key_path:
usage(_("Using {0} as the signature algorithm requires that a "
"key and certificate pair be presented using the -k and -c "
if not s and key_path:
usage(_("The {0} hash algorithm does not use a key or "
"certificate. Do not use the -k or -c options with this "
if DebugValues:
errors = []
t = misc.config_temp_root()
del t
try:
chain_certs = [
]
if cert_path is not None:
# Configure publisher(s)
concrete_fmris = []
# Gather the publishers whose catalogs will be needed.
try:
except fmri.IllegalMatchingFmri as e:
continue
if pub_prefix:
else:
# Check each publisher for matches to our patterns.
for p in xport_cfg.gen_publishers():
continue
# Find which patterns matched.
matched_pats = all_pats - u
# Remove those patterns from the unmatched set.
if unmatched_pats:
raise api_errors.PackageMatchErrors(
try:
# Get the existing manifest for the package to
# be signed.
# Construct the base signature action.
**attrs)
# Add the action to the manifest to be signed
# since the action signs itself.
# Set the signature value and certificate
# information for the signature action.
a.set_signature(m.gen_actions(),
# The hash of 'a' is currently a path, we need
# to find the hash of that file to allow
# comparison to existing signatures.
hsh = None
if cert_path:
# Action identity still uses the 'hash'
# member of the action, so we need to
# stay with the sha1 hash.
# Check whether the signature about to be added
# is identical, or almost identical, to existing
# signatures on the package. Because 'a' has
# already been added to the manifest, it is
# generated by gen_actions_by_type, so the cnt
# must be 2 or higher to be an issue.
cnt = 0
try:
cnt += 1
except api_errors.AlmostIdentical as e:
if almost_identical:
continue
if cnt == 2:
continue
elif cnt > 2:
if not dry_run:
# Append the finished signature action
# to the published manifest.
try:
t.append()
t.add(a)
for c in chain_certs:
t.add_file(c)
except:
if t.trans_id:
raise
trans.TransactionError) as e:
if errors:
return EXIT_PARTIAL
else:
return EXIT_OOPS
return EXIT_OK
except api_errors.ApiException as e:
error(e)
return EXIT_OOPS
finally:
#
# Establish a specific exit status which means: "python barfed an exception"
# so that we can more easily detect these in testing of the CLI commands.
#
if __name__ == "__main__":
try:
except (PipeError, KeyboardInterrupt):
# We don't want to display any messages here to prevent
# possible further broken pipe (EPIPE) errors.
except SystemExit as _e:
raise _e
except: