9196 pkg(5) should have support for cryptographic manifest signatures
authorBrock Pytlik <bpytlik@sun.com>
Mon, 16 Aug 2010 16:48:50 -0700
changeset 2026 d1b30615bc99
parent 2025 4ba5092f1b06
child 2027 f2e9f684e5be
9196 pkg(5) should have support for cryptographic manifest signatures 11611 pkg5 should provide for hash validation on manifests 16654 Expose ability to upload by file path
doc/client_api_versions.txt
doc/signed_manifests.txt
src/client.py
src/man/Makefile
src/man/pkg.1.txt
src/man/pkgrepo.1.txt
src/man/pkgsign.1.txt
src/modules/actions/file.py
src/modules/actions/generic.py
src/modules/actions/license.py
src/modules/actions/signature.py
src/modules/client/api.py
src/modules/client/api_errors.py
src/modules/client/image.py
src/modules/client/imageconfig.py
src/modules/client/imageplan.py
src/modules/client/pkgplan.py
src/modules/client/publisher.py
src/modules/client/sigpolicy.py
src/modules/client/transport/engine.py
src/modules/client/transport/repo.py
src/modules/client/transport/transport.py
src/modules/manifest.py
src/modules/misc.py
src/modules/p5i.py
src/modules/publish/transaction.py
src/modules/server/depot.py
src/modules/server/repository.py
src/modules/server/transaction.py
src/patch/M2Crypto/crl.patch
src/pkg/license_files/lic_m2crypto
src/pkg/manifests/developer%2Fopensolaris%2Fpkg5.p5m
src/pkg/manifests/library%2Fpython-2%2Fm2crypto.p5m
src/pkg/manifests/package%2Fpkg.p5m
src/pkgrepo.py
src/publish.py
src/pull.py
src/setup.py
src/sign.py
src/tests/api/t_action.py
src/tests/api/t_api.py
src/tests/api/t_api_search.py
src/tests/api/t_file_manager.py
src/tests/api/t_p5i.py
src/tests/api/t_publisher.py
src/tests/cli/t_pkg_depotd.py
src/tests/cli/t_pkg_image_create.py
src/tests/cli/t_pkg_install.py
src/tests/cli/t_pkg_property.py
src/tests/cli/t_pkg_publisher.py
src/tests/cli/t_pkg_search.py
src/tests/cli/t_pkgfmt.py
src/tests/cli/t_pkgmogrify.py
src/tests/cli/t_pkgrepo.py
src/tests/cli/t_pkgsend.py
src/tests/cli/t_pkgsign.py
src/tests/cli/t_util_merge.py
src/tests/cli/t_util_update_file_layout.py
src/tests/pkg5unittest.py
src/tests/ro_data/signing_certs/generate_certs.py
src/tests/ro_data/signing_certs/openssl.cnf
src/tests/ro_data/signing_certs/produced/chain_certs/04.pem
src/tests/ro_data/signing_certs/produced/chain_certs/05.pem
src/tests/ro_data/signing_certs/produced/chain_certs/09.pem
src/tests/ro_data/signing_certs/produced/chain_certs/ch1_pubCA1_cert.pem
src/tests/ro_data/signing_certs/produced/chain_certs/ch2.2_pubCA1_cert.pem
src/tests/ro_data/signing_certs/produced/chain_certs/ch2_pubCA1_cert.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/06.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/07.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/08.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/0A.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/0B.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/0D.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/0E.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/0F.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/10.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/12.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/14.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/16.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/18.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/19.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/1A.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/1C.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/cs1_p1_ta3_cert.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/cs1_p2_ta3_cert.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/cs1_p3_ta3_cert.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/cs1_p4_ta3_cert.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/cs1_pubCA1_cert.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/cs1_ta2_cert.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/cs1_ta4_cert.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/cs1_ta5_cert.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/cs2_p1_ta3_cert.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/cs2_pubCA1_cert.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/cs2_ta4_cert.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/cs3_p1_ta3_cert.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/cs3_pubCA1_cert.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/cs3_ta4_cert.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/cs4_p1_ta3_cert.pem
src/tests/ro_data/signing_certs/produced/code_signing_certs/cs4_pubCA1_cert.pem
src/tests/ro_data/signing_certs/produced/crl/ch1_pubCA1_crl.pem
src/tests/ro_data/signing_certs/produced/crl/pubCA1_ta1_crl.pem
src/tests/ro_data/signing_certs/produced/crl/pubCA1_ta4_crl.pem
src/tests/ro_data/signing_certs/produced/crl/ta5_crl.pem
src/tests/ro_data/signing_certs/produced/index
src/tests/ro_data/signing_certs/produced/index.attr
src/tests/ro_data/signing_certs/produced/inter_certs/01.pem
src/tests/ro_data/signing_certs/produced/inter_certs/02.pem
src/tests/ro_data/signing_certs/produced/inter_certs/i1_ta1_cert.pem
src/tests/ro_data/signing_certs/produced/inter_certs/i2_ta1_cert.pem
src/tests/ro_data/signing_certs/produced/keys/ch1_pubCA1_key.pem
src/tests/ro_data/signing_certs/produced/keys/ch2.2_pubCA1_key.pem
src/tests/ro_data/signing_certs/produced/keys/ch2_pubCA1_key.pem
src/tests/ro_data/signing_certs/produced/keys/cs1_p1_ta3_key.pem
src/tests/ro_data/signing_certs/produced/keys/cs1_p2_ta3_key.pem
src/tests/ro_data/signing_certs/produced/keys/cs1_p3_ta3_key.pem
src/tests/ro_data/signing_certs/produced/keys/cs1_p4_ta3_key.pem
src/tests/ro_data/signing_certs/produced/keys/cs1_pubCA1_key.pem
src/tests/ro_data/signing_certs/produced/keys/cs1_ta2_key.pem
src/tests/ro_data/signing_certs/produced/keys/cs1_ta4_key.pem
src/tests/ro_data/signing_certs/produced/keys/cs1_ta5_key.pem
src/tests/ro_data/signing_certs/produced/keys/cs2_p1_ta3_key.pem
src/tests/ro_data/signing_certs/produced/keys/cs2_pubCA1_key.pem
src/tests/ro_data/signing_certs/produced/keys/cs2_ta4_key.pem
src/tests/ro_data/signing_certs/produced/keys/cs3_p1_ta3_key.pem
src/tests/ro_data/signing_certs/produced/keys/cs3_pubCA1_key.pem
src/tests/ro_data/signing_certs/produced/keys/cs3_ta4_key.pem
src/tests/ro_data/signing_certs/produced/keys/cs4_p1_ta3_key.pem
src/tests/ro_data/signing_certs/produced/keys/cs4_pubCA1_key.pem
src/tests/ro_data/signing_certs/produced/keys/i1_ta1_key.pem
src/tests/ro_data/signing_certs/produced/keys/i2_ta1_key.pem
src/tests/ro_data/signing_certs/produced/keys/pubCA1_ta1_key.pem
src/tests/ro_data/signing_certs/produced/keys/pubCA1_ta3_key.pem
src/tests/ro_data/signing_certs/produced/keys/pubCA1_ta4_key.pem
src/tests/ro_data/signing_certs/produced/keys/pubCA1_ta5_key.pem
src/tests/ro_data/signing_certs/produced/keys/pubCA2_ta3_key.pem
src/tests/ro_data/signing_certs/produced/keys/pubCA3_ta3_key.pem
src/tests/ro_data/signing_certs/produced/keys/pubCA4_ta3_key.pem
src/tests/ro_data/signing_certs/produced/keys/ta1_key.pem
src/tests/ro_data/signing_certs/produced/keys/ta2_key.pem
src/tests/ro_data/signing_certs/produced/keys/ta3_key.pem
src/tests/ro_data/signing_certs/produced/keys/ta4_key.pem
src/tests/ro_data/signing_certs/produced/keys/ta5_key.pem
src/tests/ro_data/signing_certs/produced/publisher_cas/03.pem
src/tests/ro_data/signing_certs/produced/publisher_cas/0C.pem
src/tests/ro_data/signing_certs/produced/publisher_cas/11.pem
src/tests/ro_data/signing_certs/produced/publisher_cas/13.pem
src/tests/ro_data/signing_certs/produced/publisher_cas/15.pem
src/tests/ro_data/signing_certs/produced/publisher_cas/17.pem
src/tests/ro_data/signing_certs/produced/publisher_cas/1B.pem
src/tests/ro_data/signing_certs/produced/publisher_cas/pubCA1_ta1_cert.pem
src/tests/ro_data/signing_certs/produced/publisher_cas/pubCA1_ta3_cert.pem
src/tests/ro_data/signing_certs/produced/publisher_cas/pubCA1_ta4_cert.pem
src/tests/ro_data/signing_certs/produced/publisher_cas/pubCA1_ta5_cert.pem
src/tests/ro_data/signing_certs/produced/publisher_cas/pubCA2_ta3_cert.pem
src/tests/ro_data/signing_certs/produced/publisher_cas/pubCA3_ta3_cert.pem
src/tests/ro_data/signing_certs/produced/publisher_cas/pubCA4_ta3_cert.pem
src/tests/ro_data/signing_certs/produced/serial
src/tests/ro_data/signing_certs/produced/ta1/ta1_cert.pem
src/tests/ro_data/signing_certs/produced/ta2/ta2_cert.pem
src/tests/ro_data/signing_certs/produced/ta3/ta3_cert.pem
src/tests/ro_data/signing_certs/produced/ta4/ta4_cert.pem
src/tests/ro_data/signing_certs/produced/ta5/ta5_cert.pem
src/tests/ro_data/signing_certs/produced/trust_anchors/ta1_cert.pem
src/tests/ro_data/signing_certs/produced/trust_anchors/ta2_cert.pem
src/tests/ro_data/signing_certs/produced/trust_anchors/ta3_cert.pem
src/tests/ro_data/signing_certs/produced/trust_anchors/ta4_cert.pem
src/tests/ro_data/signing_certs/produced/trust_anchors/ta5_cert.pem
src/tests/run.py
--- a/doc/client_api_versions.txt	Thu Aug 12 09:48:48 2010 -0700
+++ b/doc/client_api_versions.txt	Mon Aug 16 16:48:50 2010 -0700
@@ -1,3 +1,12 @@
+Version 41:
+Compatible with clients using versions 40-41.
+
+    Allows the client to handle signed packages.  This includes the addition
+    of a large number of optional parameters to the client/publisher class.
+    It also makes changes to image creation to allow image properties to be set
+    during the process.  New subclasses of ApiException were created to indicate
+    different error conditions associated with signing failures.
+
 Version 40:
 Incompatible with clients using versions 0-39.
 
--- a/doc/signed_manifests.txt	Thu Aug 12 09:48:48 2010 -0700
+++ b/doc/signed_manifests.txt	Mon Aug 16 16:48:50 2010 -0700
@@ -21,42 +21,59 @@
 
 As a result, it is a useful characteristic for signatures to be
 independent of other signatures in a manifest; it should be possible
-to add (or remove) signatures (but not other actions ) in a manifest
+to add (or remove) signatures (but not other actions) in a manifest
 without invalidating the other signatures that are present.  This
-features also facilitates production handoffs, with signatures used
+feature also facilitates production handoffs, with signatures used
 along the path to indicate completion along the way; subsequent steps
-can optionally remove previous signatures at any time w/o ill-effect.
+can optionally remove previous signatures at any time without ill-effect.
 
 The need to treat signatures differently during hash computation
 suggests that the signature itself should be easily distinguished from
 other sorts of package metadata; this leads us to a new signature
 action, of the form:
 
-signature type=x.509 hashtype=sha-256 sigtype=rsa-pkcs public_key=<hash> [public_key=<hash>] ... value=<hash> ...
+signature <hash of certificate> algorithm=<signature algorithm> \
+    value=<signature value> \
+    chain="<hashes of certs needed to validate primary certificate>" \
+    version=<pkg version of signature>
 
-where the public_key attribute(s) represent the packaging hash of the
+The payload and pkg.chain_certs attributes represent the packaging hash of the
 pem file(s) containing the x.509 certificate(s) downloadable from the
-originating repository; the value is the signed (SHA-256 in this case)
-hash of the manifest's message test, prepared as discussed below.  The
-certificate(s) so presented need to form a certificate path that leads
-to the trust anchor(s) that was established as part of the original
-repository configuration.  
+originating repository; the value is the signed hash of the manifest's message
+text, prepared as discussed below.  The payload certificate is the certificate
+which verifies the value in pkg.sigval.  The other certificates presented need
+to form a certificate path that leads from the payload certificate to the trust
+anchor(s) that was established as part of the publisher configuration.
+
+To compute the signature of a manifest, first a canonical representation of the
+manifest is created.  (See "Computing the manifest's message text" below.)  The
+message text is then given to the signature algorithm along with the private key
+and the result is the value of the signature.
 
-For testing and process verification purposes, a signature of type
-"identity" is also supported; this presents the unsigned hash as
-the value directly:
+Two types of signature algorithms are currently supported.  The first is rsa
+group of signature algorithms.  An example is "rsa-sha256".  The bit after the
+dash specifies the hash algorithm to use to change the message text into a
+single value the rsa algorithm can use.
 
-signature type=identity hashtype=sha256 value=<hash>
+The second type of signature algorithm is compute the hash only.  This type of
+algorithm exists primarily for testing and process verification purposes and
+presents the hash as the signature value.  A signature action of this type is
+indicated by the lack of a payload certificate hash.  This type of signature
+action is verified if the image is configured to check signatures.  Its
+presence however does not count as a signature if signatures are required.
+
+signature algorithm=<hash algorithm> value=<hash> \
+    version=<pkg version of signature>
 
 Additional signature types (pgp, for example) may be added in the future.
 
 Additional metadata can be added to a signature if desired, as with any
 other action.
 
-Policy constraints regarding required signatures on pkgs will specify
-a public key that must appear in the certificate path of a valid signature
-on a manifest to enable installation; such policy constraints may be
-applied to all repos or just one.
+Policies may be set for the image or for specific publishers.  The policies
+include ignoring signatures, verifying existing signatures, requiring
+signatures, and requiring that specific common names must be seen in the chain
+of trust.  Other policies may be added in the future.
 
 Computing the manifest's message text:
 --------------------------------------
@@ -69,18 +86,39 @@
 algorithm used for installation, as that may change over time.
 
 Straightforward C-locale alphabetical sorting of attributes within
-actions and across actions can be used to enforce a consistent
-ordering for signature purposes and is not subject to change
-for a given manifest.
+actions, the multiple values within those attributes, and across actions 
+can be used to enforce a consistent ordering for signature purposes and 
+is not subject to change for a given manifest.
 
 In order to allow other signatures to be added or removed from a
-manifest, computation of the manifest message test does not include
+manifest, computation of the manifest message text does not include
 other signatures; in order to protect metadata on the signature
 itself, the signature being produced or verified is included in the
 message text at the end, aside of course from the actual signature
 value itself.
 
-Verification of merged signatures
+For example, take the following manifest:
+set name=fmri [email protected]
+dir path=foo/bar group=sys
+signature cert1 algorithm=rsa-sha256 value=val1 random_attr=baz
+signature cert2 algorithm=rsa-sha256 value=val2 another_attr=whee
+
+The text used to compute val1 is:
+dir group=sys path=foo/bar
+set name=fmri [email protected]
+signature cert1 algorithm=rsa-sha256 value= random_attr=baz
+
+The text used to compute val2 is:
+dir group=sys path=foo/bar
+set name=fmri [email protected]
+signature cert2 another_attr=whee algorithm=rsa-sha256 value=
+
+Including the text of the signature action itself prevents the signature action
+from being modified.  Ensuring that the text used for compute val1 contains no
+mention of the second signature (or any other signature) allows signatures to be
+added and removed freely.
+
+Verification of merged signatures:
 ----------------------------------
 
 We produce "fat" packages (containing variants such as different
@@ -94,13 +132,108 @@
 
 Generally, signatures will be unique to their variant, thus they will
 be tagged with variant tags after merging.  To verify signatures
-post-merge, the evaluation process is a little different: any variant
-tags present on the signature are assumed to have added afterwards.
-Thus, to verify the signature those variants are applied to the entire
-manifest, and then the message text is generated, with the key step of
-removing all those variant tags from each action, if present.
+post-merge, the evaluation process has three steps after other signature actions
+have been removed from consideration.
+
+1) Any variant tags present on the signature are assumed to have been added
+after the merge.  Thus, all actions whose variants do not match the signature's
+variants are removed from inclusion in the message text.
+2) Since the variant tags were not present when the manifest was signed, they
+need to be removed from the attributes of each of the remaining actions as
+well.  This includes removing the set attributes which define the variants for
+the package.
+3) Restore any set actions in the existing_pkg_vars attribute which 
+describe variants which have been removed from the text.
+
+For example, consider the following manifest:
+set name=fmri [email protected]
+set name=variant.arch value=sparc value=i386
+set name=variant.debug value=true value=false
+dir path=foo1 group=sys
+dir path=foo2 variant.arch=sparc
+dir path=foo2/d variant.arch=sparc variant.debug=true
+dir path=foo2/nd variant.arch=sparc variant.debug=false
+dir path=foo3 variant.arch=i386
+signature cert1 algorithm=rsa-sha256 value=val1 random_attr=baz \
+    variant.arch=sparc variant.debug=true
+signature cert2 algorithm=rsa-sha256 value=val2 another_attr=whee \
+    variant.arch=i386 existing_pkg_vars="variant.arch=i386"
+
+To compute the message text for the first signature, the first step is applied
+producing the following text:
+set name=fmri [email protected]
+set name=variant.arch value=sparc value=i386
+set name=variant.debug value=true value=false
+dir path=foo1 group=sys
+dir path=foo2 variant.arch=sparc
+dir path=foo2/d variant.arch=sparc variant.debug=true
+signature cert1 algorithm=rsa-sha256 value=val1 random_attr=baz \
+    variant.arch=sparc variant.debug=true
+
+After the second step is applied, the text becomes:
+set name=fmri [email protected]
+dir path=foo1 group=sys
+dir path=foo2
+dir path=foo2/d
+signature cert1 algorithm=rsa-sha256 value=val1 random_attr=baz
+
+Since the third step doesn't apply to this signature, the above text becomes the
+canonical message text.
 
+Computing the message text for the second signature proceeds like this:
+After the first step the text is:
+set name=fmri [email protected]
+set name=variant.arch value=sparc value=i386
+set name=variant.debug value=true value=false
+dir path=foo1 group=sys
+dir path=foo3 variant.arch=i386
+signature cert2 algorithm=rsa-sha256 value=val2 another_attr=whee \
+    variant.arch=i386 existing_pkg_vars="variant.arch=i386"
 
+After the second step, the text is:
+set name=fmri [email protected]
+dir path=foo1 group=sys
+dir path=foo3
+signature cert2 algorithm=rsa-sha256 value=val2 another_attr=whee \
+    existing_pkg_vars="variant.arch=i386"
+
+In the third step, we restore the set action which was present in the original
+manifest.  The text becomes:
+set name=fmri [email protected]
+set name=variant.arch value=i386
+dir path=foo1 group=sys
+dir path=foo3
+signature cert2 algorithm=rsa-sha256 value=val2 another_attr=whee \
+    existing_pkg_vars="variant.arch=i386"
 
+The existing_pkg_vars attribute allows whether a package variant set
+action was present or not at the time of signing to be determined 
+deterministically.
 
+Publication of signed manifests:
+--------------------------------
 
+Publishing a signed manifest is a two step process.  First the package is
+published, unsigned, to a repository.  The package is then updated in place,
+using pkgsign, appending a signature action to the manifest in the repository
+but leaving the package, including its timestamp, intact.  This process allows a
+signature action to be added by someone other than the publisher without
+invalidating the publisher's signature.  For example, the QA department of a
+company may want to sign all packages that are installed internally to indicate
+they have been approved for use, but not republish the packages which would
+create a new timestamp and invalidate the signature of the original publisher.
+
+The disadvantage of this approach is that a fmri no longer represents a single
+manifest eternally.  Eventually, this problem is solved by having the client
+ensure that the hash of the manifest it loads for the fmri matches the hash in
+the catalog.  Until that feature is implemented, it is imperative that
+publishers ensure that no client has access to an unsigned manifest which they
+plan to sign in the future, or to return to the QA example, that no client
+inside the organization sees a manifest for a fmri without a signature which the
+QA plans to sign in the future.
+
+pkgsign is able to update a package in place through the use of a new publishing
+operation called append.  This operation opens a transaction to modify the
+manifest of a fmri which is already in the repository.  When the transaction is
+closed, the signed manifest replaces the existing manifest and the catalog is 
+updated to reflect the new hash of the manifest.
--- a/src/client.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/client.py	Mon Aug 16 16:48:50 2010 -0700
@@ -172,6 +172,8 @@
         pkg variant [-H] [<variant_spec>]
         pkg facet [-H] [<facet_spec>]
         pkg set-property propname propvalue
+        pkg add-property-value propname propvalue
+        pkg remove-property-value propname propvalue
         pkg unset-property propname ...
         pkg property [-H] [propname ...]
 
@@ -184,6 +186,13 @@
             [--reset-uuid] [--non-sticky] [--sticky]
             [--search-after=publisher]
             [--search-before=publisher]
+            [--approve-ca-cert=path_to_CA]
+            [--revoke-ca-cert=hash_of_CA_to_revoke]
+            [--unset-ca-cert=hash_of_CA_to_unset]
+            [--set-property name_of_property=value]
+            [--add-property-value name_of_property=value_to_add]
+            [--remove-property-value name_of_property=value_to_remove]
+            [--unset-property name_of_property_to_delete]
             [publisher]
         pkg unset-publisher publisher ...
         pkg publisher [-HPn] [publisher ...]
@@ -540,7 +549,7 @@
                                         continue
 
                                 # Informational messages are ignored by fix.
-                                entries.append((act, errors, warnings ))
+                                entries.append((act, errors, warnings))
 
                         if not entries:
                                 # Nothing to fix for this package.
@@ -552,8 +561,9 @@
 
                         failed = []
                         for act, errors, warnings in entries:
-                                failed.append(act)
-                                msg("\t%s" % act.distinguished_name())
+                                if act:
+                                        failed.append(act)
+                                        msg("\t%s" % act.distinguished_name())
                                 for x in errors:
                                         msg("\t\t%s" % x)
                                 for x in warnings:
@@ -597,7 +607,9 @@
                 except (api_errors.InvalidPlanError,
                     api_errors.InvalidPackageErrors,
                     api_errors.ActionExecutionError,
-                    api_errors.PermissionsException), e:
+                    api_errors.PermissionsException,
+                    api_errors.SigningException,
+                    api_errors.InvalidResourceLocation), e:
                         logger.error("\n")
                         logger.error(str(e))
                 except api_errors.PlanLicenseErrors, e:
@@ -702,7 +714,8 @@
                             "result": result })
 
                         for act, errors, warnings, pinfo in entries:
-                                msg("\t%s" % act.distinguished_name())
+                                if act:
+                                        msg("\t%s" % act.distinguished_name())
                                 for x in errors:
                                         msg("\t\t%s" % x)
                                 for x in warnings:
@@ -929,7 +942,9 @@
         if e_type in (api_errors.CertificateError,
             api_errors.UnknownErrors,
             api_errors.PlanCreationException,
-            api_errors.PermissionsException):
+            api_errors.PermissionsException,
+            api_errors.InvalidPropertyValue,
+            api_errors.InvalidResourceLocation):
                 # Prepend a newline because otherwise the exception will
                 # be printed on the same line as the spinner.
                 error("\n" + str(e))
@@ -937,6 +952,9 @@
         if e_type == fmri.IllegalFmri:
                 error(e, cmd=op)
                 return False
+        if isinstance(e, api_errors.SigningException):
+                error(e)
+                return False
 
         # if we didn't deal with the exception above, pass it on.
         raise
@@ -2397,7 +2415,17 @@
             remove] [-m|--add-mirror mirror to add] [-M|--remove-mirror mirror
             to remove] [-p repo_uri] [--enable] [--disable] [--no-refresh]
             [--sticky] [--non-sticky ] [--search-before=publisher]
-            [--search-after=publisher] [publisher]"""
+            [--search-after=publisher]
+            [--approve-ca-cert path to CA]
+            [--revoke-ca-cert hash of CA to remove]
+            [--unset-ca-cert hash of CA to unset]
+            [--set-property name of property=value]
+            [--add-property-value name of property=value to add]
+            [--remove-property-value name of property=value to remove]
+            [--unset-property name of property to delete]
+            [publisher] """
+
+        cmd_name = "set-publisher"
 
         preferred = False
         ssl_key = None
@@ -2418,11 +2446,21 @@
         sys_repo_uri = None
         socket_path = None
 
+        approved_ca_certs = []
+        revoked_ca_certs = []
+        unset_ca_certs = []
+        set_props = {}
+        add_prop_values = {}
+        remove_prop_values = {}
+        unset_props = set()
+
         opts, pargs = getopt.getopt(args, "Pedk:c:O:G:g:M:m:p:",
             ["add-mirror=", "remove-mirror=", "add-origin=",
             "clear-system-repo", "remove-origin=", "no-refresh", "reset-uuid",
             "enable", "disable", "sticky", "non-sticky", "search-before=",
-            "search-after=", "system-repo=", "socket-path="])
+            "search-after=", "system-repo=", "socket-path=", "approve-ca-cert=",
+            "revoke-ca-cert=", "unset-ca-cert=", "set-property=",
+            "add-property-value=", "remove-property-value=", "unset-property="])
 
         for opt, arg in opts:
                 if opt == "-c":
@@ -2465,6 +2503,41 @@
                         sys_repo_uri = arg
                 elif opt == "--socket-path":
                         socket_path = arg
+                elif opt == "--approve-ca-cert":
+                        approved_ca_certs.append(arg)
+                elif opt == "--revoke-ca-cert":
+                        revoked_ca_certs.append(arg)
+                elif opt == "--unset-ca-cert":
+                        unset_ca_certs.append(arg)
+                elif opt == "--set-property":
+                        t = arg.split("=", 1)
+                        if len(t) < 2:
+                                usage(_("properties to be set must be of the "
+                                    "form '<name>=<value>'. This is what was "
+                                    "given: %s") % arg, cmd=cmd_name)
+                        if t[0] in set_props:
+                                usage(_("a property may only be set once in a "
+                                    "command. %s was set twice") % t[0],
+                                    cmd=cmd_name)
+                        set_props[t[0]] = t[1]
+                elif opt == "--add-property-value":
+                        t = arg.split("=", 1)
+                        if len(t) < 2:
+                                usage(_("property values to be added must be "
+                                    "of the form '<name>=<value>'. This is "
+                                    "what was given: %s") % arg, cmd=cmd_name)
+                        add_prop_values.setdefault(t[0], [])
+                        add_prop_values[t[0]].append(t[1])
+                elif opt == "--remove-property-value":
+                        t = arg.split("=", 1)
+                        if len(t) < 2:
+                                usage(_("property values to be removed must be "
+                                    "of the form '<name>=<value>'. This is "
+                                    "what was given: %s") % arg, cmd=cmd_name)
+                        remove_prop_values.setdefault(t[0], [])
+                        remove_prop_values[t[0]].append(t[1])
+                elif opt == "--unset-property":
+                        unset_props.add(arg)
 
         name = None
         if len(pargs) == 0 and not repo_uri:
@@ -2523,7 +2596,13 @@
                     search_after=search_after, reset_uuid=reset_uuid,
                     refresh_allowed=refresh_allowed, preferred=preferred,
                     socket_path=socket_path, clear_sys_repo=clear_sys_repo,
-                    sys_repo_uri=sys_repo_uri)
+                    sys_repo_uri=sys_repo_uri,
+                    set_props=set_props, add_prop_values=add_prop_values,
+                    remove_prop_values=remove_prop_values,
+                    unset_props=unset_props, approved_cas=approved_ca_certs,
+                    revoked_cas=revoked_ca_certs, unset_cas=unset_ca_certs,
+                    img=img)
+
                 rval, rmsg = ret
                 if rmsg:
                         error(rmsg, cmd="set-publisher")
@@ -2601,7 +2680,11 @@
                             add_origins=add_origins, ssl_cert=ssl_cert,
                             ssl_key=ssl_key, sticky=sticky,
                             search_after=search_after,
-                            search_before=search_before)
+                            search_before=search_before,
+                            set_props=set_props,
+                            add_prop_values=add_prop_values,
+                            remove_prop_values=remove_prop_values,
+                            unset_props=unset_props)
                         if rval == EXIT_OK:
                                 added.append(prefix)
                 else:
@@ -2664,7 +2747,11 @@
 
                         rval, rmsg = _set_pub_error_wrap(_add_update_pub, name,
                             [], api_inst, prefix, pub=dest_pub,
-                            add_mirrors=add_mirrors, add_origins=add_origins)
+                            add_mirrors=add_mirrors, add_origins=add_origins,
+                            set_props=set_props,
+                            add_prop_values=add_prop_values,
+                            remove_prop_values=remove_prop_values,
+                            unset_props=unset_props)
 
                         if rval == EXIT_OK:
                                 updated.append(prefix)
@@ -2714,7 +2801,9 @@
     add_origins=EmptyI, remove_origins=EmptyI, ssl_cert=None, ssl_key=None,
     search_before=None, search_after=None, socket_path=None, sys_repo_uri=None,
     reset_uuid=None, refresh_allowed=False, preferred=False,
-    clear_sys_repo=False):
+    clear_sys_repo=False, set_props=EmptyI, add_prop_values=EmptyI,
+    remove_prop_values=EmptyI, unset_props=EmptyI, approved_cas=EmptyI,
+    revoked_cas=EmptyI, unset_cas=EmptyI, img=None):
 
         repo = None
         new_pub = False
@@ -2810,10 +2899,39 @@
                         if ssl_key is not None:
                                 uri.ssl_key = ssl_key
 
+        if set_props or add_prop_values or remove_prop_values or unset_props:
+                pub.update_props(set_props=set_props,
+                    add_prop_values=add_prop_values,
+                    remove_prop_values=remove_prop_values,
+                    unset_props=unset_props)
+
         if new_pub:
                 api_inst.add_publisher(pub,
-                    refresh_allowed=refresh_allowed)
+                    refresh_allowed=refresh_allowed, approved_cas=approved_cas,
+                    revoked_cas=revoked_cas, unset_cas=unset_cas)
         else:
+                for ca in approved_cas:
+                        try:
+                                ca = os.path.normpath(
+                                    os.path.join(orig_cwd, ca))
+                                with open(ca, "rb") as fh:
+                                        s = fh.read()
+                        except EnvironmentError, e:
+                                if e.errno == errno.ENOENT:
+                                        raise api_errors.MissingFileArgumentException(
+                                            ca)
+                                elif e.errno == errno.EACCES:
+                                        raise api_errors.PermissionsException(
+                                            ca)
+                                raise
+                        pub.approve_ca_cert(s, manual=True)
+
+                for hsh in revoked_cas:
+                        pub.revoke_ca_cert(hsh)
+
+                for hsh in unset_cas:
+                        pub.unset_ca_cert(hsh)
+
                 api_inst.update_publisher(pub,
                     refresh_allowed=refresh_allowed)
 
@@ -3127,6 +3245,18 @@
                                         retcode = EXIT_PARTIAL
                         return retcode
 
+                def display_signing_certs(p):
+                        if p.approved_ca_certs:
+                                msg(_("         Approved CAs:"),
+                                    p.approved_ca_certs[0])
+                                for h in p.approved_ca_certs[1:]:
+                                        msg(_("                     :"), h)
+                        if p.revoked_ca_certs:
+                                msg(_("          Revoked CAs:"),
+                                    p.revoked_ca_certs[0])
+                                for h in p.revoked_ca_certs[1:]:
+                                        msg(_("                     :"), h)
+
                 for name in pargs:
                         # detailed print
                         pub = api_inst.get_publisher(prefix=name, alias=name)
@@ -3148,14 +3278,15 @@
 
                         msg(_("          Client UUID:"), pub.client_uuid)
                         msg(_("      Catalog Updated:"), dt)
+                        display_signing_certs(pub)
                         if pub.disabled:
                                 msg(_("              Enabled:"), _("No"))
                         else:
                                 msg(_("              Enabled:"), _("Yes"))
         return retcode
 
-def property_set(img, args):
-        """pkg set-property propname propvalue"""
+def property_add_value(img, args):
+        """pkg add-property-value propname propvalue"""
 
         # ensure no options are passed in
         opts, pargs = getopt.getopt(args, "")
@@ -3163,6 +3294,62 @@
                 propname, propvalue = pargs
         except ValueError:
                 usage(_("requires a property name and value"),
+                    cmd="property-add-value")
+
+        if propname == "preferred-publisher":
+                error(_("set-publisher must be used to change the preferred "
+                    "publisher"), cmd="property-add-value")
+                return EXIT_OOPS
+
+        try:
+                img.add_property_value(propname, propvalue)
+        except (api_errors.PermissionsException,
+            api_errors.InvalidPropertyValue), e:
+                # Prepend a newline because otherwise the exception
+                # will be printed on the same line as the spinner.
+                error("\n" + str(e), cmd="property-add-value")
+                return EXIT_OOPS
+        return EXIT_OK
+
+def property_remove_value(img, args):
+        """pkg remove-property-value propname propvalue"""
+
+        # ensure no options are passed in
+        opts, pargs = getopt.getopt(args, "")
+        try:
+                propname, propvalue = pargs
+        except ValueError:
+                usage(_("requires a property name and value"),
+                    cmd="property-remove-value")
+
+        if propname == "preferred-publisher":
+                error(_("set-publisher must be used to change the preferred "
+                    "publisher"), cmd="property-remove-value")
+                return EXIT_OOPS
+
+        try:
+                img.remove_property_value(propname, propvalue)
+        except (api_errors.PermissionsException,
+            api_errors.InvalidPropertyValue), e:
+                # Prepend a newline because otherwise the exception
+                # will be printed on the same line as the spinner.
+                error("\n" + str(e), cmd="property-remove-value")
+                return EXIT_OOPS
+        return EXIT_OK
+
+def property_set(img, args):
+        """pkg set-property propname propvalue [propvalue ...]"""
+
+        # ensure no options are passed in
+        opts, pargs = getopt.getopt(args, "")
+        try:
+                propname = pargs[0]
+                propvalues = pargs[1:]
+        except IndexError:
+                usage(_("requires a property name and at least one value"),
+                    cmd="set-property")
+        if len(propvalues) == 0:
+                usage(_("requires a property name and at least one value"),
                     cmd="set-property")
 
         if propname == "preferred-publisher":
@@ -3171,8 +3358,9 @@
                 return EXIT_OOPS
 
         try:
-                img.set_property(propname, propvalue)
-        except api_errors.PermissionsException, e:
+                img.set_property(propname, propvalues)
+        except (api_errors.PermissionsException,
+            api_errors.InvalidPropertyValue), e:
                 # Prepend a newline because otherwise the exception
                 # will be printed on the same line as the spinner.
                 error("\n" + str(e), cmd="set-property")
@@ -3314,6 +3502,8 @@
         component that consumes global zone-only information, such as various
         kernel statistics or device information."""
 
+        cmd_name = "image-create"
+        
         force = False
         imgtype = IMG_TYPE_USER
         is_zone = False
@@ -3329,11 +3519,12 @@
         sys_repo_uri = None
         variants = {}
         facets = pkg.facet.Facets()
+        set_props = {}
 
         opts, pargs = getopt.getopt(args, "fFPUza:g:m:p:k:c:",
             ["force", "full", "partial", "user", "zone", "authority=", "facet=",
                 "mirror=", "origin=", "publisher=", "no-refresh", "variant=",
-                "system-repo", "socket-path="])
+                "system-repo", "socket-path=", "set-property="])
 
         for opt, arg in opts:
                 # -a is deprecated and will be removed at a future date.
@@ -3377,9 +3568,9 @@
                         except ValueError:
                                 usage(_("variant arguments must be of the "
                                     "form '<name>=<value>'."),
-                                    cmd="image-create")
+                                    cmd=cmd_name)
                         variants[v_name] = v_value
-                if opt == "--facet":
+                elif opt == "--facet":
                         allow = { "TRUE":True, "FALSE":False }
                         f_name, f_value = arg.split("=", 1)
                         if not f_name.startswith("facet."):
@@ -3387,20 +3578,31 @@
                         if f_value.upper() not in allow:
                                 usage(_("Facet arguments must be"
                                     "form 'facet..=[True|False]'"),
-                                    cmd="image-create")
+                                    cmd=cmd_name)
                         facets[f_name] = allow[f_value.upper()]
+                elif opt == "--set-property":
+                        t = arg.split("=", 1)
+                        if len(t) < 2:
+                                usage(_("properties to be set must be of the "
+                                    "form '<name>=<value>'. This is what was "
+                                    "given: %s") % arg, cmd=cmd_name)
+                        if t[0] in set_props:
+                                usage(_("a property may only be set once in a "
+                                    "command. %s was set twice") % t[0],
+                                    cmd=cmd_name)
+                        set_props[t[0]] = t[1]
 
         if not pargs:
                 usage(_("an image directory path must be specified"),
-                    cmd="image-create")
+                    cmd=cmd_name)
         elif len(pargs) > 1:
                 usage(_("only one image directory path may be specified"),
-                    cmd="image-create")
+                    cmd=cmd_name)
         image_dir = pargs[0]
 
         if not pub_name and not pub_url:
                 usage(_("publisher argument must be of the form "
-                    "'<prefix>=<uri> or '<uri>''."), cmd="image-create")
+                    "'<prefix>=<uri> or '<uri>''."), cmd=cmd_name)
         elif not pub_name and not refresh_allowed:
                 usage(_("--no-refresh cannot be used with -p unless a "
                     "publisher prefix is provided."))
@@ -3429,7 +3631,7 @@
                     progtrack=progtrack, refresh_allowed=refresh_allowed,
                     socket_path=sock_path, ssl_cert=ssl_cert,
                     ssl_key=ssl_key, sys_repo=sys_repo_uri, repo_uri=repo_uri,
-                    variants=variants)
+                    variants=variants, props=set_props)
                 __img = api_inst.img
         except api_errors.InvalidDepotResponseException, e:
                 # Ensure messages are displayed after the spinner.
@@ -3439,18 +3641,18 @@
                     "location and the client's network configuration."
                     "\nAdditional details:\n\n%(error)s") %
                     { "pub_url": pub_url, "error": e },
-                    cmd="image-create")
+                    cmd=cmd_name)
                 print_proxy_config()
                 return EXIT_OOPS
         except api_errors.CatalogRefreshException, cre:
                 # Ensure messages are displayed after the spinner.
-                error("", cmd="image-create")
+                error("", cmd=cmd_name)
                 if display_catalog_failures(cre) == 0:
                         return EXIT_OOPS
                 else:
                         return EXIT_PARTIAL
         except api_errors.ApiException, e:
-                error(str(e), cmd="image-create")
+                error(str(e), cmd=cmd_name)
                 return EXIT_OOPS
         return EXIT_OK
 
@@ -3742,6 +3944,7 @@
                 return EXIT_OOPS
 
         cmds = {
+                "add-property-value"     : property_add_value,
                 "authority"        : publisher_list,
                 "change-facet"     : change_facet,
                 "change-variant"   : change_variant,
@@ -3759,6 +3962,7 @@
                 "purge-history"    : history_purge,
                 "rebuild-index"    : rebuild_index,
                 "refresh"          : publisher_refresh,
+                "remove-property-value"  : property_remove_value,
                 "search"           : search,
                 "set-authority"    : publisher_set,
                 "set-property"     : property_set,
--- a/src/man/Makefile	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/man/Makefile	Mon Aug 16 16:48:50 2010 -0700
@@ -19,8 +19,9 @@
 # CDDL HEADER END
 #
 
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+#
+# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+#
 
 all := TARGET = all
 link := TARGET = link
@@ -38,6 +39,7 @@
 	ln -sf $(PWD)/pkgrecv.1.txt /usr/share/man/cat1/pkgrecv.1
 	ln -sf $(PWD)/pkgrepo.1.txt /usr/share/man/cat1/pkgrepo.1
 	ln -sf $(PWD)/pkgsend.1.txt /usr/share/man/cat1/pkgsend.1
+	ln -sf $(PWD)/pkgsign.1.txt /usr/share/man/cat1/pkgsign.1
 	ln -sf $(PWD)/pm-updatemanager.1.txt /usr/share/man/cat1/pm-updatemanager.1
 	ln -sf $(PWD)/pkg.depotd.1m.txt /usr/share/man/cat1m/pkg.depotd.1m
 	ln -sf $(PWD)/pkg.5.txt /usr/share/man/man5/pkg.5
@@ -48,6 +50,7 @@
 	rm -f /usr/share/man/cat1/pkgrecv.1
 	rm -f /usr/share/man/cat1/pkgrepo.1
 	rm -f /usr/share/man/cat1/pkgsend.1
+	rm -f /usr/share/man/cat1/pkgsign.1
 	rm -f /usr/share/man/cat1/pm-updatemanager.1
 	rm -f /usr/share/man/cat1m/pkg.depotd.1m
 	rm -f /usr/share/man/cat5/pkg.5
--- a/src/man/pkg.1.txt	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/man/pkg.1.txt	Mon Aug 16 16:48:50 2010 -0700
@@ -43,6 +43,8 @@
          [--licenses] <facet_spec>=[True|False|None] ...
 
      /usr/bin/pkg set-property propname propvalue
+     /usr/bin/pkg add-property-value propname propvalue
+     /usr/bin/pkg remove-property-value propname propvalue
      /usr/bin/pkg unset-property propname ...
      /usr/bin/pkg property [-H] [propname ...]
 
@@ -54,6 +56,13 @@
          [-p repo_uri] [--enable] [--disable] [--no-refresh]
          [--reset-uuid] [--non-sticky] [--sticky]
          [--search-after=publisher] [--search-before=publisher]
+         [--approve-ca-cert=path_to_CA]
+         [--revoke-ca-cert=hash_of_CA_to_remove]
+         [--unset-ca-cert=hash_of_CA_to_remove]
+         [--set-property name_of_property=value]
+         [--add-property-value name_of_property=value_to_add]
+         [--remove-property-value name_of_property=value_to_remove]
+         [--unset-property name_of_property_to_delete]
          [publisher]
      /usr/bin/pkg unset-publisher publisher ...
      /usr/bin/pkg publisher [-HPn] [publisher ...]
@@ -554,6 +563,15 @@
           except for preferred-publisher, which can only be changed using
           set-publisher.
 
+     add-property-value propname propvalue
+          Add a value to an existing image property or add a new image property;
+          except for preferred-publisher, which can only be changed using
+          set-publisher.
+
+     remove-property-value propname propvalue
+          Remove a value from an existing image property; except for 
+          preferred-publisher, which can only be changed using set-publisher.
+
      unset-property propname ...
           Remove an existing image property or properties; except for
           preferred-publisher, which can only be changed using
@@ -575,6 +593,13 @@
        [-p repo_uri] [--enable] [--disable] [--no-refresh]
        [--reset-uuid] [--non-sticky] [--sticky]
        [--search-after=publisher] [--search-before=publisher]
+       [--approve-ca-cert path_to_CA]
+       [--revoke-ca-cert hash_of_CA_to_remove]
+       [--unset-ca-cert hash_of_CA_to_remove]
+       [--set-property name_of_property=value]
+       [--add-property-value name_of_property=value_to_add]
+       [--remove-property-value name_of_property=value_to_remove]
+       [--unset-property name_of_property_to_delete]
        [publisher]
 
           Update an existing publisher or add an additional package
@@ -604,6 +629,30 @@
           the publisher being modified is now searched after the specified
           publisher.
 
+	  With --approve-ca-cert, add the given certificate as a CA certificate 
+          that is trusted.  The hashes of the user approved CA certificates are
+          listed in the output of the detailed pkg publisher view for a
+          publisher.
+
+          With --revoked-ca-cert, treat the certificate with the given hash as
+          revoked.  The hashes of the user revoked CA certificates are
+          listed in the output of the detailed pkg publisher view for a
+          publisher.
+
+          With --unset-ca-cert, remove the certificate with the given hash from
+          the list of approved and the list of revoked certificates.
+
+          With --set-property, update an existing publisher property or add a 
+          new publisher property.
+
+          With --add-property-value, add a value to an existing publisher 
+          property or add a new publisher property.
+
+          With --remove-property-value, remove a value from an existing 
+          publisher property.
+
+          With --unset-property, remove an existing publisher property.
+
           With -c and -k, specify client SSL certificate and key respectively.
 
           With -g (--add-origin), add the URI as an origin for the given
@@ -730,6 +779,56 @@
 
 	  Default value: True
 
+     signature-policy
+          (string)  Determine what checks will be performed on manifests
+          when installing a package into this image.  The final policy 
+          applied to a  package depends on the combination of image policy 
+          and publisher policy.  The combination will be at least as strict 
+          as the stricter of the two policies taken individually.  The 
+          following are the valid values for this property.
+
+          ignore
+               Ignore signatures for all manifests.
+          verify
+               Verify that all manifests with signatures are validly
+               signed, but do not require all installed packages to be 
+               signed.
+          require-signatures
+               Require that all newly installed packages have at least
+               one valid signature.  'pkg fix' and 'pkg verify' will also
+               warn if an installed package does not have a valid 
+               signature.
+          require-names
+               Follow the same requirements as 'require-signatures' but
+               also require that the strings listed in the 
+               'signature-required-names' property appear as a common
+               name of the certificates used to verifiy the chains
+               of trust of the signatures.
+
+     signature-required-names
+          (list of strings)  A list of names which must be seen as common
+          names of certificates while validating the signatures of a 
+          package.
+
+     trust-anchor-directory
+          (string)  The pathname of the directory that contains the trust 
+          anchors for the image.
+
+
+PUBLISHER PROPERTIES
+     The following properties are part of the image and may be set using
+     the set-property option of the set-publisher subcommand.
+
+     signature-policy
+          (string)  This property functions identically to the image
+          property of the same name except it only applies to packages
+          from the particular publisher.
+
+     signature-required-names
+          (list of strings)  This property functions identically to the 
+          image property of the same name except it only applies to 
+          packages from the particular publisher.
+
 EXAMPLES
      Example 1:  Create a new, full image, with publisher example.com,
      stored at /aux0/example_root.
@@ -843,6 +942,46 @@
 
      $ pkg set-publisher -g file:/export/repo example.com
 
+     Example 13:  Configure an image to verify all signed packages.
+
+     $ pkg set-property signature-policy verify
+
+     Example 14:  Configure an image to require all packages to be signed and
+     the string "opensolaris.org" has to be seen as a common name for one of
+     the certificates in the chain of trust.
+
+     $ pkg set-property signature-policy require-names opensolaris.org
+
+     Example 15:  Configure an image so that all packages installed from
+     publisher foo must be signed.
+
+     $ pkg set-publisher --set-property signature-policy=require-signatures
+
+     Example 16:  Add the string "foo" to the image's list of common names that 
+     must be seen in a signature's chain of trust to be considered valid.
+
+     $ pkg add-property-value signature-require-names foo
+
+     Example 17:  Remove the string "foo" from publisher test's list of common
+     names that must be seen to validate a signature.
+
+     $ pkg set-publisher --remove-property-value signature-require-names=foo \
+         test
+
+     Example 18:  Add the certificate stored in /tmp/example_file.pem as a
+     trusted CA certificate for the publisher test.
+
+     $ pkg set-publisher --approve-ca-cert /tmp/example_file.pem
+
+     Example 19:  Revoke the certificate with the hash a12345 for publisher 
+     test, preventing it from validating any signatures for packages from test.
+
+     $ pkg set-publisher --revoke-ca-cert a12345
+
+     Example 20:  Make pkg forget that the certificate a12345 was ever added or
+     revoked by the user.
+
+     $ pkg set-publisher --unset-ca-cert a12345
 
 EXIT STATUS
      The following exit values are returned:
--- a/src/man/pkgrepo.1.txt	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/man/pkgrepo.1.txt	Mon Aug 16 16:48:50 2010 -0700
@@ -19,6 +19,11 @@
      /usr/bin/pkgrepo rebuild [--no-index]
      /usr/bin/pkgrepo refresh [--no-catalog] [--no-index]
 
+     /usr/bin/pkgrepo add-signing-ca-cert path ...
+     /usr/bin/pkgrepo add-signing-intermediate-cert path ...
+     /usr/bin/pkgrepo remove-signing-ca-cert hash ...
+     /usr/bin/pkgrepo remove-signing-intermediate-cert hash ...
+
      /usr/bin/pkgrepo version
      /usr/bin/pkgrepo help
 
@@ -45,6 +50,14 @@
 SUBCOMMANDS
      The following subcommands are supported:
 
+     add-signing-ca-certs path ...
+          Add the certificates provided as approved CA certificates for the 
+          publisher.
+
+     add-signing-intermediate-certs path ...
+          Add the certificates provided as intermediate certificates for the 
+          publisher.
+
      create <uri_or_path>
           Creates a pkg(5) repository at the specified location.  This
           command can only be used to create filesystem-based
@@ -96,6 +109,14 @@
 
           With --no-index, don't update search indexes.
 
+     remove-signing-ca-certs hash ...
+          Remove the certificates provided from the list of CA certificates for
+          the publisher.
+
+     remove-signing-intermediate-certs hash ...
+          Remove the certificates provided from the list of intermediate 
+          certificates for the publisher.
+
      version
           Display a unique string identifying the version of the
           pkg(5) system.  The values produced by the version
@@ -128,6 +149,16 @@
 
      $ pkgrepo -s http://example.com/repository refresh
 
+     Example 5:  Add the certificate stored in /tmp/example_file.pem as a
+     signing CA certificate for the repository located at /my/repository.
+
+     $ pkgrepo -s /my/repository add-signing-ca-cert /tmp/example_file.pem
+
+     Example 6:  Remove the certificate with hash a12345 from the list of
+     intermediate certificates for the repository located at /my/repository.
+
+     $ pkgrepo -s /my/repository remove-signing-intermediate-ca-cert a12345
+
 EXIT STATUS
      The following exit values are returned:
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/man/pkgsign.1.txt	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,101 @@
+User Commands                                        pkgsign(1)
+
+
+NAME
+     pkgsign - image packaging system signing utility
+
+SYNOPSIS
+     /usr/bin/pkgsign [-a hash_algorithm] [-c path_to_signing_certificate] 
+         [-i path_to_intermediate_cert] ... [-k path_to_private_key] 
+         [-s src_uri] [--help] [--no-index] [--no-catalog] [--sign-all |
+         fmri_with_timestamp ...]
+
+DESCRIPTION
+     pkgsign updates the manifest for the given fmri(s) in place in the 
+     repository by adding a signature action using the provided key and 
+     certificates.  The package modified will retain the original timestamp.
+
+OPTIONS
+     The following options are supported:
+
+     With -a, use the signature algorithm provided instead of the default, 
+     which is rsa-sha256.  The following are the currently supported signature 
+     algorithms: rsa-sha256, rsa-sha384, rsa-sha512, sha256, sha384, sha512.
+     A signature algorithm which only specifies a hash algorithm will cause the
+     signature value to be the hash of the manifest of the package.  A signature
+     algorithm which specifies rsa and a hash algorithm will cause the signature
+     value to be the hash of the manifest signed with the private key provided
+     (see the -c and -k options).
+
+     With -c, add the certificate provided as the certificate to use when
+     verifying the value of the signature in the action.  It can only be used if
+     -k is also used.
+
+     With -i, add the certificate provided as a certificate to use when 
+     validating the certificate given as an argument to -c.  Multiple 
+     certificates may be provided by using -i multiple times.
+
+     With -k, use the private key stored in the given path to sign the 
+     manifest.  It can only be used if -c is also used.  If -k is not set,
+     then the signature value will be the hash of the manifest.
+
+     With -s, sign packages in the repository at the given URI.
+
+     With --help, show the usage information for the command.
+
+     With --no-index, tell the repository not to update the search indices
+     after the signed manifest has been republished.
+
+     With --no-catalog, tell the repository not to update the catalog after
+     the signed manifest has been republished.
+
+     With --sign-all, sign all the packages in the repository.
+
+EXAMPLES
+     Example 1:  Sign a package published to http://localhost:10000 using the 
+     hash value of the manifest.  This is often useful for testing.
+
+     $ pkgsign -s http://localhost:10000 -a sha256 \
+          [email protected],5.11-0:20100626T030108Z
+
+     Example 2: Sign a package published into the file repository in /foo/bar
+     using rsa-sha384 to hash and sign the manifest, the key in /key/usr2.key, 
+     its associated certificate in /key/usr2.cert, and a certificate needed to 
+     validate the certificate in /icerts/usr1.cert.
+
+     $ pkgsign -s file:///foo/bar/ -a rsa-sha384 -k /key/usr2.key \
+          -c /key/usr2.cert -i /icerts/usr1.cert \
+          [email protected],5.11-0:20100626T031341Z
+
+EXIT STATUS
+     The following exit values are returned:
+
+     0    Command succeeded.
+
+     1    An error occurred.
+
+     2    Invalid command line options were specified.
+
+     3    Multiple operations were requested, but only some of them
+          succeeded.
+
+ATTRIBUTES
+     See attributes(5) for descriptions of the following attributes:
+     ____________________________________________________________
+    |       ATTRIBUTE TYPE        |       ATTRIBUTE VALUE       |
+    |_____________________________|_____________________________|
+    | Availability                | pkg:/package/pkg            |
+    |_____________________________|_____________________________|
+    | Interface Stability         | None / Under Development    |
+    |_____________________________|_____________________________|
+
+SEE ALSO
+     pkg(1), pkgrecv(1), pkgsend(1), pkgrepo(1M), pkg(5)
+
+NOTES
+     The image packaging system is an under-development feature.
+     Command names, invocation, formats, and operations are all
+     subject to change.  Development is hosted in the OpenSolaris
+     community at:
+
+     http://hub.opensolaris.org/bin/view/Project+pkg/
--- a/src/modules/actions/file.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/modules/actions/file.py	Mon Aug 16 16:48:50 2010 -0700
@@ -21,8 +21,7 @@
 #
 
 #
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 """module describing a file packaging object
@@ -54,6 +53,8 @@
         key_attr = "path"
         globally_unique = True
 
+        has_payload = True
+
         def __init__(self, data=None, **attrs):
                 generic.Action.__init__(self, data, **attrs)
                 self.hash = "NOHASH"
--- a/src/modules/actions/generic.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/modules/actions/generic.py	Mon Aug 16 16:48:50 2010 -0700
@@ -76,6 +76,11 @@
         orderdict = {}
         unknown = 0
 
+        # The version of signature used.
+        sig_version = 0
+        # Most types of actions do not have a payload.
+        has_payload = False
+
         def loadorderdict(self):
                 ol = [
                         "set",
@@ -210,7 +215,7 @@
                 """
 
                 out = self.name
-                if hasattr(self, "hash"):
+                if hasattr(self, "hash") and self.hash is not None:
                         out += " " + self.hash
 
                 def q(s):
@@ -241,6 +246,57 @@
                                         out += " " + k + "=\"" + v.replace("\"", "\\\"") + "\""
                         else:
                                 out += " " + k + "=" + v
+                return out
+
+        def sig_str(self, a, ver):
+                """Create a stable string representation of an action that
+                is deterministic in its creation.  If creating a string from an
+                action is non-deterministic, then manifest signing cannot work.
+
+                The parameter "a" is the signature action that's going to use
+                the string produced.  It's needed for the signature string
+                action, and is here to keep the method signature the same.
+                """
+
+                # Any changes to this function or any subclasses sig_str mean
+                # Action.sig_version must be incremented.
+
+                if ver != Action.sig_version:
+                        raise apx.UnsupportedSignatureVersion(ver, sig=self)
+
+                out = self.name
+                if hasattr(self, "hash") and self.hash is not None:
+                        out += " " + self.hash
+
+                def q(s):
+                        if " " in s or "'" in s or "\"" in s or s == "":
+                                if "\"" not in s:
+                                        return '"%s"' % s
+                                elif "'" not in s:
+                                        return "'%s'" % s
+                                else:
+                                        return '"%s"' % s.replace("\"", "\\\"")
+                        else:
+                                return s
+
+                # Sort so that we get consistent action attribute ordering.
+                # We pay a performance penalty to do so, but it seems worth it.
+                for k in sorted(self.attrs.keys()):
+                        v = self.attrs[k]
+                        if isinstance(v, list) or isinstance(v, set):
+                                out += " " + " ".join([
+                                    "%s=%s" % (k, q(lmt)) for lmt in sorted(v)
+                                ])
+                        elif " " in v or "'" in v or "\"" in v or v == "":
+                                if "\"" not in v:
+                                        out += " " + k + "=\"" + v + "\""
+                                elif "'" not in v:
+                                        out += " " + k + "='" + v + "'"
+                                else:
+                                        out += " " + k + "=\"" + \
+                                            v.replace("\"", "\\\"") + "\""
+                        else:
+                                out += " " + k + "=" + v
 
                 return out
 
--- a/src/modules/actions/license.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/modules/actions/license.py	Mon Aug 16 16:48:50 2010 -0700
@@ -21,8 +21,7 @@
 #
 
 #
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 """module describing a license packaging object
@@ -50,6 +49,8 @@
         key_attr = "license"
         reverse_indices = ("license", )
 
+        has_payload = True
+
         def __init__(self, data=None, **attrs):
                 generic.Action.__init__(self, data, **attrs)
                 self.hash = "NOHASH"
--- a/src/modules/actions/signature.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/modules/actions/signature.py	Mon Aug 16 16:48:50 2010 -0700
@@ -21,16 +21,342 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
+import os
+import shutil
+import tempfile
+
 import generic
+import pkg.actions
+import pkg.client.api_errors as apx
+import pkg.misc as misc
+import M2Crypto as m2
+
+valid_hash_algs = ("sha256", "sha384", "sha512")
+valid_sig_algs = ("rsa",)
 
 class SignatureAction(generic.Action):
-        """Stub signature class to allow clients to function when signature
-        actions start appearing in the catalog."""
+        """Class representing the signature-type packaging object."""
 
-        __slots__ = ["hash"]
+        __slots__ = ["hash", "hash_alg", "sig_alg", "cert_ident",
+            "chain_cert_openers"]
 
         name = "signature"
+        key_attr = "value"
+
+        def __init__(self, data, **attrs):
+                generic.Action.__init__(self, data, **attrs)
+
+                self.hash = None
+                self.chain_cert_openers = []
+
+                try:
+                        self.sig_alg, self.hash_alg = self.decompose_sig_alg(
+                            self.attrs["algorithm"])
+                except KeyError:
+                        raise pkg.actions.InvalidActionError(str(self),
+                            _("Missing algorithm attribute"))
+                if "value" not in self.attrs:
+                        self.attrs["value"] = ""
+                if "version" not in self.attrs:
+                        self.attrs["version"] = \
+                            str(generic.Action.sig_version)
+
+        @property
+        def has_payload(self):
+                # If there's a hash, then there's a certificate to deliver
+                # with this action.
+                if not self.hash:
+                        return False
+                return True
+
+        @staticmethod
+        def make_opener(pth):
+                def file_opener():
+                        return open(pth, "rb")
+                return file_opener
+
+        def __set_chain_certs_data(self, chain_certs):
+                """Store the information about the certs needed to validate
+                this signature in the signature.
+
+                The 'chain_certs' parameter is a list of paths to certificates.
+                """
+
+                self.chain_cert_openers = []
+                hshes = []
+                sizes = []
+                for pth in chain_certs:
+                        if not os.path.exists(pth):
+                                raise pkg.actions.ActionDataError(
+                                    _("No such file: '%s'.") % pth, path=pth)
+                        elif os.path.isdir(pth):
+                                raise pkg.actions.ActionDataError(
+                                    _("'%s' is not a file.") % pth, path=pth)
+                        file_opener = self.make_opener(pth)
+                        self.chain_cert_openers.append(file_opener)
+                        self.attrs.setdefault("chain.sizes", [])
+                        try:
+                                fs = os.stat(pth)
+                                sizes.append(str(fs.st_size))
+                        except EnvironmentError, e:
+                                raise pkg.actions.ActionDataError(e, path=pth)
+                        # misc.get_data_digest takes care of closing the file
+                        # that's opened below.
+                        with file_opener() as fh:
+                                hsh, data = misc.get_data_digest(fh,
+                                    length=fs.st_size, return_content=True)
+                        hshes.append(hsh)                        
+                if hshes:
+                        # These attributes are stored as a single value with
+                        # spaces in it rather than multiple values to ensure
+                        # the ordering remains consistent.
+                        self.attrs["chain.sizes"] = " ".join(sizes)
+                        self.attrs["chain"] = " ".join(hshes)
+
+        def sig_str(self, a, version):
+                """Create a stable string representation of an action that
+                is deterministic in its creation.  If creating a string from an
+                action is non-deterministic, then manifest signing cannot work.
+
+                The parameter 'a' is the signature action that's going to use
+                the string produced.  It's needed for the signature string
+                action, and is here to keep the method signature the same.
+                """
+
+                # Any changes to this function mean Action.sig_version must be
+                # incremented.
+
+                if version != generic.Action.sig_version:
+                        raise apx.UnsupportedSignatureVersion(version, sig=self)
+                # Signature actions don't sign other signature actions.  So if
+                # the action that's doing the signing isn't ourself, return
+                # nothing.
+                if str(a) != str(self):
+                        return None
+
+                # It's necessary to sign the action as the client will see it,
+                # post publication.  To do that, it's necessary to simulate the
+                # publication process on a copy of the action, converting
+                # paths to hashes and adding size information.
+                tmp_a = SignatureAction(None, **self.attrs)
+                # The signature action can't sign the value of the value
+                # attribute, but it can sign that attribute's name.
+                tmp_a.attrs["value"] = ""
+                if callable(self.data):
+                        size = int(self.attrs.get("pkg.size", 0))
+                        tmp_dir = tempfile.mkdtemp()
+                        with self.data() as fh:
+                                tmp_a.hash, data = misc.get_data_digest(fh,
+                                    size, return_content=True)
+                        csize, chash = misc.compute_compressed_attrs(
+                            os.path.basename(self.hash), self.hash, data, size,
+                            tmp_dir)
+                        shutil.rmtree(tmp_dir)
+                        tmp_a.attrs["pkg.csize"] = csize
+                        tmp_a.attrs["chash"] = chash.hexdigest()
+                elif self.hash:
+                        tmp_a.hash = self.hash
+
+                hashes = []
+                csizes = []
+                chashes = []
+                sizes = self.attrs.get("chain.sizes", "").split()
+                for i, c in enumerate(self.chain_cert_openers):
+                        size = int(sizes[i])
+                        tmp_dir = tempfile.mkdtemp()
+                        hsh, data = misc.get_data_digest(c(), size,
+                            return_content=True)
+                        hashes.append(hsh)
+                        csize, chash = misc.compute_compressed_attrs("tmp",
+                            None, data, size, tmp_dir)
+                        shutil.rmtree(tmp_dir)
+                        csizes.append(csize)
+                        chashes.append(chash.hexdigest())
+                if hashes:
+                        tmp_a.attrs["chain"] = " ".join(hashes)
+
+                # Now that tmp_a looks like the post-published action, transform
+                # it into a string using the generic sig_str method.
+                return generic.Action.sig_str(tmp_a, tmp_a, version)
+ 
+        def actions_to_str(self, acts, version):
+                """Transforms a collection of actions into a string that is
+                used to sign those actions."""
+
+                # If a is None, then the action was another signature action so
+                # discard it from the information to be signed.
+                return "\n".join(sorted(
+                    (a for a in
+                     (b.sig_str(self, version) for b in acts)
+                     if a is not None)))
+
+        def get_chain_certs(self, pub):
+                """Retrieve the intermediate certificates needed to validate
+                this signature."""
+
+                for c in self.attrs.get("chain", "").split():
+                        pub.get_cert_by_hash(c, only_retrieve=True)
+
+        def is_signed(self):
+                """Returns True if this action is signed using a key, instead
+                of simply being a hash.  Since variant tagged signature
+                actions are not handled yet, it also returns False in that
+                case."""
+
+                return self.hash is not None and not self.get_variants()
+
+        @staticmethod
+        def decompose_sig_alg(val):
+                """Split the sig_alg attribute up in to something useful."""
+
+                for s in valid_sig_algs:
+                        for h in valid_hash_algs:
+                                t = "%s-%s" % (s, h)
+                                if val == t:
+                                        return s, h
+                for h in valid_hash_algs:
+                        if h == val:
+                                return None, h
+                return None, None
+
+        def verify_sig(self, acts, pub, required_names=None):
+                """Try to verify this signature.  It can return True or
+                None.  None means we didn't know how to verify this signature.
+                If we do know how to verify the signature but it doesn't verify,
+                then an exception is raised.
+
+                The 'acts' parameter is the iterable of actions against which
+                to verify the signature.
+
+                The 'pub' parameter is the publisher that published the
+                package this action signed.
+
+                The 'required_names' parameter is a set of strings that must
+                be seen as a CN in the chain of trust for the certificate."""
+
+                ver = int(self.attrs["version"])
+                # If this signature is tagged with variants, if the version is
+                # higher than one we know about, or it uses an unrecognized
+                # hash algorithm, we can't handle it yet.
+                if self.get_variants() or ver > generic.Action.sig_version or \
+                    not self.hash_alg:
+                        return None
+                # Turning this into a list makes debugging vastly more
+                # tractable.
+                acts = list(acts)
+                # If self.hash is None, then the signature is storing a hash
+                # of the actions, not a signed value.
+                if self.hash is None:
+                        assert self.sig_alg is None
+                        dgst = m2.EVP.MessageDigest(self.hash_alg)
+                        res = dgst.update(self.actions_to_str(acts, ver))
+                        assert res == 1, \
+                            "Res was expected to be 1, but was %s" % res
+                        computed_hash = dgst.final()
+                        # The attrs value is stored in hex so that it's easy
+                        # to read.
+                        if misc.hex_to_binary(self.attrs["value"]) != \
+                            computed_hash:
+                                raise apx.UnverifiedSignature(self,
+                                    _("The signature value did not match the "
+                                    "expected value. action:%s") % self)
+                        return True
+                # Verify a signature that's not just a hash.
+                if self.sig_alg is None:
+                        return None
+                # Get the approved CA certs for this publisher.
+                ca_dict = pub.get_ca_certs()
+                # Get the certificate paired with the key which signed this
+                # action.
+                cert = pub.get_cert_by_hash(self.hash, verify_hash=True)
+                # Make sure that the intermediate certificates that are needed
+                # to validate this signature are present.
+                self.get_chain_certs(pub)
+                try:
+                        # Verify the certificate whose key created this
+                        # signature action.
+                        pub.verify_chain(cert, ca_dict, required_names)
+                except apx.SigningException, e:
+                        e.act = self
+                        raise
+                # Check that the certificate verifies against this signature.
+                pub_key = cert.get_pubkey(md=self.hash_alg)
+                pub_key.verify_init()
+                pub_key.verify_update(self.actions_to_str(acts, ver))
+                res = pub_key.verify_final(
+                    misc.hex_to_binary(self.attrs["value"]))
+                if not res:
+                        raise apx.UnverifiedSignature(self,
+                            _("The signature value did not match the expected "
+                            "value. Res: %s") % res)
+                return True
+
+        def set_signature(self, acts, key_path=None, chain_paths=misc.EmptyI):
+                """Sets the signature value for this action.
+
+                The 'acts' parameter is the iterable of actions this action
+                should sign.
+
+                The 'key_path' parameter is the path to the file containing the
+                private key which is used to sign the actions.
+
+                The 'chain_paths' parameter is an iterable of paths to
+                certificates which are needed to form the chain of trust from
+                the certificate associated with the key in 'key_path' to one of
+                the CAs for the publisher of the actions."""
+
+                # Turning this into a list makes debugging vastly more
+                # tractable.
+                acts = list(acts)
+
+                # If key_path is None, then set value to be the hash
+                # of the actions.
+                if key_path is None:
+                        # If no private key is set, then no certificate should
+                        # have been given.
+                        assert self.data is None
+                        dgst = m2.EVP.MessageDigest(self.hash_alg)
+                        res = dgst.update(self.actions_to_str(acts,
+                            generic.Action.sig_version))
+                        assert res == 1, \
+                            "Res was expected to be 1, it was %s" % res
+                        self.attrs["value"] = \
+                            misc.binary_to_hex(dgst.final())
+                else:
+                        # If a private key is used, then the certificate it's
+                        # paired with must be provided.
+                        assert self.data is not None
+                        self.__set_chain_certs_data(chain_paths)
+
+                        try:
+                                priv_key = m2.RSA.load_key(key_path)
+                        except m2.RSA.RSAError, e:
+                                raise apx.BadFileFormat(_("%s was expected to "
+                                    "be a RSA key but could not be read "
+                                    "correctly.") % key_path)
+                        signer = m2.EVP.PKey(md=self.hash_alg)
+                        signer.assign_rsa(priv_key, 1)
+                        del priv_key
+                        signer.sign_init()
+                        signer.sign_update(self.actions_to_str(acts,
+                            generic.Action.sig_version))
+
+                        self.attrs["value"] = \
+                            misc.binary_to_hex(signer.sign_final())
+
+        def generate_indices(self):
+                """Generates the indices needed by the search dictionary.  See
+                generic.py for a more detailed explanation."""
+
+                res = []
+                if self.hash is not None:
+                        res.append((self.name, "certificate", self.hash,
+                            self.hash))
+                res.append((self.name, "hash type",
+                    self.attrs["algorithm"], self.attrs["algorithm"]))
+                res.append((self.name, "signature", self.attrs["value"],
+                    self.attrs["value"]))
+                return res
--- a/src/modules/client/api.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/modules/client/api.py	Mon Aug 16 16:48:50 2010 -0700
@@ -60,7 +60,7 @@
 from pkg.client.imageplan import EXECUTED_OK
 from pkg.client import global_settings
 
-CURRENT_API_VERSION = 40
+CURRENT_API_VERSION = 41
 CURRENT_P5I_VERSION = 1
 
 # Image type constants.
@@ -125,7 +125,7 @@
                 This function can raise VersionException and
                 ImageNotFoundException."""
 
-                compatible_versions = set([CURRENT_API_VERSION])
+                compatible_versions = set([40, CURRENT_API_VERSION])
 
                 if version_id not in compatible_versions:
                         raise apx.VersionException(CURRENT_API_VERSION,
@@ -2299,13 +2299,17 @@
                 except StopIteration:
                         return False
 
-        def add_publisher(self, pub, refresh_allowed=True):
+        def add_publisher(self, pub, refresh_allowed=True,
+            approved_cas=misc.EmptyI, revoked_cas=misc.EmptyI,
+            unset_cas=misc.EmptyI):
                 """Add the provided publisher object to the image
                 configuration."""
                 try:
                         self.__img.add_publisher(pub,
                             refresh_allowed=refresh_allowed,
-                            progtrack=self.__progresstracker)
+                            progtrack=self.__progresstracker,
+                            approved_cas=approved_cas, revoked_cas=revoked_cas,
+                            unset_cas=unset_cas)
                 finally:
                         self.__img.cleanup_downloads()
 
@@ -2892,7 +2896,7 @@
     mirrors=misc.EmptyI, origins=misc.EmptyI, prefix=None, refresh_allowed=True,
     repo_uri=None, socket_path=None, ssl_cert=None, ssl_key=None,
     sys_repo=None, user_provided_dir=False, progtrack=None,
-    variants=misc.EmptyDict):
+    variants=misc.EmptyDict, props=misc.EmptyDict):
         """Creates an image at the specified location.
 
         'pkg_client_name' is a string containing the name of the client,
@@ -2932,6 +2936,9 @@
         UnknownRepositoryPublishers exception will be raised.  If not provided,
         'refresh_allowed' cannot be False.
 
+        'props' is an optional dictionary mapping image property names to values
+        to be set while creating the image.
+
         'refresh_allowed' is an optional boolean value indicating whether
         publisher configuration data and metadata can be retrieved during
         image creation.  If False, 'repo_uri' cannot be specified and
@@ -3106,7 +3113,7 @@
 
                 img.create(pubs, facets=facets, is_zone=is_zone,
                     progtrack=progtrack, refresh_allowed=refresh_allowed,
-                    variants=variants)
+                    variants=variants, props=props)
         except EnvironmentError, e:
                 if e.errno == errno.EACCES:
                         raise apx.PermissionsException(
--- a/src/modules/client/api_errors.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/modules/client/api_errors.py	Mon Aug 16 16:48:50 2010 -0700
@@ -24,6 +24,7 @@
 # Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
+import errno
 import os
 import urlparse
 
@@ -1389,6 +1390,213 @@
                     "attr": self.data, "scheme": self._args["scheme"] }
 
 
+class SigningException(ApiException):
+        """The base class for exceptions related to manifest signing."""
+
+        def __init__(self, pfmri=None, sig=None):
+                self.pfmri = pfmri
+                self.sig = sig
+
+        # This string method is used by subclasses to fill in the details
+        # about the package and signature involved.
+        def __str__(self):
+                if self.pfmri:
+                        if self.sig:
+                                return _("The relevant signature action is "
+                                    "found in %(pfmri)s and has a hash of "
+                                    "%(hsh)s") % \
+                                    {"pfmri": self.pfmri, "hsh": self.sig.hash}
+                        return _("The package involved is:%s") % self.pfmri
+                if self.sig:
+                        return _("The relevant signature action's value "
+                            "attribute is %s") % self.sig.attrs["value"]
+                return ""
+
+
+class BadFileFormat(SigningException):
+        """Exception used when a key, certificate or CRL file is not in a
+        recognized format."""
+
+        def __init__(self, txt):
+                self.txt = txt
+
+        def __str__(self):
+                return self.txt
+       
+
+class UnsupportedSignatureVersion(SigningException):
+        """Exception used when a signature reports a version which this version
+        of pkg(5) doesn't support."""
+
+        def __init__(self, version, *args, **kwargs):
+                SigningException.__init__(self, *args, **kwargs)
+                self.version = version
+
+        def __str__(self):
+                return _("The signature action %(act)s was made using a "
+                    "version (%(ver)s) this version of pkg(5) doesn't "
+                    "understand.") % {"act":self.sig, "ver":self.version}
+
+
+class CertificateException(SigningException):
+        """Base class for exceptions encountered while establishing the chain
+        of trust."""
+
+        def __init__(self, cert, pfmri=None):
+                SigningException.__init__(self, pfmri)
+                self.cert = cert
+
+
+class ModifiedCertificateException(CertificateException):
+        """Exception used when a certificate does not match its expected hash
+        value."""
+
+        def __init__(self, cert, path, pfmri=None):
+                CertificateException.__init__(self, cert, pfmri)
+                self.path = path
+        
+        def __str__(self):
+                return _("Certificate %s has been modified on disk. Its hash "
+                    "value is not what was expected.") % self.path
+
+
+class UntrustedSelfSignedCert(CertificateException):
+        """Exception used when a chain of trust is rooted in an untrusted
+        self-signed certificate."""
+
+        def __str__(self):
+                return _("Chain was rooted in an untrusted self-signed "
+                    "certificate.\n") + CertificateException.__str__(self)
+
+
+class BrokenChain(CertificateException):
+        """Exception used when a chain of trust can not be established between
+        the leaf certificate and a trust anchor."""
+
+        def __init__(self, cert, cert_exceptions, *args, **kwargs):
+                CertificateException.__init__(self, cert, *args, **kwargs)
+                self.ext_exs = cert_exceptions
+        
+        def __str__(self):
+                s = ""
+                if self.ext_exs:
+                        s = _("The following problems were encountered:\n") + \
+                        "\n".join([str(e) for e in self.ext_exs])
+                return _("The certificate which issued this "
+                    "certificate:%(subj)s could not be found. The issuer "
+                    "is:%(issuer)s\n") % {"subj":self.cert.get_subject(),
+                    "issuer":self.cert.get_issuer()} + s + \
+                    CertificateException.__str__(self)
+
+
+class RevokedCertificate(CertificateException):
+        """Exception used when a chain of trust contains a revoked certificate.
+        """
+
+        def __init__(self, cert, reason, *args, **kwargs):
+                CertificateException.__init__(self, cert, *args, **kwargs)
+                self.reason = reason
+
+        def __str__(self):
+                return _("This certificate was revoked:%(cert)s for this "
+                    "reason:\n%(reason)s") % {"cert":self.cert.get_subject(),
+                    "reason":self.reason} + CertificateException.__str__(self)
+
+
+class UnverifiedSignature(SigningException):
+        """Exception used when a signature could not be verified by the
+        expected certificate."""
+
+        def __init__(self, sig, reason, pfmri=None):
+                SigningException.__init__(self, pfmri)
+                self.sig = sig
+                self.reason = reason
+
+        def __str__(self):
+                if self.pfmri:
+                        return _("A signature in %(pfmri)s could not be "
+                            "verified for "
+                            "this reason:\n%(reason)s\nThe signature's hash is "
+                            "%(hash)s") % {"pfmri": self.pfmri,
+                            "reason": self.reason,
+                            "hash": self.sig.hash}
+                return _("The signature with this signature value:\n"
+                    "%(sigval)s\n could not be verified for this reason:\n"
+                    "%(reason)s\n") % {"reason": self.reason,
+                    "sigval": self.sig.attrs["value"]}
+
+
+class RequiredSignaturePolicyException(SigningException):
+        """Exception used when signatures were required but none were found."""
+
+        def __init__(self, pub, pfmri=None):
+                SigningException.__init__(self, pfmri)
+                self.pub = pub
+
+        def __str__(self):
+                pub_str = self.pub.prefix
+                if self.pfmri:
+                        return _("The policy for %(pub_str)s requires "
+                            "signatures to be present but no signature was "
+                            "found in %(fmri_str)s.") % \
+                            {"pub_str": pub_str, "fmri_str": self.pfmri}
+                return _("The policy for %(pub_str)s requires signatures to be "
+                    "present but no signature was found.") % {
+                    "pub_str": pub_str}
+
+
+class MissingRequiredNamesException(SigningException):
+        """Exception used when a signature policy required names to be seen
+        which weren't seen."""
+
+        def __init__(self, pub, missing_names, pfmri=None):
+                SigningException.__init__(self, pfmri)
+                self.pub = pub
+                self.missing_names = missing_names
+
+        def __str__(self):
+                pub_str = self.pub.prefix
+                if self.pfmri:
+                        return _("The policy for %(pub_str)s requires certain "
+                            "CNs to be seen in a chain of trust. The following "
+                            "required names couldn't be found for this "
+                            "package:%(fmri_str)s.\n%(missing)s") % \
+                            {"pub_str": pub_str, "fmri_str": self.pfmri,
+                            "missing": "\n".join(self.missing_names)}
+                return _("The policy for %(pub_str)s requires certain CNs to "
+                    "be seen in a chain of trust. The following required names "
+                    "couldn't be found.\n%(missing)s") % {"pub_str": pub_str,
+                    "missing": "\n".join(self.missing_names)}
+
+class UnsupportedCriticalExtension(SigningException):
+        """Exception used when a certificate in the chain of trust uses a
+        critical extension pkg5 doesn't understand."""
+
+        def __init__(self, cert, ext):
+                SigningException.__init__(self)
+                self.cert = cert
+                self.ext = ext
+
+        def __str__(self):
+                return _("The certificate whose subject is %(cert)s could not "
+                    "be verified "
+                    "because it uses a critical extension that pkg5 cannot "
+                    "handle yet.\nExtension name:%(name)s\nExtension "
+                    "value:%(val)s") % {"cert": self.cert.get_subject(),
+                    "name":self.ext.get_name(), "val":self.ext.get_value()}
+
+
+class InvalidPropertyValue(ApiException):
+        """Exception used when a property was set to an invalid value."""
+
+        def __init__(self, s):
+                ApiException.__init__(self)
+                self.str = s
+
+        def __str__(self):
+                return self.str
+
+
 class CertificateError(ApiException):
         """Base exception class for all certificate exceptions."""
 
@@ -1629,3 +1837,13 @@
         def __str__(self):
                 return _("the specified image path is not empty: %s.\nTo "
                     "override, use the -f (force) option.") % self.path
+
+
+def convert_environment_error(e, ignored_errors=EmptyI):
+        if e.errno in ignored_errors:
+                return None
+        if e.errno in (errno.EACCES, errno.EPERM):
+                return PermissionsException(e.filename)
+        if e.errno == errno.EROFS:
+                return ReadOnlyFileSystemException(e.filename)
+        return e
--- a/src/modules/client/image.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/modules/client/image.py	Mon Aug 16 16:48:50 2010 -0700
@@ -49,6 +49,7 @@
 import pkg.client.pkgplan               as pkgplan
 import pkg.client.progress              as progress
 import pkg.client.publisher             as publisher
+import pkg.client.sigpolicy             as sigpolicy
 import pkg.client.transport.transport   as transport
 import pkg.fmri
 import pkg.manifest                     as manifest
@@ -56,6 +57,7 @@
 import pkg.portable                     as portable
 import pkg.server.catalog
 import pkg.version
+import M2Crypto as m2
 
 from pkg.client.debugvalues import DebugValues
 from pkg.client.imagetypes import IMG_USER, IMG_ENTIRE
@@ -209,6 +211,8 @@
                 self.__lock = pkg.nrlock.NRLock()
                 self.__locked = False
                 self.__lockf = None
+                self.__sig_policy = None
+                self.__trust_anchors = None
 
                 # When users and groups are added before their database files
                 # have been installed, the actions store them temporarily in the
@@ -261,6 +265,52 @@
                 self.__catalogs = {}
 
         @property
+        def signature_policy(self):
+                """Returns the signature policy for this image."""
+
+                if self.__sig_policy is not None:
+                        return self.__sig_policy
+                if not self.cfg_cache:
+                        self.__load_config()
+                txt = self.cfg_cache.get_policy_str(
+                    imageconfig.SIGNATURE_POLICY)
+                names = self.cfg_cache.properties.get(
+                    "signature-required-names", [])
+                self.__sig_policy = sigpolicy.Policy.policy_factory(txt, names)
+                return self.__sig_policy
+
+        @property
+        def trust_anchors(self):
+                """Return a dictionary mapping subject hashes for certificates
+                this image trusts to those certs."""
+
+                if self.__trust_anchors is not None:
+                        return self.__trust_anchors
+                if not self.cfg_cache:
+                        self.__load_config()
+                trust_anchor_loc = self.cfg_cache.properties.get(
+                    "trust-anchor-directory", "/etc/certs/CA/")
+                if not os.path.isdir(trust_anchor_loc):
+                        raise api_errors.InvalidPropertyValue(_("The trust "
+                            "anchor for the image were expected to be found "
+                            "in %s, but that is not a directory.  Please set "
+                            "the image property 'trust-anchor-directory' to "
+                            "the correct path.") % trust_anchor_loc)
+                self.__trust_anchors = {}
+                for fn in os.listdir(trust_anchor_loc):
+                        pth = os.path.join(trust_anchor_loc, fn)
+                        if os.path.islink(pth):
+                                continue
+                        trusted_ca = m2.X509.load_cert(pth)
+                        # M2Crypto's subject hash doesn't match openssl's
+                        # subject hash so recompute it so all hashes are in the
+                        # same universe.
+                        s = trusted_ca.get_subject().as_hash()
+                        self.__trust_anchors.setdefault(s, [])
+                        self.__trust_anchors[s].append(trusted_ca)
+                return self.__trust_anchors
+
+        @property
         def locked(self):
                 """Returns a boolean value indicating whether the image is
                 currently locked."""
@@ -630,7 +680,7 @@
                         self.__rebuild_image_catalogs(progtrack=progtrack)
 
         def create(self, pubs, facets=EmptyDict, is_zone=False,  progtrack=None,
-            refresh_allowed=True, variants=EmptyDict):
+            props=EmptyDict, refresh_allowed=True, variants=EmptyDict):
                 """Creates a new image with the given attributes if it does not
                 exist; should not be used with an existing image.
 
@@ -645,6 +695,9 @@
 
                 'progtrack' is an optional ProgressTracker object.
 
+                'props' is an option dictionary mapping image property names to
+                values.
+
                 'variants' is an optional dictionary of variant names and
                 values.
 
@@ -660,6 +713,8 @@
                     self._get_publisher_meta_dir())
                 self.history.log_operation_start("image-create")
 
+                self.cfg_cache.properties.update(props)
+
                 # Determine and add the default variants for the image.
                 if is_zone:
                         self.cfg_cache.variants[
@@ -680,7 +735,7 @@
                 # Since multiple publishers are allowed, they are all
                 # added at once without any publisher data retrieval.
                 # A single retrieval is then performed afterwards, if
-                # allowed, to nimimize the amount of work the client
+                # allowed, to minimize the amount of work the client
                 # needs to perform.
                 for p in pubs:
                         self.add_publisher(p, refresh_allowed=False,
@@ -869,10 +924,10 @@
                                 self.cfg_cache.preferred_publisher = pub.prefix
                                 self.save_config()
 
-        def set_property(self, prop_name, prop_value):
+        def set_property(self, prop_name, prop_values):
                 assert prop_name != "preferred-publisher"
                 with self.locked_op("set-property"):
-                        self.cfg_cache.properties[prop_name] = prop_value
+                        self.cfg_cache.properties[prop_name] = prop_values
                         self.save_config()
 
         def get_property(self, prop_name):
@@ -887,6 +942,41 @@
                         del self.cfg_cache.properties[prop_name]
                         self.save_config()
 
+        def add_property_value(self, prop_name, prop_value):
+                assert prop_name != "preferred-publisher"
+                with self.locked_op("add-property-value"):
+                        t = self.cfg_cache.properties.setdefault(prop_name, [])
+                        if not isinstance(t, list):
+                                raise api_errors.InvalidPropertyValue(_(
+                                    "Cannot add a value to a single valued "
+                                    "property. The property name is:%(name)s "
+                                    "and the current value is:%(value)s") %
+                                    {"name":prop_name, "value":t})
+                        self.cfg_cache.properties[prop_name].append(prop_value)
+                        self.save_config()
+
+        def remove_property_value(self, prop_name, prop_value):
+                assert prop_name != "preferred-publisher"
+                with self.locked_op("remove-property-value"):
+                        t = self.cfg_cache.properties.get(prop_name, None)
+                        if not isinstance(t, list):
+                                raise api_errors.InvalidPropertyValue(_(
+                                    "Cannot remove a value from a single "
+                                    "valued property, unset must be used. The "
+                                    "property name is:%(name)s and the current "
+                                    "value is:%(value)s") %
+                                    {"name":prop_name, "value":t})
+                        try:
+                                self.cfg_cache.properties[prop_name].remove(
+                                    prop_value)
+                        except ValueError:
+                                raise api_errors.InvalidPropertyValue(_(
+                                    "Cannot remove the value %(value)s from "
+                                    "the property %(name)s because the value "
+                                    "is not in the property's list.") %
+                                    {"value":prop_value, "name":prop_name})
+                        self.save_config()
+
         def destroy(self):
                 """Destroys the image; image object should not be used
                 afterwards."""
@@ -913,7 +1003,8 @@
                 for p in self.cfg_cache.properties:
                         yield p
 
-        def add_publisher(self, pub, refresh_allowed=True, progtrack=None):
+        def add_publisher(self, pub, refresh_allowed=True, progtrack=None,
+            approved_cas=EmptyI, revoked_cas=EmptyI, unset_cas=EmptyI):
                 """Adds the provided publisher object to the image
                 configuration.
 
@@ -957,6 +1048,11 @@
                                         pub.validate_config()
                                         self.refresh_publishers(pubs=[pub],
                                             progtrack=progtrack)
+                                        # Check that all CA certs claimed by
+                                        # this publisher validate against the
+                                        # trust anchors for this image.
+                                        self.signature_policy.check_cas(pub,
+                                            self.trust_anchors)
                                 except Exception, e:
                                         # Remove the newly added publisher since
                                         # it is invalid or the retrieval failed.
@@ -970,6 +1066,28 @@
                                             pub.prefix)
                                         raise
 
+                        for ca in approved_cas:
+                                try:
+                                        ca = os.path.abspath(ca)
+                                        fh = open(ca, "rb")
+                                        s = fh.read()
+                                        fh.close()
+                                except EnvironmentError, e:
+                                        if e.errno == errno.ENOENT:
+                                                raise api_errors.MissingFileArgumentException(
+                                                    ca)
+                                        elif e.errno == errno.EACCES:
+                                                raise api_errors.PermissionsException(ca)
+                                        raise
+                                pub.approve_ca_cert(s, manual=True)
+
+                        for hsh in revoked_cas:
+                                pub.revoke_ca_cert(hsh)
+
+                        for hsh in unset_cas:
+                                pub.unset_ca_cert(hsh)
+                        
+
                         # Only after success should the configuration be saved.
                         self.save_config()
 
@@ -988,7 +1106,23 @@
                 'args' is a dict of additional keyword arguments to be passed
                 to each action verification routine."""
 
-                for act in self.get_manifest(fmri).gen_actions(
+                pub = self.get_publisher(prefix=fmri.get_publisher())
+                manf = self.get_manifest(fmri)
+                try:
+                        sig_pol = self.signature_policy.combine(
+                            pub.signature_policy)
+                        sig_pol.check_cas(pub, self.trust_anchors)
+                        sig_pol.process_signatures(
+                            manf.gen_actions_by_type(
+                                "signature", self.list_excludes()),
+                            manf.gen_actions(), pub)
+                except api_errors.SigningException, e:
+                        e.pfmri = fmri
+                        yield e.sig, [e], [], []
+                except api_errors.InvalidResourceLocation, e:
+                        yield [], [e], [], []
+
+                for act in manf.gen_actions(
                     self.list_excludes()):
                         errors, warnings, info = act.verify(self, pkg_fmri=fmri,
                             **args)
--- a/src/modules/client/imageconfig.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/modules/client/imageconfig.py	Mon Aug 16 16:48:50 2010 -0700
@@ -38,9 +38,10 @@
 import pkg.facet              as facet
 import pkg.fmri               as fmri
 import pkg.portable           as portable
+import pkg.client.sigpolicy   as sigpolicy
 import pkg.variant            as variant
 
-from pkg.misc import DictProperty
+from pkg.misc import DictProperty, SIGNATURE_POLICY
 # The default_policies dictionary defines the policies that are supported by
 # pkg(5) and their default values. Calls to the ImageConfig.get_policy method
 # should use the constants defined here.
@@ -48,10 +49,12 @@
 FLUSH_CONTENT_CACHE = "flush-content-cache-on-success"
 MIRROR_DISCOVERY = "mirror-discovery"
 SEND_UUID = "send-uuid"
+
 default_policies = {
     FLUSH_CONTENT_CACHE: False,
     MIRROR_DISCOVERY: False,
-    SEND_UUID: True
+    SEND_UUID: True,
+    SIGNATURE_POLICY: sigpolicy.DEFAULT_POLICY
 }
 
 CA_PATH = "ca-path"
@@ -86,7 +89,7 @@
                 self.__publishers = {}
                 self.__publisher_search_order = []
 
-                self.properties = dict((
+                self.__properties = dict((
                     (p, str(v))
                     for p, v in default_policies.iteritems()
                 ))
@@ -97,7 +100,7 @@
                 self.facets = facet.Facets()
                 self.variants = variant.Variants()
                 self.children = []
-
+                self.__delay_validation = False
 
         def __str__(self):
                 return "%s\n%s" % (self.__publishers, self.properties)
@@ -169,6 +172,14 @@
                         return policystr.lower() in ("true", "yes")
                 return default_policies[policy]
 
+        def get_policy_str(self, policy):
+                """Return a boolean value for the named policy.  Returns
+                the default value for the policy if the named policy is
+                not defined in the image configuration.
+                """
+                assert policy in default_policies
+                return self.__properties.get(policy, default_policies[policy])
+
         def read(self, path):
                 """Read the config files for the image from the given directory.
                 """
@@ -245,10 +256,16 @@
                         for o in cp.options("policy"):
                                 self.properties[o] = cp.get("policy", o)
 
+                # Set __delay_validation to be True so that the order the
+                # properties are read doesn't matter.
+                self.__delay_validation = True
                 if cp.has_section("property"):
                         for o in cp.options("property"):
                                 self.properties[o] = cp.get("property",
                                     o, raw=True).decode('utf-8')
+                self.__delay_validation = False
+                # Now validate the properties are consistent.
+                self.__validate_properties()
 
                 try:
                         preferred_publisher = \
@@ -337,7 +354,7 @@
                 # For compatibility, the preferred-publisher is written out
                 # as the preferred-authority.  Modify a copy so that we don't
                 # change the in-memory copy.
-                props = self.properties.copy()
+                props = self.__properties.copy()
                 try:
                         del props["preferred-publisher"]
                 except KeyError:
@@ -347,7 +364,11 @@
 
                 cp.add_section("property")
                 for p in props:
-                        cp.set("property", p, props[p].encode("utf-8"))
+                        if isinstance(props[p], basestring):
+                                cp.set("property", p, props[p].encode("utf-8"))
+                        else:
+                                cp.set("property", p, str(props[p]).encode(
+                                    "utf-8"))
 
                 cp.add_section("variant")
                 for f in self.variants:
@@ -370,6 +391,14 @@
                         c.add_section(section)
                         c.set(section, "alias", str(pub.alias))
                         c.set(section, "prefix", str(pub.prefix))
+                        c.set(section, "signing_ca_certs", str(
+                            pub.signing_ca_certs))
+                        c.set(section, "approved_ca_certs", str(
+                            pub.approved_ca_certs))
+                        c.set(section, "revoked_ca_certs", str(
+                            pub.revoked_ca_certs))
+                        c.set(section, "intermediate_certs", str(
+                            pub.inter_certs))
                         c.set(section, "disabled", str(pub.disabled))
                         c.set(section, "sticky", str(pub.sticky))
 
@@ -442,6 +471,9 @@
                         for key, val in repo_data.iteritems():
                                 c.set(section, "repo.%s" % key, str(val))
 
+                        for key, val in pub.properties.iteritems():
+                                c.set(section, "property.%s" % key, str(val))
+
                 # XXX Child images
 
                 for afile, acp in [(CFG_FILE, cp), (DA_FILE, da)]:
@@ -467,6 +499,7 @@
                 """Take a list in string representation and convert it back
                 to a Python list."""
 
+                list_str = list_str.encode("utf-8")
                 # Strip brackets and any whitespace
                 list_str = list_str.strip("][ ")
                 # Strip comma and any whitespeace
@@ -479,6 +512,7 @@
                 return lst
 
         def read_publisher(self, meta_root, cp, s):
+                # s is the section of the config file.
                 # publisher block has alias, prefix, origin, and mirrors
                 changed = False
                 try:
@@ -490,6 +524,38 @@
 
                 prefix = cp.get(s, "prefix")
 
+                try:
+                        ca_certs = self.read_list(cp.get(s, "signing_ca_certs"))
+                except ConfigParser.NoOptionError:
+                        ca_certs = []
+
+                try:
+                        approved_ca_certs = self.read_list(cp.get(s,
+                            "approved_ca_certs"))
+                except ConfigParser.NoOptionError:
+                        approved_ca_certs = []
+
+                try:
+                        revoked_ca_certs = self.read_list(cp.get(s,
+                            "revoked_ca_certs"))
+                except ConfigParser.NoOptionError:
+                        revoked_ca_certs = []
+
+                try:
+                        inter_certs = self.read_list(cp.get(s,
+                            "intermediate_certs"))
+                except ConfigParser.NoOptionError:
+                        inter_certs = []
+                try:
+                        signature_policy = cp.get(s, "signature_policy")
+                except ConfigParser.NoOptionError:
+                        signature_policy = sigpolicy.DEFAULT_POLICY
+                try:
+                        signature_names = self.read_list(cp.get(s,
+                            "signature-required-names"))
+                except ConfigParser.NoOptionError:
+                        signature_names = []
+
                 if prefix.startswith(fmri.PREF_PUB_PFX):
                         raise RuntimeError(
                             "Invalid Publisher name: %s" % prefix)
@@ -563,6 +629,14 @@
                 except ConfigParser.NoOptionError:
                         client_uuid = None
 
+                props = {}
+                for opt in cp.options(s):
+                        if not opt.startswith("property."):
+                                continue
+                        prop_name = opt[len("property."):]
+                        val = self.read_list(cp.get(s, opt))
+                        props[prop_name] = val
+
                 # Load selected repository data.
                 # XXX this is temporary until a switch to a more expressive
                 # configuration format is made.
@@ -666,7 +740,10 @@
 
                 pub = publisher.Publisher(prefix, alias=alias,
                     client_uuid=client_uuid, disabled=disabled,
-                    meta_root=pmroot, repositories=[r], sticky=sticky)
+                    meta_root=pmroot, repositories=[r], sticky=sticky,
+                    ca_certs=ca_certs, inter_certs=inter_certs, props=props,
+                    revoked_ca_certs=revoked_ca_certs,
+                    approved_ca_certs=approved_ca_certs)
 
                 # write out the UUID if it was set
                 if pub.client_uuid != client_uuid:
@@ -674,6 +751,100 @@
 
                 return prefix, pub, changed
 
+        def __get_prop(self, name):
+                """Accessor method for properties dictionary"""
+                return self.__properties[name]
+
+        def __validate_properties(self):
+                """Check that properties are consistent with each other."""
+
+                if self.__properties[SIGNATURE_POLICY] == "require-names":
+                        if not self.__properties.get("signature-required-names",
+                            None):
+                                raise api_errors.InvalidPropertyValue(_(
+                                    "At least one name must be provided for "
+                                    "the signature-required-names policy."))
+
+        def __set_prop(self, name, values):
+                """Accessor method to add a property"""
+
+                if name == SIGNATURE_POLICY:
+                        if isinstance(values, basestring):
+                                values = [values]
+                        policy_name = values[0]
+                        if policy_name not in sigpolicy.Policy.policies():
+                                raise api_errors.InvalidPropertyValue(_(
+                                    "%(val)s is not a valid value for this "
+                                    "property:%(prop)s") % {"val": policy_name,
+                                    "prop": SIGNATURE_POLICY})
+                        self.__properties[SIGNATURE_POLICY] = policy_name
+                        if policy_name == "require-names":
+                                # If __delay_validation is set, then it's
+                                # possible that signature-required-names was
+                                # set by a previous line in the cfg_cache
+                                # file.  If so, don't overwrite the values
+                                # that have already been read.
+                                if self.__delay_validation:
+                                        self.__properties.setdefault(
+                                            "signature-required-names", [])
+                                        self.__properties[
+                                            "signature-required-names"].extend(
+                                            values[1:])
+                                else:
+                                        self.__properties[
+                                            "signature-required-names"] = \
+                                            values[1:]
+                        else:
+                                if len(values) > 1:
+                                        raise api_errors.InvalidPropertyValue(
+                                            _("The %s signature-policy takes "
+                                            "no argument.") % policy_name)
+                elif name == "signature-required-names":
+                        if isinstance(values, basestring):
+                                values = self.read_list(values)
+                        self.__properties[name] = values
+                elif name == "trust-anchor-directory":
+                        if isinstance(values, list):
+                                if len(values) > 1:
+                                        raise api_errors.InvalidPropertyValue(
+                                            _("%(name)s is not a multivalued "
+                                            "property. Values are:%(value)r") %
+                                            {"name":name, "value":values})
+                                values = values[0]
+                        self.__properties[name] = values
+                else:
+                        self.__properties[name] = values
+                if not self.__delay_validation:
+                        self.__validate_properties()
+
+        def __del_prop(self, name):
+                """Accessor method for properties"""
+                del self.__properties[name]
+
+        def __prop_iter(self):
+                return self.__properties.__iter__()
+
+        def __prop_iteritems(self):
+                """Support iteritems on properties"""
+                return self.__properties.iteritems()
+
+        def __prop_keys(self):
+                """Support keys() on properties"""
+                return self.__properties.keys()
+
+        def __prop_values(self):
+                """Support values() on properties"""
+                return self.__properties.values()
+
+        def __prop_getdefault(self, name, value):
+                return self.__properties.get(name, value)
+
+        def __prop_setdefault(self, name, value):
+                return self.__properties.setdefault(name, value)
+
+        def __prop_update(self, d):
+                return self.__properties.update(d)
+
         # properties so we can enforce rules
 
         publisher_search_order = property(lambda self: self.__publisher_search_order[:])
@@ -682,3 +853,9 @@
         publishers = DictProperty(__get_publisher, __set_publisher, __del_publisher,
             __publisher_iteritems, __publisher_keys, __publisher_values, __publisher_iter,
             doc="A dict mapping publisher prefixes to publisher objects")
+
+        properties = DictProperty(__get_prop, __set_prop, __del_prop,
+            __prop_iteritems, __prop_keys, __prop_values, __prop_iter,
+            doc="A dict holding the properties for an image.",
+            fgetdefault=__prop_getdefault, fsetdefault=__prop_setdefault,
+            update=__prop_update)
--- a/src/modules/client/imageplan.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/modules/client/imageplan.py	Mon Aug 16 16:48:50 2010 -0700
@@ -485,11 +485,12 @@
                 self.__cached_actions[(name, key)] = d
                 return self.__cached_actions[(name, key)]
 
-        def __get_manifest(self, pfmri, intent):
+        def __get_manifest(self, pfmri, intent, all_variants=False):
                 """Return manifest for pfmri"""
                 if pfmri:
                         return self.image.get_manifest(pfmri, 
-                            all_variants=self.__variant_change, intent=intent)
+                            all_variants=all_variants or self.__variant_change,
+                            intent=intent)
                 else:
                         return manifest.NullCachedManifest
 
@@ -612,8 +613,10 @@
                         pp = pkgplan.PkgPlan(self.image, self.__progtrack,
                             self.__check_cancelation)
 
-                        pp.propose(oldfmri, self.__get_manifest(oldfmri, old_in),
-                                   newfmri, self.__get_manifest(newfmri, new_in))
+                        pp.propose(oldfmri,
+                            self.__get_manifest(oldfmri, old_in),
+                            newfmri, self.__get_manifest(newfmri, new_in,
+                            all_variants=True))
 
                         pp.evaluate(self.__old_excludes, self.__new_excludes)
 
--- a/src/modules/client/pkgplan.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/modules/client/pkgplan.py	Mon Aug 16 16:48:50 2010 -0700
@@ -20,8 +20,9 @@
 # CDDL HEADER END
 #
 
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+#
+# Copyright (c) 2007, 2010 Oracle and/or its affiliates.  All rights reserved.
+#
 
 import errno
 import itertools
@@ -139,6 +140,29 @@
                 if ddups:
                         raise RuntimeError(["Duplicate actions", ddups])
 
+                # If new actions are being installed, check the destination
+                # manifest for signatures.
+                if self.destination_fmri is not None:
+                        dest_pub = self.image.get_publisher(
+                            prefix=self.destination_fmri.get_publisher())
+                        signature_policy = self.image.signature_policy.combine(
+                            dest_pub.signature_policy)
+                        # Check that the publisher's CA certs validate against
+                        # the image's trust anchors.
+                        signature_policy.check_cas(dest_pub,
+                            self.image.trust_anchors)
+                        try:
+                                signature_policy.process_signatures(
+                                    self.__destination_mfst.gen_actions_by_type(
+                                        "signature", new_excludes),
+                                    self.__destination_mfst.gen_actions(),
+                                        dest_pub)
+                                self.__destination_mfst.exclude_content(
+                                    new_excludes)
+                        except apx.SigningException, e:
+                                e.pfmri = self.destination_fmri
+                                raise
+
                 self.actions = self.__destination_mfst.difference(
                     self.__origin_mfst, old_excludes, new_excludes)
 
--- a/src/modules/client/publisher.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/modules/client/publisher.py	Mon Aug 16 16:48:50 2010 -0700
@@ -33,11 +33,15 @@
 # the client version number and compatible_versions specifier found in
 # modules/client/api.py:__init__.
 #
+
 import calendar
 import copy
+import cStringIO
 import datetime as dt
 import errno
+import hashlib
 import os
+import pycurl
 import shutil
 import tempfile
 import time
@@ -49,10 +53,16 @@
 logger = global_settings.logger
 
 import pkg.catalog
+import pkg.actions.signature as signature
 import pkg.client.api_errors as api_errors
+import pkg.client.sigpolicy as sigpolicy
 import pkg.misc as misc
 import pkg.portable as portable
 import pkg.server.catalog as old_catalog
+import M2Crypto as m2
+
+from pkg.misc import EmptyI, SIGNATURE_POLICY, DictProperty
+from pkg.pkggzip import PkgGzipFile
 
 # The "core" type indicates that a repository contains all of the dependencies
 # declared by packages in the repository.  It is primarily used for operating
@@ -869,7 +879,8 @@
 
         def __init__(self, prefix, alias=None, client_uuid=None, disabled=False,
             meta_root=None, repositories=None, selected_repository=None,
-            transport=None, sticky=True):
+            transport=None, sticky=True, ca_certs=EmptyI, inter_certs=EmptyI,
+            props=None, revoked_ca_certs=EmptyI, approved_ca_certs=EmptyI):
                 """Initialize a new publisher object."""
 
                 if client_uuid is None:
@@ -897,6 +908,46 @@
                 if selected_repository:
                         self.selected_repository = selected_repository
 
+                self.__sig_policy = None
+                self.__delay_validation = False
+
+                self.__properties = {}
+
+                # Writing out an EmptyI to a config file and reading it back
+                # in doesn't work correctly at the moment, but reading and
+                # writing an empty list does. So if inter_certs is empty, make
+                # sure it's stored as an empty list.
+                #
+                # The relevant implementation is probably the line which
+                # strips ][ from the input in imageconfig.read_list.
+                if ca_certs:
+                        self.signing_ca_certs = ca_certs
+                else:
+                        self.signing_ca_certs = []
+
+                if revoked_ca_certs:
+                        self.revoked_ca_certs = revoked_ca_certs
+                else:
+                        self.revoked_ca_certs = []
+
+                if approved_ca_certs:
+                        self.approved_ca_certs = approved_ca_certs
+                else:
+                        self.approved_ca_certs = []
+
+                if inter_certs:
+                        self.inter_certs = inter_certs
+                else:
+                        self.inter_certs = []
+
+                if props:
+                        self.properties.update(props)
+
+                self.ca_dict = None
+
+                self.__verified_cas = False
+                self.__bad_ca_certs = set()
+
         def __cmp__(self, other):
                 if other is None:
                         return 1
@@ -923,7 +974,11 @@
                     client_uuid=self.__client_uuid, disabled=self.__disabled,
                     meta_root=self.meta_root, repositories=repositories,
                     selected_repository=selected, transport=self.transport,
-                    sticky=self.__sticky)
+                    sticky=self.__sticky, ca_certs=self.signing_ca_certs,
+                    props=self.properties,
+                    revoked_ca_certs=self.revoked_ca_certs,
+                    approved_ca_certs=self.approved_ca_certs,
+                    inter_certs=self.inter_certs)
                 pub._source_object_id = id(self)
                 return pub
 
@@ -1057,6 +1112,11 @@
                 self.__meta_root = pathname
                 if self.__catalog:
                         self.__catalog.meta_root = self.catalog_root
+                if self.__meta_root:
+                        self.cert_root = os.path.join(self.__meta_root, "certs")
+                        self.__subj_root = os.path.join(self.cert_root,
+                            "subject_hashes")
+                        self.__crl_root = os.path.join(self.cert_root, "crls")
 
         def __set_prefix(self, prefix):
                 if not misc.valid_pub_prefix(prefix):
@@ -1226,6 +1286,17 @@
                                         # If the path already exists, move on.
                                         # Otherwise, raise the exception.
                                         raise
+                # Optional roots not needed for all operations.
+                for path in (self.cert_root, self.__subj_root, self.__crl_root):
+                        try:
+                                os.makedirs(path)
+                        except EnvironmentError, e:
+                                if e.errno in (errno.EACCES, errno.EROFS):
+                                        pass
+                                elif e.errno != errno.EEXIST:
+                                        # If the path already exists, move on.
+                                        # Otherwise, raise the exception.
+                                        raise
 
         def get_repository(self, name=None, origin=None):
                 """Returns the repository object matching the name or that has
@@ -1720,6 +1791,533 @@
                             known=known, unknown=[self.prefix],
                             origins=self.selected_repository.origins)
 
+        def approve_ca_cert(self, cert, manual=False, trust_anchors=None,
+            img_policy=None):
+                """Add the cert as a CA for manifest signing for this publisher.
+
+                The 'cert' parameter as a string of the certificate to add.
+
+                The 'manual' parameter indicates whether this is a CA the user
+                has explicitly added.
+
+                The 'trust_anchors' parameter is a dictionary which contains
+                the trust anchors to use to validate the certificate.
+
+                The 'img_policy' parameter is the signature policy for the
+                image."""
+
+                assert manual or (trust_anchors and img_policy)
+                # Verifying this one certificate shouldn't change whether
+                # the publisher's CA certs have been verified.
+                old_verification_value = self.__verified_cas
+                # Mark that not all CA certs have been verified.
+                self.__verified_cas = False
+                hsh = self.add_cert(cert)
+                self.signing_ca_certs.append(hsh)
+                # If the user had previously removed this certificate, remove
+                # the certificate from that list.
+                if manual and hsh in self.revoked_ca_certs:
+                        t = set(self.revoked_ca_certs)
+                        t.remove(hsh)
+                        self.revoked_ca_certs = list(t)
+                        self.__bad_ca_certs.discard(hsh)
+                # If the user indicated that this cert should be approved, add
+                # it to the approved list. 
+                if manual:
+                        self.approved_ca_certs.append(hsh)
+                else:
+                        # If the user did not add this certificate manually,
+                        # then ensure that it validates against the image's
+                        # trust anchors.
+                        self.__verify_ca_cert(cert, trust_anchors, img_policy)
+                self.__verified_cas = old_verification_value
+
+        def revoke_ca_cert(self, s):
+                """Record that the cert with hash 's' is no longer trusted
+                as a CA.  This method currently assumes it's only invoked as
+                a result of user action."""
+
+                self.revoked_ca_certs.append(s)
+                self.revoked_ca_certs = list(set(
+                    self.revoked_ca_certs))
+                if s in self.approved_ca_certs:
+                        t = set(self.approved_ca_certs)
+                        t.remove(s)
+                        self.approved_ca_certs = list(t)
+
+        def unset_ca_cert(self, s):
+                """If the cert with hash 's' has been added or removed by the
+                user, undo the add or removal."""
+
+                if s in self.approved_ca_certs:
+                        t = set(self.approved_ca_certs)
+                        t.remove(s)
+                        self.approved_ca_certs = list(t)
+                if s in self.revoked_ca_certs:
+                        t = set(self.revoked_ca_certs)
+                        t.remove(s)
+                        self.revoked_ca_certs = list(t)
+
+        def add_cert(self, s):
+                """Add the certificate stored as a string in 's' to the
+                certificates this publisher knows about."""
+
+                self.create_meta_root()
+                pkg_hash = hashlib.sha1()
+                pkg_hash.update(s)
+                pkg_hash = pkg_hash.hexdigest()
+                pkg_hash_pth = os.path.join(self.cert_root, pkg_hash)
+                try:
+                        with open(pkg_hash_pth, "wb") as fh:
+                                fh.write(s)
+                except EnvironmentError, e:
+                        raise api_errors.convert_environment_error(e)
+                try:
+                        c = m2.X509.load_cert_string(s)
+                except m2.X509.X509Error, e:
+                        try:
+                                portable.remove(pkg_hash_pth)
+                        except:
+                                # Pass because the bad file format error is the
+                                # more important one.
+                                pass
+                        raise api_errors.BadFileFormat(_("The file with hash "
+                            "%s was expected to be a PEM certificate but it "
+                            "could not be read.") % pkg_hash)
+
+                # Note that while we store certs by their subject hashes,
+                # M2Crypto's subject hashes differ from what openssl reports
+                # the subject hash to be.
+                subj_hsh = c.get_subject().as_hash()
+                c = 0
+                made_link = False
+                while not made_link:
+                        fn = os.path.join(self.__subj_root,
+                            "%s.%s" % (subj_hsh, c))
+                        if os.path.exists(fn):
+                                c += 1
+                        else:
+                                try:
+                                        portable.link(pkg_hash_pth, fn)
+                                except EnvironmentError, e:
+                                        raise api_errors.convert_environment_error(e)
+                                made_link = True
+                return pkg_hash
+
+        def get_cert_by_hash(self, pkg_hash, verify_hash=False,
+            only_retrieve=False):
+                """Given a pkg5 hash, retrieve the cert that's associated with
+                it.
+
+                The 'pkg_hash' parameter contains the file hash of the
+                certificate to retrieve.
+
+                The 'verify_hash' parameter determines the file that's read
+                from disk matches the expected hash.
+
+                The 'only_retrieve' parameter determines whether a X509 object
+                is built from the certificate retrieved or if the certificate
+                is only stored on disk. """
+
+                assert not (verify_hash and only_retrieve)
+                pth = os.path.join(self.cert_root, pkg_hash)
+                if not os.path.exists(pth):
+                        self.add_cert(self.transport.get_content(self,
+                            pkg_hash))
+                if only_retrieve:
+                        return None
+                with open(pth, "rb") as fh:
+                        s = fh.read()
+                        c = m2.X509.load_cert_string(s)
+
+                if verify_hash:
+                        h = misc.get_data_digest(cStringIO.StringIO(s),
+                            length=len(s))[0]
+                        if h != pkg_hash:
+                                raise api_errors.ModifiedCertificateException(c,
+                                    pth)
+                return c
+
+        def get_certs_by_name(self, name):
+                """Given 'name', a M2Crypto X509_Name, return the certs with
+                that name as a subject."""
+
+                res = []
+                c = 0
+                name_hsh = name.as_hash()
+                try:
+                        while True:
+                                pth = os.path.join(self.__subj_root,
+                                    "%s.%s" % (name_hsh, c))
+                                cert = m2.X509.load_cert(pth)
+                                res.append(cert)
+                                c += 1
+                except EnvironmentError, e:
+                        t = api_errors.convert_environment_error(e,
+                            [errno.ENOENT])
+                        if t:
+                                raise t
+                return res
+
+        def get_ca_certs(self):
+                """Return a dictionary of the CA certificates for this
+                publisher."""
+
+                # The CA certs must be verified before this method is called.
+                assert self.__verified_cas
+                if self.ca_dict is not None:
+                        return self.ca_dict
+                self.ca_dict = {}
+                # CA certs approved for this publisher are stored by hash to
+                # prevent the later substitution or confusion over what certs
+                # have or have not been approved.
+                for h in (set(self.signing_ca_certs) -
+                    set(self.__bad_ca_certs)) | set(self.approved_ca_certs):
+                        c = self.get_cert_by_hash(h, verify_hash=True)
+                        s = c.get_subject().as_hash()
+                        self.ca_dict.setdefault(s, [])
+                        self.ca_dict[s].append(c)
+                return self.ca_dict
+
+        def get_intermediate_certs(self):
+                """Retrieve the intermediate certificates the publisher deemed
+                were necessary to validate its CA certificates against the
+                image's trust anchors."""
+
+                for c in self.inter_certs:
+                        self.get_cert_by_hash(c, verify_hash=True)
+
+        def update_props(self, set_props=EmptyI, add_prop_values=EmptyI,
+            remove_prop_values=EmptyI, unset_props=EmptyI):
+                """Update the properties set for this publisher with the ones
+                provided as arguments.  The order of application is that any
+                existing properties are unset, then properties are set to their
+                new values, then values are added to properties, and finally
+                values are removed from properties."""
+
+                # Delay validation so that any intermittent inconsistent state
+                # doesn't cause problems.
+                self.__delay_validation = True
+                # Remove existing properties.
+                for n in unset_props:
+                        self.properties.pop(n, None)
+                # Add or reset new properties.
+                self.properties.update(set_props)
+                # Add new values to properties.
+                for n in add_prop_values.keys():
+                        self.properties.setdefault(n, [])
+                        self.properties[n].extend(add_prop_values[n])
+                # Remove values from properties.
+                for n in remove_prop_values.keys():
+                        if n not in self.properties:
+                                raise api_errors.InvalidPropertyValue(_(
+                                    "Cannot remove a value from the property "
+                                    "%(name)s because the property does not "
+                                    "exist.") % {"name":n})
+                        if not isinstance(self.properties[n], list):
+                                raise api_errors.InvalidPropertyValue(_(
+                                    "Cannot remove a value from a single "
+                                    "valued property, unset must be used. The "
+                                    "property name is '%(name)s' and the "
+                                    "current value is '%(value)s'") %
+                                    {"name":n, "value":self.properties[n]})
+                        for v in remove_prop_values[n]:
+                                try:
+                                        self.properties[n].remove(v)
+                                except ValueError:
+                                        raise api_errors.InvalidPropertyValue(_(
+                                            "Cannot remove the value %(value)s "
+                                            "from the property %(name)s "
+                                            "because the value is not in the "
+                                            "property's list.") %
+                                            {"value":v, "name":n})
+                self.__delay_validation = False
+                self.__validate_properties()
+
+        def verify_ca_certs(self, trust_anchors):
+                """Verify the CA certs for this publisher against the image's
+                trust anchors."""
+
+                self.__bad_ca_certs = set(self.revoked_ca_certs)
+
+                self.get_intermediate_certs()
+                # The set of potential CA certs is all those certs the publisher
+                # declared minus the ones the user has explictly removed.
+                for c in set(self.signing_ca_certs) - \
+                    set(self.revoked_ca_certs):
+                        cert = self.get_cert_by_hash(c, verify_hash=True)
+                        try:
+                                self.verify_chain(cert, trust_anchors)
+                        except api_errors.CertificateException, e:
+                                # If the cert couldn't be verified, add it to
+                                # the certs to ignore for this operation but
+                                # don't treat it as if the user had declared
+                                # the cert untrustworthy.
+                                self.__bad_ca_certs.add(c)
+                self.__verified_cas = True
+
+        def __validate_properties(self):
+                """Check that the properties set for this publisher are
+                consistent with each other."""
+
+                if self.__properties.get(SIGNATURE_POLICY, "") == \
+                    "require-names":
+                        if not self.__properties.get("signature-required-names",
+                            None):
+                                raise api_errors.InvalidPropertyValue(_(
+                                    "At least one name must be provided for "
+                                    "the signature-required-names policy."))
+
+        def __format_safe_read_crl(self, pth):
+                """CRLs seem to frequently come in DER format, so try reading
+                the CRL using both of the formats before giving up."""
+
+                try:
+                        return m2.X509.load_crl(pth)
+                except m2.X509.X509Error, e:
+                        try:
+                                return m2.X509.load_crl(pth,
+                                    format=m2.X509.FORMAT_DER)
+                        except m2.X509.X509Error, e:
+                                raise api_errors.BadFileFormat(_("The CRL file "
+                                    "%s is not in a recognized format.") %
+                                    pth)
+
+        def get_crl(self, uri):
+                """Given a URI (for now only http URIs are supported), return
+                the CRL object created from the file stored at that uri."""
+
+                if uri.startswith("URI:"):
+                        uri = uri[4:]
+                if not uri.startswith("http://") and \
+                    not uri.startswith("file://"):
+                        raise api_errors.InvalidResourceLocation(uri.strip())
+                fn = urllib.quote(uri, "")
+                assert os.path.isdir(self.__crl_root)
+                fpath = os.path.join(self.__crl_root, fn)
+                crl = None
+                # Check if we already have a CRL for this URI.
+                if os.path.exists(fpath):
+                        # If we already have a CRL, check whether it's time
+                        # to retrieve a new one from the location.
+                        crl = self.__format_safe_read_crl(fpath)
+                        nu = crl.get_next_update().get_datetime()
+                        # get_datetime is supposed to return a UTC time, so
+                        # assert that's the case.
+                        assert nu.tzinfo.utcoffset(nu) == dt.timedelta(0)
+                        # Add timezone info to cur_time so that cur_time and
+                        # nu can be compared.
+                        cur_time = dt.datetime.now(nu.tzinfo)
+                        if cur_time < nu:
+                                return crl
+                # If no CRL already exists or it's time to try to get a new one,
+                # try to retrieve it from the server.
+                tmp_pth = fpath + ".tmp"
+                with open(tmp_pth, "wb") as fh:
+                        hdl = pycurl.Curl()
+                        hdl.setopt(pycurl.URL, uri)
+                        hdl.setopt(pycurl.WRITEDATA, fh)
+                        hdl.setopt(pycurl.FAILONERROR, 1)
+                        try:
+                                hdl.perform()
+                        except pycurl.error, e:
+                                # If we should treat failure to get a new CRL
+                                # as a failure, raise an exception here. If not,
+                                # if we should use an old CRL if it exists,
+                                # return that here. If none is available and
+                                # that means the cert should not be treated as
+                                # revoked, return None here.
+                                return crl
+                try:
+                        ncrl = self.__format_safe_read_crl(tmp_pth)
+                except api_errors.BadFileFormat, e:
+                        portable.remove(tmp_pth)
+                        return crl
+                portable.rename(tmp_pth, fpath)
+                return ncrl
+
+        def __check_crls(self, cert, ca_dict):
+                """Determines whether the certificate has been revoked by its
+                CRL.
+
+                The 'cert' parameter is the certificate to check for revocation.
+
+                The 'ca_dict' is a dictionary which maps subject hashes to
+                certs treated as trust anchors."""
+
+                # If the certificate doesn't have a CRL location listed, treat
+                # it as valid.
+                try:
+                        ext = cert.get_ext("crlDistributionPoints")
+                except LookupError, e:
+                        return True
+                uri = ext.get_value()
+                crl = self.get_crl(uri)
+                # If we couldn't retrieve a CRL from the distribution point
+                # and no CRL is cached on disk, assume the cert has not been
+                # revoked.  It's possible that this should be an image or
+                # publisher setting in the future.
+                if not crl:
+                        return True
+
+                # A CRL has been found, now it needs to be validated like
+                # a certificate is.
+                verified_crl = False
+                crl_issuer = crl.get_issuer()
+                tas = ca_dict.get(crl_issuer.as_hash(), [])
+                for t in tas:
+                        if crl.verify(t.get_pubkey()):
+                                verified_crl = True
+                if not verified_crl:
+                        crl_cas = self.get_certs_by_name(crl_issuer)
+                        for c in crl_cas:
+                                if crl.verify(c.get_pubkey()):
+                                        try:
+                                                self.verify_chain(c, ca_dict)
+                                        except api_errors.SigningException:
+                                                pass
+                                        else:
+                                                verified_crl = True
+                                                break
+                if not verified_crl:
+                        return True
+                # For a certificate to be revoked, its CRL must be validated
+                # and revoked the certificate.
+                rev = crl.is_revoked(cert)
+                if rev:
+                        raise api_errors.RevokedCertificate(cert, rev[1])
+
+        def check_critical(self, ext):
+                """Check whether this criticial extension is supported."""
+
+                if ext.get_name() != "basicConstraints":
+                        return False
+                v = ext.get_value()
+                if v.upper() not in ("CA:TRUE", "CA:FALSE"):
+                        return False
+                return True
+
+        def check_extensions(self, cert):
+                """Check whether the critical extensions in this certificate
+                are supported."""
+
+                for i in range(0, cert.get_ext_count()):
+                        ext = cert.get_ext_at(i)
+                        if not ext.get_critical() or self.check_critical(ext):
+                                continue
+                        raise api_errors.UnsupportedCriticalExtension(cert, ext)
+        
+        def verify_chain(self, cert, ca_dict, required_names=None):
+                """Validates the certificate against the given trust anchors.
+
+                The 'cert' parameter is the certificate to validate.
+
+                The 'ca_dict' is a dictionary which maps subject hashes to
+                certs treated as trust anchors.
+
+                The 'required_names' parameter is a set of strings that must
+                be seen as a CN in the chain of trust for the certificate."""
+
+                if required_names is None:
+                        required_names = set()
+                verified = False
+                found_req_name = not required_names
+                continue_loop = True
+                certs_with_problems = []
+
+                # Check whether we can validate this certificate.
+                self.check_extensions(cert)
+
+                # Check whether this certificate has been revoked.
+                self.__check_crls(cert, ca_dict)
+
+                while continue_loop:
+                        # If this certificate's CN is in the set of required
+                        # names, remove it.
+                        for cert_cn in [
+                            str(c.get_data())
+                            for c
+                            in cert.get_subject().get_entries_by_nid(
+                                m2.X509.X509_Name.nid["CN"])
+                        ]:
+                                required_names.discard(cert_cn)
+
+                        # Find the certificate that issued this certificate.
+                        issuer = cert.get_issuer()
+                        issuer_hash = issuer.as_hash()
+
+                        # See whether this certificate was issued by any of the
+                        # given trust anchors.
+                        for c in ca_dict.get(issuer_hash, []):
+                                if cert.verify(c.get_pubkey()):
+                                        verified = True
+                                        # If there are more names to check for
+                                        # continue up the chain of trust to look
+                                        # for them.
+                                        if not required_names:
+                                                continue_loop = False
+                                        break
+
+                        # If the subject and issuer for this certificate are
+                        # identical and the certificate hasn't been verified
+                        # then this is an untrusted self-signed cert and should
+                        # be rejected.
+                        if cert.get_subject().as_hash() == issuer_hash:
+                                if not verified:
+                                        raise \
+                                            api_errors.UntrustedSelfSignedCert(
+                                            cert)
+                                # This break should break the
+                                # while continue_loop loop.
+                                break
+
+                        # If the certificate hasn't been issued by a trust
+                        # anchor or more names need to be found, continue
+                        # looking up the chain of trust.
+                        if continue_loop:
+                                up_chain = False
+                                # Keep track of certs that would have verified
+                                # this certificate but had critical extensions
+                                # we can't handle yet for error reporting.
+                                certs_with_problems = []
+                                for c in self.get_certs_by_name(issuer):
+                                        # If the certificate is approved to
+                                        # sign another certificate, verifies
+                                        # the current certificate, and hasn't
+                                        # been revoked, consider it as the
+                                        # next link in the chain.
+                                        if c.check_ca() and \
+                                            cert.verify(c.get_pubkey()):
+                                                problem = False
+                                                # Check whether this certificate
+                                                # has a critical extension we
+                                                # don't understand.
+                                                try:
+                                                        self.check_extensions(c)
+                                                        self.__check_crls(c,
+                                                            ca_dict)
+                                                except (api_errors.UnsupportedCriticalExtension, api_errors.RevokedCertificate), e:
+                                                        certs_with_problems.append(e)
+                                                        problem = True
+                                                # If this certificate has no
+                                                # problems with it, it's the
+                                                # next link in the chain so
+                                                # make it the current
+                                                # certificate.
+                                                if not problem:
+                                                        up_chain = True
+                                                        cert = c
+                                                        break
+                                # If there's not another link in the chain to be
+                                # found, stop the iteration.
+                                if not up_chain:
+                                        continue_loop = False
+                # If the certificate wasn't verified against a trust anchor,
+                # raise an exception.
+                if not verified:
+                        raise api_errors.BrokenChain(cert,
+                            certs_with_problems)
+
         alias = property(lambda self: self.__alias, __set_alias,
             doc="An alternative name for a publisher.")
 
@@ -1755,3 +2353,103 @@
         sticky = property(lambda self: self.__sticky, __set_stickiness,
             doc="Whether or not installed packages from this publisher are"
                 " always preferred to other publishers.")
+
+        def __get_prop(self, name):
+                """Accessor method for properites dictionary"""
+                return self.__properties[name]
+
+        def __set_prop(self, name, values):
+                """Accesor method to add a property"""
+
+                if name == SIGNATURE_POLICY:
+                        self.__sig_policy = None
+                        if isinstance(values, basestring):
+                                values = [values]
+                        policy_name = values[0]
+                        if policy_name not in sigpolicy.Policy.policies():
+                                raise api_errors.InvalidPropertyValue(_(
+                                    "%(val)s is not a valid value for this "
+                                    "property:%(prop)s") % {"val": policy_name,
+                                    "prop": SIGNATURE_POLICY})
+                        if policy_name == "require-names":
+                                if self.__delay_validation:
+                                        # If __delay_validation is set, then
+                                        # it's possible that
+                                        # signature-required-names was
+                                        # set by a previous call to set_prop
+                                        # file.  If so, don't overwrite the
+                                        # values that have already been read.
+                                        self.__properties.setdefault(
+                                            "signature-required-names", [])
+                                        self.__properties[
+                                            "signature-required-names"].extend(
+                                            values[1:])
+                                else:
+                                        self.__properties[
+                                            "signature-required-names"] = \
+                                            values[1:]
+                                        self.__validate_properties()
+                        else:
+                                if len(values) > 1:
+                                        raise api_errors.InvalidPropertyValue(_(
+                                            "The %s signature-policy takes no "
+                                            "argument.") % policy_name)
+                        self.__properties[SIGNATURE_POLICY] = policy_name
+                        return
+                if name == "signature-required-names":
+                        if isinstance(values, basestring):
+                                values = self.read_list(values)
+                self.__properties[name] = values
+
+        def __del_prop(self, name):
+                """Accessor method for properties"""
+                del self.__properties[name]
+
+        def __prop_iter(self):
+                return self.__properties.__iter__()
+
+        def __prop_iteritems(self):
+                """Support iteritems on properties"""
+                return self.__properties.iteritems()
+
+        def __prop_keys(self):
+                """Support keys() on properties"""
+                return self.__properties.keys()
+
+        def __prop_values(self):
+                """Support values() on properties"""
+                return self.__properties.values()
+
+        def __prop_getdefault(self, name, value):
+                """Support getdefault() on properties"""
+                return self.__properties.get(name, value)
+
+        def __prop_setdefault(self, name, value):
+                """Support setdefault() on properties"""
+                return self.__properties.setdefault(name, value)
+
+        def __prop_update(self, d):
+                """Support update() on properties"""
+                return self.__properties.update(d)
+
+        def __prop_pop(self, d, default):
+                """Support pop() on properties"""
+                return self.__properties.pop(d, default)
+
+        properties = DictProperty(__get_prop, __set_prop, __del_prop,
+            __prop_iteritems, __prop_keys, __prop_values, __prop_iter,
+            doc="A dict holding the properties for an image.",
+            fgetdefault=__prop_getdefault, fsetdefault=__prop_setdefault,
+            update=__prop_update, pop=__prop_pop)
+
+        @property
+        def signature_policy(self):
+                """Return the signature policy for the publisher."""
+
+                if self.__sig_policy is not None:
+                        return self.__sig_policy
+                txt = self.properties.get(SIGNATURE_POLICY,
+                    [sigpolicy.DEFAULT_POLICY])[0]
+                names = self.properties.get("signature-required-names", [])
+                self.__sig_policy = sigpolicy.Policy.policy_factory(txt, names)
+                return self.__sig_policy
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/modules/client/sigpolicy.py	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,196 @@
+#!/usr/bin/python2.6
+#
+# 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) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+import pkg.client.api_errors as apx
+
+class Policy(object):
+        """Abstract base Policy class.  It defines the interface all subclasses
+        must provide.
+
+        Each subclass must also define its "strictness".
+        Strictness is a positive integer and is relative to the other
+        subclasses in existence.  More than one subclass may have the same
+        strictness level.  In the abscence of other information, when combining
+        two policies, the result is the stricter policy."""
+
+        _policies = {}
+
+        def __init__(self, *args, **kwargs):
+                # This method exists to provide a consistent __init__ method
+                # for the factory below.
+                object.__init__(self)
+
+        def process_signatures(self, sigs, acts, pub):
+                """Check that the signatures ("sigs") verify against the actions
+                ("acts") using the publisher ("pub") as the repository for
+                certificates.
+
+                Not implemented in the base class."""
+                raise NotImplementedError()
+
+        def check_cas(self, pub, trust_anchors):
+                """Almost all policies want to verify the publishers CA certs
+                when given the chance to check them."""
+
+                pub.verify_ca_certs(trust_anchors)
+
+        def __cmp__(self, other):
+                return cmp(self.strictness, other.strictness)
+
+        def combine(self, other):
+                """If the other signature policy is more strict than this
+                policy, use the other policy.  Otherwise, use this policy."""
+
+                if self > other:
+                        return self
+                return other
+
+        def __str__(self):
+                return self.name
+
+        @staticmethod
+        def policies():
+                """Return the names of the signature policies available."""
+
+                return set(Policy._policies.keys())
+
+        @staticmethod
+        def policy_factory(name, *args, **kwargs):
+                """Given the name of a policy, return a new policy object of
+                that type."""
+
+                assert name in Policy._policies
+                return Policy._policies[name](*args, **kwargs)
+
+
+class Ignore(Policy):
+        """This policy ignores all signatures except to attempt to retrieve
+        any certificates that might be needed if the policy changes."""
+
+        strictness = 1
+        name = "ignore"
+
+        def process_signatures(self, sigs, acts, pub):
+                """Since this policy ignores signatures, only download the
+                certificates that might be needed so that they're present if
+                the policy changes later."""
+
+                for s in sigs:
+                        s.get_chain_certs(pub)
+
+        def check_cas(self, pub, trust_anchors):
+                """Since this policy ignores signatures, only download the
+                certificates that might be needed so that they're present if
+                the policy changes later."""
+
+                pub.get_intermediate_certs()
+
+Policy._policies[Ignore.name] = Ignore
+
+
+class Verify(Policy):
+        """This policy verifies that all signatures present are valid but
+        doesn't require that a signature be present."""
+
+        strictness = 2
+        name = "verify"
+
+        def process_signatures(self, sigs, acts, pub):
+                """Check that all signatures present are valid signatures."""
+
+                # Ensure that acts can be iterated over repeatedly.
+                acts = list(acts)
+                for s in sigs:
+                        s.verify_sig(acts, pub)
+
+Policy._policies[Verify.name] = Verify
+
+class RequireSigs(Policy):
+        """This policy that all signatures present are valid and insists that
+        at least one signature is seen with each package."""
+
+        strictness = 3
+        name = "require-signatures"
+
+        def process_signatures(self, sigs, acts, pub):
+                """Check that all signatures present are valid signatures and
+                at least one signature action which has been signed with a
+                private key is present."""
+
+                # Ensure that acts can be iterated over repeatedly.
+                acts = list(acts)
+                verified = False
+                for s in sigs:
+                        verified |= bool(s.verify_sig(acts, pub)) and \
+                            s.is_signed()
+                if not verified:
+                        raise apx.RequiredSignaturePolicyException(pub)
+
+Policy._policies[RequireSigs.name] = RequireSigs
+
+
+class RequireNames(Policy):
+        """This policy that all signatures present are valid and insists that
+        at least one signature is seen with each package.  In addition, it has
+        a set of names that must seen as CN's in the chain of trust."""
+
+        strictness = 4
+        name = "require-names"
+        def __init__(self, req_names, *args, **kwargs):
+                assert req_names, "RequireNames requires at least one name " \
+                    "to be passed to the constructor."
+                Policy.__init__(self, *args, **kwargs)
+                if isinstance(req_names, basestring):
+                        req_names = [req_names]
+                self.required_names = frozenset(req_names)
+
+        def process_signatures(self, sigs, acts, pub):
+                acts = list(acts)
+                missing_names = set(self.required_names)
+                verified = False
+                for s in sigs:
+                        verified |= bool(s.verify_sig(
+                            acts, pub, missing_names)) and \
+                            s.is_signed()
+                if missing_names:
+                        raise apx.MissingRequiredNamesException(pub,
+                            missing_names)
+
+        def combine(self, other):
+                """Determines how RequireNames policies combine with another
+                policy.  If the other policy is also a RequireNames policy,
+                the result is a policy which requires the union of both policies
+                required names."""
+
+                if self > other:
+                        return self
+                if other > self:
+                        return other
+                return RequireNames(self.required_names | other.required_names)
+
+Policy._policies[RequireNames.name] = RequireNames
+
+DEFAULT_POLICY = "ignore"
--- a/src/modules/client/transport/engine.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/modules/client/transport/engine.py	Mon Aug 16 16:48:50 2010 -0700
@@ -677,7 +677,7 @@
 
         def send_data(self, url, data=None, header=None, sslcert=None,
             sslkey=None, repourl=None, ccancel=None, sock_path=None,
-            data_fobj=None, failonerror=True):
+            data_fobj=None, data_fp=None, failonerror=True):
                 """Invoke the engine to retrieve a single URL.  
                 This routine sends the data in data, and returns the
                 server's response.  
@@ -698,7 +698,7 @@
                     hdrfunc=fobj.get_header_func(), header=header, data=data,
                     httpmethod="POST", sslcert=sslcert, sslkey=sslkey,
                     repourl=repourl, progfunc=progfunc, uuid=fobj.uuid,
-                    sock_path=None, read_fobj=data_fobj,
+                    sock_path=None, read_fobj=data_fobj, read_filepath=data_fp,
                     failonerror=failonerror)
 
                 self.__req_q.appendleft(t)
--- a/src/modules/client/transport/repo.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/modules/client/transport/repo.py	Mon Aug 16 16:48:50 2010 -0700
@@ -77,13 +77,13 @@
 
                 raise NotImplementedError
 
-        def get_datastream(self, fhash, header=None, ccancel=None):
+        def get_datastream(self, fhash, version, header=None, ccancel=None):
                 """Get a datastream from a repo.  The name of the
                 file is given in fhash."""
 
                 raise NotImplementedError
 
-        def get_files(self, filelist, dest, progtrack, header=None):
+        def get_files(self, filelist, dest, progtrack, version, header=None):
                 """Get multiple files from the repo at once.
                 The files are named by hash and supplied in filelist.
                 If dest is specified, download to the destination
@@ -131,6 +131,9 @@
 
                 raise NotImplementedError
 
+        def publish_add_file(self, action, header=None, trans_id=None):
+                raise NotImplementedError
+
         def publish_abandon(self, header=None, trans_id=None):
                 """The 'abandon' publication operation, that tells a
                 Repository to abort the current transaction.  The caller
@@ -156,6 +159,10 @@
 
                 raise NotImplementedError
 
+        def publish_append(self, header=None, client_release=None,
+            pkg_name=None):
+                raise NotImplementedError
+
         def publish_refresh_index(self, header=None):
                 """If the Repo points to a Repository that has a refresh-able
                 index, refresh the index."""
@@ -288,11 +295,11 @@
                     sock_path=self._sock_path, failonerror=failonerror)
 
         def _post_url(self, url, data=None, header=None, ccancel=None,
-            data_fobj=None, failonerror=True):
+            data_fobj=None, data_fp=None, failonerror=True):
                 return self._engine.send_data(url, data=data, header=header,
                     repourl=self._url, ccancel=ccancel,
                     sock_path=self._sock_path, data_fobj=data_fobj,
-                    failonerror=failonerror)
+                    data_fp=data_fp, failonerror=failonerror)
 
         def add_version_data(self, verdict):
                 """Cache the information about what versions a repository
@@ -421,11 +428,11 @@
 
                 return self._annotate_exceptions(errors)
 
-        def get_datastream(self, fhash, header=None, ccancel=None):
+        def get_datastream(self, fhash, version, header=None, ccancel=None):
                 """Get a datastream from a repo.  The name of the
                 file is given in fhash."""
 
-                methodstr = "file/0/"
+                methodstr = "file/%s/" % version
 
                 baseurl = urlparse.urljoin(self._repouri.uri, methodstr)
                 requesturl = urlparse.urljoin(baseurl, fhash)
@@ -508,7 +515,7 @@
 
                 return self._annotate_exceptions(errors, urlmapping)
 
-        def get_files(self, filelist, dest, progtrack, header=None):
+        def get_files(self, filelist, dest, progtrack, version, header=None):
                 """Get multiple files from the repo at once.
                 The files are named by hash and supplied in filelist.
                 If dest is specified, download to the destination
@@ -516,7 +523,7 @@
                 it contains a ProgressTracker object for the
                 downloads."""
 
-                methodstr = "file/0/"
+                methodstr = "file/%s/" % version
                 urllist = []
                 progclass = None
 
@@ -629,6 +636,32 @@
                 finally:
                         fobj.close()
 
+        def publish_add_file(self, pth, header=None, trans_id=None):
+                """The publish operation that adds content to a repository.
+                The action must be populated with a data property.
+                Callers may supply a header, and should supply a transaction
+                id in trans_id."""
+
+                attrs = {}
+                methodstr = "file/1/"
+
+                baseurl = urlparse.urljoin(self._repouri.uri, methodstr)
+                request_str = "%s" % trans_id
+                requesturl = urlparse.urljoin(baseurl, request_str)
+
+                headers = dict(
+                    ("X-IPkg-SetAttr%s" % i, "%s=%s" % (k, attrs[k]))
+                    for i, k in enumerate(attrs)
+                )
+
+                if header:
+                        headers.update(header)
+
+                fobj = self._post_url(requesturl, header=headers, data_fp=pth)
+
+                # Discard response body
+                fobj.read()
+                
         def publish_abandon(self, header=None, trans_id=None):
                 """The 'abandon' publication operation, that tells a
                 Repository to abort the current transaction.  The caller
@@ -717,6 +750,12 @@
                 Returns a transaction-ID."""
 
                 methodstr = "open/0/"
+                return self.__start_trans(methodstr, header, client_release,
+                    pkg_name)
+
+        def __start_trans(self, methodstr, header, client_release, pkg_name):
+                """Start a publication transaction."""
+
                 baseurl = urlparse.urljoin(self._repouri.uri, methodstr)
                 request_str = urllib.quote(pkg_name, "")
                 requesturl = urlparse.urljoin(baseurl, request_str)
@@ -748,6 +787,17 @@
 
                 return trans_id
 
+        def publish_append(self, header=None, client_release=None,
+            pkg_name=None):
+                """Begin a publication operation by calling 'append'.
+                The caller must specify the client's OS release in
+                client_release, and the package's name in pkg_name.
+                Returns a transaction-ID."""
+
+                methodstr = "append/0/"
+                return self.__start_trans(methodstr, header, client_release,
+                    pkg_name)
+
         def publish_refresh_index(self, header=None):
                 """If the Repo points to a Repository that has a refresh-able
                 index, refresh the index."""
@@ -848,12 +898,13 @@
                     failonerror=failonerror)
 
         def _post_url(self, url, data=None, header=None, ccancel=None,
-            data_fobj=None, failonerror=True):
+            data_fobj=None, data_fp=None, failonerror=True):
                 return self._engine.send_data(url, data=data, header=header,
                     sslcert=self._repouri.ssl_cert,
                     sslkey=self._repouri.ssl_key, repourl=self._url,
                     ccancel=ccancel, sock_path=self._sock_path,
-                    data_fobj=data_fobj, failonerror=failonerror)
+                    data_fobj=data_fobj, data_fp=data_fp,
+                    failonerror=failonerror)
 
 
 class FileRepo(TransportRepo):
@@ -1057,7 +1108,7 @@
 
                 return self._annotate_exceptions(errors)
 
-        def get_datastream(self, fhash, header=None, ccancel=None):
+        def get_datastream(self, fhash, version, header=None, ccancel=None):
                 """Get a datastream from a repo.  The name of the
                 file is given in fhash."""
 
@@ -1094,8 +1145,13 @@
                             "alias")
                         pfx = self._frepo.cfg.get_property("publisher",
                             "prefix")
+                        scas = self._frepo.cfg.get_property("publisher",
+                            "signing_ca_certs")
+                        icas = self._frepo.cfg.get_property("publisher",
+                            "intermediate_certs")
                         pub = publisher.Publisher(pfx, alias=alias,
-                            repositories=[repo])
+                            repositories=[repo], ca_certs=scas,
+                            inter_certs=icas)
 
                         buf = cStringIO.StringIO()
                         p5i.write(buf, [pub])
@@ -1192,7 +1248,7 @@
 
                 return errors + pre_exec_errors
 
-        def get_files(self, filelist, dest, progtrack, header=None):
+        def get_files(self, filelist, dest, progtrack, version, header=None):
                 """Get multiple files from the repo at once.
                 The files are named by hash and supplied in filelist.
                 If dest is specified, download to the destination
@@ -1278,8 +1334,9 @@
 
                 buf = cStringIO.StringIO()
                 vops = {
+                    "append": ["0"],
                     "catalog": ["1"],
-                    "file": ["0"],
+                    "file": ["0", "1"],
                     "manifest": ["0"],
                     "publisher": ["0"],
                     "search": ["1"],
@@ -1312,6 +1369,15 @@
                 except svr_repo.RepositoryError, e:
                         raise tx.TransportOperationError(str(e))
 
+        def publish_add_file(self, pth, header=None, trans_id=None):
+                """The publish operation that adds a file to an existing
+                transaction."""
+
+                try:
+                        self._frepo.add_file(trans_id, pth)
+                except svr_repo.RepositoryError, e:
+                        raise tx.TransportOperationError(str(e))
+
         def publish_abandon(self, header=None, trans_id=None):
                 """The abandon operation, that tells a Repository to abort
                 the current transaction.  The caller must specify the
@@ -1354,6 +1420,15 @@
 
                 return trans_id
 
+        def publish_append(self, header=None, client_release=None,
+            pkg_name=None):
+                try:
+                        trans_id = self._frepo.append(client_release, pkg_name)
+                except svr_repo.RepositoryError, e:
+                        raise tx.TransportOperationError(str(e))
+
+                return trans_id
+
         def publish_refresh_index(self, header=None):
                 """If the Repo points to a Repository that has a refresh-able
                 index, refresh the index."""
--- a/src/modules/client/transport/transport.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/modules/client/transport/transport.py	Mon Aug 16 16:48:50 2010 -0700
@@ -890,12 +890,13 @@
                 if not self.__engine:
                         self.__setup()
 
-                for d in self.__gen_repo(pub, retry_count):
+                for d, v in self.__gen_repo(pub, retry_count, operation="file",
+                    versions=[0, 1]):
 
                         url = d.get_url()
 
                         try:
-                                resp = d.get_datastream(fhash, header,
+                                resp = d.get_datastream(fhash, v, header,
                                     ccancel=ccancel)
                                 s = cStringIO.StringIO()
                                 hash_val = misc.gunzip_from_stream(resp, s)
@@ -1385,7 +1386,8 @@
                         # present.
                         cache = cache[0]
 
-                for d in self.__gen_repo(pub, retry_count):
+                for d, v in self.__gen_repo(pub, retry_count, operation="file",
+                    versions=[0, 1]):
 
                         failedreqs = []
                         repostats = self.stats[d.get_url()]
@@ -1397,7 +1399,7 @@
                         # unless we want to supress a permanant failure.
                         try:
                                 errlist = d.get_files(filelist, download_dir,
-                                    progtrack, header)
+                                    progtrack, v, header)
                         except tx.ExcessiveTransientFailure, ex:
                                 # If an endpoint experienced so many failures
                                 # that we just gave up, record this for later
@@ -2001,8 +2003,7 @@
         @LockedTransport()
         def publish_add(self, pub, action=None, trans_id=None):
                 """Perform the 'add' publication operation to the publisher
-                supplied in pub.  The caller should include the action in the
-                action argument. The transaction-id is passed in trans_id."""
+                supplied in pub.  The transaction-id is passed in trans_id."""
 
                 failures = tx.TransportFailures()
                 retry_count = global_settings.PKG_CLIENT_MAX_TIMEOUT
@@ -2032,6 +2033,44 @@
                 raise failures
 
         @LockedTransport()
+        def publish_add_file(self, pub, pth, trans_id=None):
+                """Perform the 'add_file' publication operation to the publisher
+                supplied in pub.  The caller should include the action in the
+                action argument. The transaction-id is passed in trans_id."""
+
+                failures = tx.TransportFailures()
+                retry_count = global_settings.PKG_CLIENT_MAX_TIMEOUT
+                header = self.__build_header(uuid=self.__get_uuid(pub))
+
+                # Call setup if the transport isn't configured or was shutdown.
+                if not self.__engine:
+                        self.__setup()
+
+                repo_found = False
+                for d, v in self.__gen_repo(pub, retry_count, origin_only=True,
+                    single_repository=True, operation="file", versions=[1]):
+                        repo_found = True
+                        try:
+                                d.publish_add_file(pth, header=header,
+                                    trans_id=trans_id)
+                                return
+                        except tx.ExcessiveTransientFailure, ex:
+                                # If an endpoint experienced so many failures
+                                # that we just gave up, grab the list of
+                                # failures that it contains
+                                failures.extend(ex.failures)
+                        except tx.TransportException, e:
+                                if e.retryable:
+                                        failures.append(e)
+                                else:
+                                        raise
+                if not repo_found:
+                        raise apx.UnsupportedRepositoryOperation(pub,
+                            "file/1")
+
+                raise failures
+
+        @LockedTransport()
         def publish_abandon(self, pub, trans_id=None):
                 """Perform an 'abandon' publication operation to the
                 publisher supplied in the pub argument.  The caller should
@@ -2141,6 +2180,46 @@
                 raise failures
 
         @LockedTransport()
+        def publish_append(self, pub, client_release=None, pkg_name=None):
+                """Perform an 'append' transaction to start a publication
+                transaction to the publisher named in pub.  The caller should
+                supply the client's OS release in client_release, and the
+                package's name in pkg_name."""
+
+                failures = tx.TransportFailures()
+                retry_count = global_settings.PKG_CLIENT_MAX_TIMEOUT
+                header = self.__build_header(uuid=self.__get_uuid(pub))
+
+                # Call setup if transport isn't configured, or was shutdown.
+                if not self.__engine:
+                        self.__setup()
+
+                repo_found = False
+                for d, v in self.__gen_repo(pub, retry_count, origin_only=True,
+                    single_repository=True, operation="append", versions=[0]):
+                        repo_found = True
+                        try:
+                                trans_id = d.publish_append(header=header,
+                                    client_release=client_release,
+                                    pkg_name=pkg_name)
+                                return trans_id
+                        except tx.ExcessiveTransientFailure, ex:
+                                # If an endpoint experienced so many failures
+                                # that we just gave up, grab the list of
+                                # failures that it contains
+                                failures.extend(ex.failures)
+                        except tx.TransportException, e:
+                                if e.retryable:
+                                        failures.append(e)
+                                else:
+                                        raise
+                if not repo_found:
+                        raise apx.UnsupportedRepositoryOperation(pub,
+                            "append/0")
+
+                raise failures
+
+        @LockedTransport()
         def publish_refresh_index(self, pub):
                 """Instructs the repositories named by Publisher pub
                 to refresh their index."""
--- a/src/modules/manifest.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/modules/manifest.py	Mon Aug 16 16:48:50 2010 -0700
@@ -25,6 +25,7 @@
 #
 
 from collections import namedtuple
+import copy
 import errno
 import hashlib
 import os
@@ -358,9 +359,16 @@
                         content = self.__content_to_actions(content)
 
                 for action in content:
-                        self.__add_action(action, excludes)
+                        self.add_action(action, excludes)
+                return
 
-        def __add_action(self, action, excludes):
+        def exclude_content(self, excludes):
+                """Remove any actions from the manifest which should be
+                excluded."""
+
+                self.set_content(self.actions, excludes)
+
+        def add_action(self, action, excludes):
                 """Performs any needed transformations on the action then adds
                 it to the manifest.
 
@@ -938,6 +946,11 @@
                         self.__load()
                 return Manifest.gen_actions(self, excludes=excludes)
 
+        def __str__(self, excludes=EmptyI):
+                if not self.loaded:
+                        self.__load()
+                return Manifest.__str__(self)
+
         def duplicates(self, excludes=EmptyI):
                 if not self.loaded:
                         self.__load()
--- a/src/modules/misc.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/modules/misc.py	Mon Aug 16 16:48:50 2010 -0700
@@ -44,6 +44,7 @@
 import urlparse
 import zlib
 
+from pkg.pkggzip import PkgGzipFile
 from pkg.client.imagetypes import img_type_names, IMG_NONE
 from pkg import VERSION
 
@@ -53,6 +54,9 @@
 # Copied from image.py as image.py can't be imported here (circular reference).
 PKG_STATE_INSTALLED = 2
 
+# Constant string used across many modules as a property name.
+SIGNATURE_POLICY = "signature-policy"
+
 def get_release_notes_url():
         """Return a release note URL pointing to the correct release notes
            for this version"""
@@ -373,6 +377,65 @@
 
         return fhash.hexdigest(), content.read()
 
+def compute_compressed_attrs(fname, file_path, data, size, compress_dir,
+    bufsz=64*1024):
+        """Returns the size and hash of the compressed data.  If the file
+        located at file_path doesn't exist or isn't gzipped, it creates a file
+        in compress_dir named fname."""
+
+        #
+        # This check prevents compressing a file which is already compressed.
+        # This takes CPU load off the depot on large imports of mostly-the-same
+        # stuff.  And in general it saves disk bandwidth, and on ZFS in
+        # particular it saves us space in differential snapshots.  We also need
+        # to check that the destination is in the same compression format as
+        # the source, as we must have properly formed files for chash/csize
+        # properties to work right.
+        #
+
+        fileneeded = True
+        if file_path:
+                if PkgGzipFile.test_is_pkggzipfile(file_path):
+                        fileneeded = False
+                        opath = file_path
+
+        if fileneeded:
+                opath = os.path.join(compress_dir, fname)
+                ofile = PkgGzipFile(opath, "wb")
+
+                nbuf = size / bufsz
+
+                for n in range(0, nbuf):
+                        l = n * bufsz
+                        h = (n + 1) * bufsz
+                        ofile.write(data[l:h])
+
+                m = nbuf * bufsz
+                ofile.write(data[m:])
+                ofile.close()
+
+        data = None
+
+        # Now that the file has been compressed, determine its
+        # size.
+        fs = os.stat(opath)
+        csize = str(fs.st_size)
+
+        # Compute the SHA hash of the compressed file.  In order for this to
+        # work correctly, we have to use the PkgGzipFile class.  It omits
+        # filename and timestamp information from the gzip header, allowing us
+        # to generate deterministic hashes for different files with identical
+        # content.
+        cfile = open(opath, "rb")
+        chash = hashlib.sha1()
+        while True:
+                cdata = cfile.read(bufsz)
+                if cdata == "":
+                        break
+                chash.update(cdata)
+        cfile.close()
+        return csize, chash
+
 def __getvmusage():
         """Return the amount of virtual memory in bytes currently in use."""
 
@@ -456,7 +519,8 @@
 
 class DictProperty(object):
         class __InternalProxy(object):
-                def __init__(self, obj, fget, fset, fdel, iteritems, keys, values, iterator):
+                def __init__(self, obj, fget, fset, fdel, iteritems, keys,
+                    values, iterator, fgetdefault, fsetdefault, update, pop):
                         self.__obj = obj
                         self.__fget = fget
                         self.__fset = fset
@@ -465,6 +529,10 @@
                         self.__keys = keys
                         self.__values = values
                         self.__iter = iterator
+                        self.__fgetdefault = fgetdefault
+                        self.__fsetdefault = fsetdefault
+                        self.__update = update
+                        self.__pop = pop
 
                 def __getitem__(self, key):
                         if self.__fget is None:
@@ -497,13 +565,34 @@
                                 raise AttributeError, "can't iterate over values"
                         return self.__values(self.__obj)
 
+                def get(self, key, default=None):
+                        if self.__fgetdefault is None:
+                                raise AttributeError, "can't use get"
+                        return self.__fgetdefault(self.__obj, key, default)
+
+                def setdefault(self, key, default=None):
+                        if self.__fsetdefault is None:
+                                raise AttributeError, "can't use setdefault"
+                        return self.__fsetdefault(self.__obj, key, default)
+
+                def update(self, d):
+                        if self.__update is None:
+                                raise AttributeError, "can't use update"
+                        return self.__update(self.__obj, d)
+
+                def pop(self, d, default):
+                        if self.__pop is None:
+                                raise AttributeError, "can't use pop"
+                        return self.__pop(self.__obj, d, default)
+
                 def __iter__(self):
                         if self.__iter is None:
                                 raise AttributeError, "can't iterate"
                         return self.__iter(self.__obj)
 
         def __init__(self, fget=None, fset=None, fdel=None, iteritems=None, 
-            keys=None, values=None, iterator=None, doc=None):
+            keys=None, values=None, iterator=None, doc=None, fgetdefault=None,
+            fsetdefault=None, update=None, pop=None):
                 self.__fget = fget
                 self.__fset = fset
                 self.__fdel = fdel
@@ -512,12 +601,18 @@
                 self.__keys = keys
                 self.__values = values
                 self.__iter = iterator
+                self.__fgetdefault = fgetdefault
+                self.__fsetdefault = fsetdefault
+                self.__update = update
+                self.__pop = pop
 
         def __get__(self, obj, objtype=None):
                 if obj is None:
                         return self
                 return self.__InternalProxy(obj, self.__fget, self.__fset, 
-                    self.__fdel, self.__iteritems, self.__keys, self.__values, self.__iter)
+                    self.__fdel, self.__iteritems, self.__keys, self.__values,
+                    self.__iter, self.__fgetdefault, self.__fsetdefault,
+                    self.__update, self.__pop)
 
         
 def get_sorted_publishers(pubs, preferred=None):
@@ -595,6 +690,52 @@
 
         return cert
 
+# Used for the conversion of the signature value between hex and binary.
+char_list = "0123456789abcdef"
+
+def binary_to_hex(s):
+        """Converts a string of bytes to a hexadecimal representation.
+        """
+
+        res = ""
+        for i, p in enumerate(s):
+                p = ord(p)
+                a = char_list[p % 16]
+                p = p/16
+                b = char_list[p % 16]
+                res += b + a
+        return res
+
+def hex_to_binary(s):
+        """Converts a string of hex digits to the binary representation.
+        """
+
+        res = ""
+        for i in range(0, len(s), 2):
+                res += chr(char_list.find(s[i]) * 16 +
+                    char_list.find(s[i+1]))
+        return res
+
+def config_temp_root():
+        """Examine the environment.  If the environment has set TMPDIR, TEMP,
+        or TMP, return None.  This tells tempfile to use the environment
+        settings when creating temporary files/directories.  Otherwise,
+        return a path that the caller should pass to tempfile instead."""
+
+        default_root = "/var/tmp"
+
+        # In Python's tempfile module, the default temp directory
+        # includes some paths that are suboptimal for holding large numbers
+        # of files.  If the user hasn't set TMPDIR, TEMP, or TMP in the
+        # environment, override the default directory for creating a tempfile.
+        tmp_envs = [ "TMPDIR", "TEMP", "TMP" ]
+        for ev in tmp_envs:
+                env_val = os.getenv(ev)
+                if env_val:
+                        return None
+
+        return default_root
+
 class Singleton(type):
         """Set __metaclass__ to Singleton to create a singleton.
         See http://en.wikipedia.org/wiki/Singleton_pattern """
--- a/src/modules/p5i.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/modules/p5i.py	Mon Aug 16 16:48:50 2010 -0700
@@ -21,8 +21,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 import os
@@ -104,11 +103,14 @@
                 for p in plist:
                         alias = p.get("alias", None)
                         prefix = p.get("name", None)
-
+                        signing_ca_certs = p.get("signing_ca_certs", [])
+                        inter_certs = p.get("intermediate_certs", [])
+                        
                         if not prefix:
                                 prefix = "Unknown"
 
-                        pub = publisher.Publisher(prefix, alias=alias)
+                        pub = publisher.Publisher(prefix, alias=alias,
+                            ca_certs=signing_ca_certs, inter_certs=inter_certs)
                         pkglist = p.get("packages", [])
                         result.append((pub, pkglist))
 
@@ -177,9 +179,12 @@
 
         dpubs = dump_struct["publishers"]
         for p in pubs:
+
                 dpub = {
                     "alias": p.alias,
                     "name": p.prefix,
+                    "signing_ca_certs": p.signing_ca_certs,
+                    "intermediate_certs": p.inter_certs,
                     "packages": [],
                     "repositories": []
                 }
--- a/src/modules/publish/transaction.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/modules/publish/transaction.py	Mon Aug 16 16:48:50 2010 -0700
@@ -21,13 +21,13 @@
 #
 
 #
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 """Provides a set of publishing interfaces for interacting with a pkg(5)
 repository.  Note that only the Transaction class should be used directly,
 though the other classes can be referred to for documentation purposes."""
 
+import os
 import urllib
 import urlparse
 
@@ -149,6 +149,17 @@
                         raise TransactionOperationError("add",
                             trans_id=self.trans_id, msg=str(e))
 
+        def add_file(self, pth):
+                """Adds an additional file to the inflight transaction so that
+                it will be available for retrieval once the transaction is
+                closed."""
+
+                if not os.path.isfile(pth):
+                        raise TransactionOperationError("add_file",
+                            trans_id=self.trans_id, msg=str(_("The file to "
+                            "be added is not a file.  The path given was %s.") %
+                            pth))
+
         def close(self, abandon=False, refresh_index=True):
                 """Ends an in-flight transaction.  Returns a tuple containing
                 a package fmri (if applicable) and the final state of the
@@ -168,6 +179,11 @@
                 transaction ID on success."""
                 return urllib.quote(self.pkg_name, "")
 
+        def append(self):
+                """Starts an in-flight transaction to append to an existing
+                manifest. Returns a URL-encoded transaction ID on success."""
+                return self.open()
+
         @staticmethod
         def refresh_index():
                 """Instructs the repository to refresh its search indices.
@@ -246,6 +262,25 @@
                         raise TransactionOperationError("add",
                             trans_id=self.trans_id, msg=msg)
 
+        def add_file(self, pth):
+                """Adds an additional file to the inflight transaction so that
+                it will be available for retrieval once the transaction is
+                closed."""
+
+                if not os.path.isfile(pth):
+                        raise TransactionOperationError("add_file",
+                            trans_id=self.trans_id, msg=str(_("The file to "
+                            "be added is not a file.  The path given was %s.") %
+                            pth))
+
+                try:
+                        self.transport.publish_add_file(self.publisher,
+                            pth=pth, trans_id=self.trans_id)
+                except apx.TransportError, e:
+                        msg = str(e)
+                        raise TransactionOperationError("add_file",
+                            trans_id=self.trans_id, msg=msg)
+
         def close(self, abandon=False, refresh_index=True, add_to_catalog=True):
                 """Ends an in-flight transaction.  Returns a tuple containing
                 a package fmri (if applicable) and the final state of the
@@ -317,6 +352,30 @@
 
                 return self.trans_id
 
+        def append(self):
+                """Starts an in-flight transaction to append to an existing
+                manifest. Returns a URL-encoded transaction ID on success."""
+
+                trans_id = None
+
+                try:
+                        trans_id = self.transport.publish_append(self.publisher,
+                            client_release=os_util.get_os_release(),
+                            pkg_name=self.pkg_name)
+                except apx.TransportError, e:
+                        msg = str(e)
+                        raise TransactionOperationError("append",
+                            trans_id=self.trans_id, msg=msg)
+
+                self.trans_id = trans_id
+
+                if self.trans_id is None:
+                        raise TransactionOperationError("append",
+                            msg=_("Unknown failure; no transaction ID provided"
+                            " in response."))
+
+                return self.trans_id        
+
         def refresh_index(self):
                 """Instructs the repository to refresh its search indices.
                 Returns nothing."""
--- a/src/modules/server/depot.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/modules/server/depot.py	Mon Aug 16 16:48:50 2010 -0700
@@ -145,6 +145,7 @@
             "filelist",
             "file",
             "open",
+            "append",
             "close",
             "abandon",
             "add",
@@ -708,6 +709,28 @@
 
         file_0._cp_config = { "response.stream": True }
 
+        def file_1(self, *tokens):
+                """Outputs the contents of the file, named by the SHA-1 hash
+                name in the request path, directly to the client."""
+
+                method = cherrypy.request.method
+                if method == "GET":
+                        return self.file_0(*tokens)
+                elif method in ("POST", "PUT"):
+                        return self.__upload_file(*tokens)
+                raise cherrypy.HTTPError(httplib.METHOD_NOT_ALLOWED,
+                    "%s is not allowed" % method)
+
+        # We need to prevent cherrypy from processing the request body so that
+        # file can parse the request body itself.  In addition, we also need to
+        # set the timeout higher since the default is five minutes; not really
+        # enough for a slow connection to upload content.
+        file_1._cp_config = {
+            "request.process_request_body": False,
+            "response.timeout": 3600,
+            "response.stream": True
+        }
+
         @cherrypy.tools.response_headers(headers=[("Pragma", "no-cache"),
             ("Cache-Control", "no-cache, no-transform, must-revalidate"),
             ("Expires", 0)])
@@ -741,6 +764,37 @@
         @cherrypy.tools.response_headers(headers=[("Pragma", "no-cache"),
             ("Cache-Control", "no-cache, no-transform, must-revalidate"),
             ("Expires", 0)])
+        def append_0(self, *tokens):
+                """Starts an append transaction for the package name specified
+                in the request path.  Returns no output."""
+
+                request = cherrypy.request
+                response = cherrypy.response
+
+                client_release = request.headers.get("Client-Release", None)
+                try:
+                        pfmri = tokens[0]
+                except IndexError:
+                        pfmri = None
+
+                # XXX Authentication will be handled by virtue of possessing a
+                # signed certificate (or a more elaborate system).
+
+                try:
+                        trans_id = self.repo.append(client_release, pfmri)
+                        response.headers["Content-type"] = \
+                            "text/plain; charset=utf-8"
+                        response.headers["Transaction-ID"] = trans_id
+                except repo.RepositoryError, e:
+                        # Assume a bad request was made.  A 404 can't be
+                        # returned here as misc.versioned_urlopen will interpret
+                        # that to mean that the server doesn't support this
+                        # operation.
+                        raise cherrypy.HTTPError(httplib.BAD_REQUEST, str(e))
+
+        @cherrypy.tools.response_headers(headers=[("Pragma", "no-cache"),
+            ("Cache-Control", "no-cache, no-transform, must-revalidate"),
+            ("Expires", 0)])
         def close_0(self, *tokens):
                 """Ends an in-flight transaction for the Transaction ID
                 specified in the request path.
@@ -897,6 +951,38 @@
             ]
         }
 
+        def __upload_file(self, *tokens):
+                """Adds a file to an in-flight transaction for the Transaction
+                ID specified in the request path.  The content is expected to be
+                in the request body.  Returns no output."""
+
+                try:
+                        # cherrypy decoded it, but we actually need it encoded.
+                        trans_id = urllib.quote(tokens[0], "")
+                except IndexError:
+                        raise
+                        trans_id = None
+
+                request = cherrypy.request
+                response = cherrypy.response
+
+                size = int(request.headers.get("Content-Length", 0))
+                if size < 0:
+                        raise cherrypy.HTTPError(httplib.BAD_REQUEST,
+                            _("file/1 must be sent a file."))
+                data = request.rfile
+
+                try:
+                        self.repo.add_file(trans_id, data, size)
+                except repo.RepositoryError, e:
+                        # Assume a bad request was made.  A 404 can't be
+                        # returned here as misc.versioned_urlopen will interpret
+                        # that to mean that the server doesn't support this
+                        # operation.
+                        raise cherrypy.HTTPError(httplib.BAD_REQUEST, str(e))
+                response.headers["Content-Length"] = "0"
+                return response.body
+
         @cherrypy.tools.response_headers(headers=[("Pragma", "no-cache"),
             ("Cache-Control", "no-cache, no-transform, must-revalidate"),
             ("Expires", 0)])
@@ -1023,9 +1109,13 @@
 
                 repo = publisher.Repository(**rargs)
                 alias = self.repo.cfg.get_property("publisher", "alias")
+                icas = self.repo.cfg.get_property("publisher",
+                    "intermediate_certs")
                 pfx = self.repo.cfg.get_property("publisher", "prefix")
+                scas = self.repo.cfg.get_property("publisher",
+                    "signing_ca_certs")
                 return publisher.Publisher(pfx, alias=alias,
-                    repositories=[repo])
+                    repositories=[repo], ca_certs=scas, inter_certs=icas)
 
         @cherrypy.tools.response_headers(headers=[(
             "Content-Type", p5i.MIME_TYPE)])
--- a/src/modules/server/repository.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/modules/server/repository.py	Mon Aug 16 16:48:50 2010 -0700
@@ -51,6 +51,7 @@
 import pkg.version as version
 
 from pkg.misc import EmptyI, EmptyDict
+from pkg.pkggzip import PkgGzipFile
 
 class RepositoryError(Exception):
         """Base exception class for all Repository exceptions."""
@@ -231,8 +232,9 @@
                 if self.mirror:
                         self.__required_dirs = [self.file_root]
                 else:
-                        self.__required_dirs = [self.trans_root, self.manifest_root,
-                            self.catalog_root, self.file_root]
+                        self.__required_dirs = [self.trans_root,
+                            self.manifest_root, self.catalog_root,
+                            self.file_root]
 
                 # Ideally, callers would just specify overrides for the feed
                 # cache root, index_root, etc.  But this must be set after all
@@ -480,6 +482,16 @@
                 c = self.catalog
                 c.add_package(pfmri, manifest=manifest)
 
+        def __replace_package(self, pfmri, manifest=None):
+                """Private version; caller responsible for repository
+                locking."""
+
+                if not manifest:
+                        manifest = self._get_manifest(pfmri, sig=True)
+                c = self.catalog
+                c.remove_package(pfmri)
+                c.add_package(pfmri, manifest=manifest)
+
         def __check_search(self):
                 if not self.index_root:
                         return
@@ -1118,6 +1130,32 @@
                 finally:
                         self.__unlock_repository()
 
+        def add_file(self, trans_id, data, size=None):
+                """Adds a certificate to a transaction with the specified
+                Transaction ID."""
+
+                if self.mirror:
+                        raise RepositoryMirrorError()
+                if self.read_only:
+                        raise RepositoryReadOnlyError()
+                if not self.repo_root:
+                        raise RepositoryUnsupportedOperationError()
+
+                self.__lock_repository()
+                try:
+                        try:
+                                t = self.__in_flight_trans[trans_id]
+                        except KeyError:
+                                raise RepositoryInvalidTransactionIDError(
+                                    trans_id)
+
+                        try:
+                                t.add_file(data, size)
+                        except trans.TransactionError, e:
+                                raise RepositoryError(e)
+                finally:
+                        self.__unlock_repository()
+
         def add_package(self, pfmri):
                 """Adds the specified FMRI to the repository's catalog."""
 
@@ -1135,6 +1173,24 @@
                 finally:
                         self.__unlock_repository()
 
+        def replace_package(self, pfmri):
+                """Replaces the information for the specified FMRI in the
+                repository's catalog."""
+
+                if self.mirror:
+                        raise RepositoryMirrorError()
+                if self.read_only:
+                        raise RepositoryReadOnlyError()
+                if not self.repo_root:
+                        raise RepositoryUnsupportedOperationError()
+
+                self.__lock_repository()
+                try:
+                        self.__replace_package(pfmri)
+                        self.__save_catalog()
+                finally:
+                        self.__unlock_repository()
+
         @property
         def catalog(self):
                 """Returns the Catalog object for the repository's catalog."""
@@ -1292,6 +1348,30 @@
                 finally:
                         self.__unlock_repository()
 
+        def append(self, client_release, pfmri):
+                """Starts an append transaction for the specified client
+                release and FMRI.  Returns the Transaction ID for the new
+                transaction."""
+
+                if self.mirror:
+                        raise RepositoryMirrorError()
+                if self.read_only:
+                        raise RepositoryReadOnlyError()
+                if not self.repo_root:
+                        raise RepositoryUnsupportedOperationError()
+
+                self.__lock_repository()
+                try:
+                        try:
+                                t = trans.Transaction()
+                                t.append(self, client_release, pfmri)
+                                self.__in_flight_trans[t.get_basename()] = t
+                                return t.get_basename()
+                        except trans.TransactionError, e:
+                                raise RepositoryError(e)
+                finally:
+                        self.__unlock_repository()
+
         def refresh_index(self):
                 """ This function refreshes the search indexes if there any new
                 packages.  It starts a subprocess which results in a call to
@@ -1449,6 +1529,22 @@
                 entry = c.get_entry(pfmri)
                 return entry is None
 
+        def valid_append_fmri(self, pfmri):
+                if self.mirror:
+                        raise RepositoryMirrorError()
+                if not self.repo_root:
+                        raise RepositoryUnsupportedOperationError()
+                if not fmri.is_valid_pkg_name(pfmri.get_name()):
+                        return False
+                if not pfmri.version:
+                        return False
+                if not pfmri.version.timestr:
+                        return False
+
+                c = self.catalog
+                entry = c.get_entry(pfmri)
+                return entry
+
         def write_config(self):
                 """Save the repository's current configuration data."""
 
@@ -1458,6 +1554,54 @@
                 finally:
                         self.__unlock_repository()
 
+        def add_signing_certs(self, cert_paths, ca, write_config=True):
+                """Add the certificates stored in the given paths to the
+                files in the repository and as properties of the publisher.
+                Whether the certificates are added as CA certificates or
+                intermediate certificates is determined by the 'ca' parameter.
+                """
+
+                hshs = []
+                
+                for p in cert_paths:
+                        # Get the hash of the file.
+                        hsh, s = misc.get_data_digest(p, return_content=True)
+                        hshs.append(hsh)
+                        if self.read_only:
+                                if not self.cache_store.lookup(hsh):
+                                        raise RepositoryReadOnlyError(hsh)
+                        else:
+                                # The temporary file is moved into place by the
+                                # insert.
+                                fd, pth = tempfile.mkstemp()
+                                gfh = PkgGzipFile(filename=pth, mode="wb")
+                                gfh.write(s)
+                                gfh.close()
+                                self.cache_store.insert(hsh, pth)
+                prop_name = "intermediate_certs"
+                if ca:
+                        prop_name = "signing_ca_certs"
+                t = set(self.cfg.get_property("publisher", prop_name))
+                t.update(hshs)
+                self.cfg.set_property("publisher", prop_name, sorted(t))
+                if write_config:
+                        self.write_config()
+
+        def remove_signing_certs(self, hshs, ca, write_config=True):
+                """Remove the given hashes from the certificates configured
+                for the publisher.  Whether the hashes are removed from the
+                list of CA certificates or the list of intermediate certificates
+                is determined by the 'ca' parameter. """
+
+                prop_name = "intermediate_certs"
+                if ca:
+                        prop_name = "signing_ca_certs"
+                t = set(self.cfg.get_property("publisher", prop_name))
+                t.difference_update(hshs)
+                self.cfg.set_property("publisher", prop_name, sorted(t))
+                if write_config:
+                        self.write_config()
+
         catalog_root = property(__get_catalog_root, __set_catalog_root)
         file_root = property(__get_file_root, __set_file_root)
         repo_root = property(__get_repo_root, __set_repo_root)
@@ -1494,6 +1638,8 @@
                 cfg.PropertySection("publisher", [
                     cfg.PropPublisher("alias"),
                     cfg.PropPublisher("prefix"),
+                    cfg.PropList("signing_ca_certs"),
+                    cfg.PropList("intermediate_certs"),
                 ]),
                 cfg.PropertySection("repository", [
                     cfg.PropDefined("collection_type", ["core",
--- a/src/modules/server/transaction.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/modules/server/transaction.py	Mon Aug 16 16:48:50 2010 -0700
@@ -19,8 +19,10 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+
+#
+# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+#
 
 import calendar
 import datetime
@@ -101,6 +103,12 @@
                             "package data for more than one publisher or "
                             "a default publisher has not been defined.") % \
                             self._args.get("pfmri", "")
+                elif "missing_fmri" in self._args:
+                        return _("Need an existing instance of %s to exist to "
+                            "append to it") % self._args.get("pfmri", "")
+                elif "non_sig" in self._args:
+                        return _("Only a signature can be appended to an "
+                            "existing package")
                 elif "pfmri" in self._args:
                         return _("The specified FMRI, '%s', is invalid.") % \
                             self._args["pfmri"]
@@ -133,6 +141,8 @@
                 self.renamed = False
                 self.has_reqdeps = False
                 self.types_found = set()
+                self.append_trans = False
+                self.remaining_payload_cnt = 0
                 return
 
         def get_basename(self):
@@ -251,6 +261,96 @@
                 # if not found, create package
                 # set package state to TRANSACTING
 
+        def append(self, repo, client_release, pfmri):
+                # XXX needs to be done in __init__
+                self.repo = repo
+                self.append_trans = True
+
+                if client_release is None:
+                        raise TransactionOperationError(client_release=None,
+                            pfmri=pfmri)
+                if pfmri is None:
+                        raise TransactionOperationError(pfmri=None)
+
+                self.client_release = client_release
+                self.pkg_name = pfmri
+                self.esc_pkg_name = urllib.quote(pfmri, "")
+
+                # attempt to construct an FMRI object
+                try:
+                        self.fmri = fmri.PkgFmri(self.pkg_name,
+                            self.client_release)
+                except fmri.FmriError, e:
+                        raise TransactionOperationError(e)
+
+                # Version and timestamp is required for appending.
+                if self.fmri.version is None or not self.fmri.get_timestamp():
+                        raise TransactionOperationError(fmri_version=None,
+                            pfmri=pfmri)
+
+                # Ensure that the FMRI has been fully qualified with publisher
+                # information or apply the default if appropriate.
+                if not self.fmri.publisher:
+                        c = repo.catalog
+                        pubs = c.publishers()
+                        default_pub = repo.cfg.get_property("publisher",
+                            "prefix")
+
+                        if len(pubs) > 1 or not default_pub:
+                                # A publisher is required if the repository
+                                # contains package data for more than one
+                                # publisher or no default has been defined.
+                                raise TransactionOperationError(
+                                    publisher_required=True, pfmri=pfmri)
+
+                        self.fmri.publisher = default_pub
+                        pkg_name = self.pkg_name
+                        pub_string = "pkg://%s/" % default_pub
+                        if not pkg_name.startswith("pkg:/"):
+                                pkg_name = pub_string + pkg_name
+                        else:
+                                pkg_name = pkg_name.replace("pkg:/", pub_string)
+                        self.pkg_name = pkg_name
+                        self.esc_pkg_name = urllib.quote(pkg_name, "")
+
+                # record transaction metadata: opening_time, package, user
+                self.open_time = self.fmri.get_timestamp()
+                if self.open_time:
+                        # Strip the timestamp information for consistency with
+                        # the case where it was not specified.
+                        self.pkg_name = ":".join(pfmri.split(":")[:-1])
+                        self.esc_pkg_name = urllib.quote(self.pkg_name, "")
+                else:
+                        # A timestamp was not provided.
+                        self.open_time = datetime.datetime.utcnow()
+                        self.fmri.set_timestamp(self.open_time)
+
+                if not repo.valid_append_fmri(self.fmri):
+                        raise TransactionOperationError(missing_fmri=True,
+                            pfmri=self.fmri)
+
+                trans_basename = self.get_basename()
+                self.dir = "%s/%s" % (repo.trans_root, trans_basename)
+
+                try:
+                        os.makedirs(self.dir)
+                except EnvironmentError, e:
+                        if e.errno == errno.EEXIST:
+                                raise TransactionAlreadyOpenError(
+                                    trans_basename)
+                        raise TransactionOperationError(e)
+
+                # Record that this is an append operation so that it can be
+                # reopened correctly.
+                with open(os.path.join(self.dir, "append"), "wb") as fh:
+                        pass
+
+                # copy in existing manifest, then open it for appending
+                m = self.repo._get_manifest(pfmri)
+                tfile = file("%s/manifest" % self.dir, "ab+")
+                tfile.write(str(m))
+                tfile.close()
+
         def reopen(self, repo, trans_dir):
                 """The reopen() method is invoked on server restart, to
                 reestablish the status of inflight transactions."""
@@ -278,6 +378,8 @@
                 m = pkg.manifest.Manifest()
                 m.set_content(tfile.read())
                 tfile.close()
+                if os.path.exists(os.path.join(self.dir, "append")):
+                        self.append_trans = True
                 self.obsolete = m.getbool("pkg.obsolete", "false")
                 self.renamed = m.getbool("pkg.renamed", "false")
                 self.types_found = set((
@@ -299,8 +401,12 @@
                 pkg_state = "SUBMITTED"
 
                 # set state to PUBLISHED
-                pkg_fmri, pkg_state = self.accept_publish(refresh_index,
-                add_to_catalog)
+                if self.append_trans:
+                        pkg_fmri, pkg_state = self.accept_append(refresh_index,
+                            add_to_catalog)
+                else:
+                        pkg_fmri, pkg_state = self.accept_publish(refresh_index,
+                            add_to_catalog)
 
                 # Discard the in-flight transaction data.
                 try:
@@ -330,15 +436,16 @@
                 except actions.ActionError, e:
                         raise TransactionOperationError(e)
 
+                if self.append_trans and action.name != "signature":
+                        raise TransactionOperationError(non_sig=True)
+
                 size = int(action.attrs.get("pkg.size", 0))
 
-                if action.name in ("file", "license") and size <= 0:
+                if action.has_payload and size <= 0:
                         # XXX hack for empty files
                         action.data = lambda: open(os.devnull, "rb")
 
                 if action.data is not None:
-                        bufsz = 64 * 1024
-
                         fname, data = misc.get_data_digest(action.data(),
                             length=size, return_content=True)
 
@@ -367,65 +474,16 @@
                                 action.attrs["elfarch"] = elf_info["arch"]
                                 os.unlink(elf_name)
 
-                        #
-                        # This check prevents entering into the depot store
-                        # a file which is already there in the store.
-                        # This takes CPU load off the depot on large imports
-                        # of mostly-the-same stuff.  And in general it saves
-                        # disk bandwidth, and on ZFS in particular it saves
-                        # us space in differential snapshots.  We also need
-                        # to check that the destination is in the same
-                        # compression format as the source, as we must have
-                        # properly formed files for chash/csize properties
-                        # to work right.
-                        #
                         dst_path = self.repo.cache_store.lookup(fname)
-                        fileneeded = True
-                        if dst_path:
-                                if PkgGzipFile.test_is_pkggzipfile(dst_path):
-                                        fileneeded = False
-                                        opath = dst_path
-
-                        if fileneeded:
-                                opath = os.path.join(self.dir, fname)
-                                ofile = PkgGzipFile(opath, "wb")
-
-                                nbuf = size / bufsz
-
-                                for n in range(0, nbuf):
-                                        l = n * bufsz
-                                        h = (n + 1) * bufsz
-                                        ofile.write(data[l:h])
-
-                                m = nbuf * bufsz
-                                ofile.write(data[m:])
-                                ofile.close()
-
+                        csize, chash = misc.compute_compressed_attrs(fname,
+                            dst_path, data, size, self.dir)
+                        action.attrs["chash"] = chash.hexdigest()
+                        action.attrs["pkg.csize"] = csize
+                        chash = None
                         data = None
 
-                        # Now that the file has been compressed, determine its
-                        # size and store that as an attribute in the manifest
-                        # for the file.
-                        fs = os.stat(opath)
-                        action.attrs["pkg.csize"] = str(fs.st_size)
-
-                        # Compute the SHA hash of the compressed file.
-                        # Store this as the chash attribute of the file's
-                        # action.  In order for this to work correctly, we
-                        # have to use the PkgGzipFile class.  It omits
-                        # filename and timestamp information from the gzip
-                        # header, allowing us to generate deterministic
-                        # hashes for different files with identical content.
-                        cfile = open(opath, "rb")
-                        chash = hashlib.sha1()
-                        while True:
-                                cdata = cfile.read(bufsz)
-                                if cdata == "":
-                                        break
-                                chash.update(cdata)
-                        cfile.close()
-                        action.attrs["chash"] = chash.hexdigest()
-                        cdata = None
+                self.remaining_payload_cnt = \
+                    len(action.attrs.get("chain.sizes", "").split())
 
                 # Do some sanity checking on packages marked or being marked
                 # obsolete or renamed.
@@ -476,6 +534,23 @@
 
                 self.types_found.add(action.name)
 
+        def add_file(self, f, size=None):
+                """Adds the file to the Transaction."""
+
+                fname, data = misc.get_data_digest(f, length=size,
+                    return_content=True)
+
+                if size is None:
+                        size = len(data)
+
+                dst_path = self.repo.cache_store.lookup(fname)
+                csize, chash = misc.compute_compressed_attrs(fname, dst_path,
+                    data, size, self.dir)
+                chash = None
+                data = None
+
+                self.remaining_payload_cnt -= 1
+
         def accept_publish(self, refresh_index=True, add_to_catalog=True):
                 """Transaction meets consistency criteria, and can be published.
                 Publish, making appropriate catalog entries."""
@@ -488,11 +563,38 @@
                 # XXX If we are going to publish, then we should augment
                 # our response with any other packages that moved to
                 # PUBLISHED due to the package's arrival.
+
+                self.publish_package()
+
+                if add_to_catalog:
+                        self.repo.add_package(self.fmri)
+                if refresh_index:
+                        self.repo.refresh_index()
+
+                return (str(self.fmri), "PUBLISHED")
+
+        def accept_append(self, refresh_index=True, add_to_catalog=True):
+                """Transaction meets consistency criteria, and can be published.
+                Publish, making appropriate catalog replacements."""
+
+                # Ensure that a renamed package has at least one dependency
+                if self.renamed and not self.has_reqdeps:
+                        raise TransactionOperationError(_("A renamed package "
+                            "must contain at least one 'depend' action."))
+
+                if self.remaining_payload_cnt > 0:
+                        raise TransactionOperationError(_("At least one "
+                            "certificate has not been delivered for the "
+                            "signature action."))
+
+                # XXX If we are going to publish, then we should augment
+                # our response with any other packages that moved to
+                # PUBLISHED due to the package's arrival.
                 
                 self.publish_package()
 
                 if add_to_catalog:
-                        self.repo.add_package(self.fmri)
+                        self.repo.replace_package(self.fmri)
                 if refresh_index:
                         self.repo.refresh_index()
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/patch/M2Crypto/crl.patch	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,196 @@
+diff -r 49981e7aa9ca M2Crypto-0.20.2/M2Crypto/X509.py
+--- M2Crypto/X509.py	Mon Jun 14 13:46:27 2010 -0700
++++ M2Crypto/X509.py	Thu Jul 08 17:48:27 2010 -0700
+@@ -446,9 +446,9 @@
+         assert m2.x509_type_check(self.x509), "'x509' type error"
+         return ASN1.ASN1_UTCTIME(m2.x509_get_not_after(self.x509))
+ 
+-    def get_pubkey(self):
++    def get_pubkey(self, md="sha1"):
+         assert m2.x509_type_check(self.x509), "'x509' type error"
+-        return EVP.PKey(m2.x509_get_pubkey(self.x509), _pyfree=1)
++        return EVP.PKey(m2.x509_get_pubkey(self.x509), _pyfree=1, md=md)
+ 
+     def set_pubkey(self, pkey):
+         """
+@@ -1067,6 +1067,7 @@
+         else:
+             self.crl = m2.x509_crl_new()
+             self._pyfree = 1
++        self.revocations = None
+             
+     def __del__(self):
+         if getattr(self, '_pyfree', 0):
+@@ -1083,22 +1084,67 @@
+         m2.x509_crl_print(buf.bio_ptr(), self.crl)
+         return buf.read_all()
+ 
++    def get_last_update(self):
++        assert m2.x509_CRL_type_check(self.crl), "'x509_CRL' type error"
++        return ASN1.ASN1_UTCTIME(m2.x509_CRL_get_last_update(self.crl))
+ 
+-def load_crl(file):
++    def get_next_update(self):
++        assert m2.x509_CRL_type_check(self.crl), "'x509_CRL' type error"
++        return ASN1.ASN1_UTCTIME(m2.x509_CRL_get_next_update(self.crl))
++
++    def verify(self, pkey):
++        assert m2.x509_CRL_type_check(self.crl), "'x509_CRL' type error"
++        return m2.x509_CRL_verify(self.crl, pkey.pkey)
++
++    def get_issuer(self):
++        assert m2.x509_CRL_type_check(self.crl), "'x509_CRL' type error"
++        return X509_Name(m2.x509_CRL_get_issuer(self.crl))
++    
++    def is_revoked(self, cert):
++        if self.revocations is None:
++            self.revocations = {}
++            revo_stk_ptr = m2.x509_CRL_get_revoked(self.crl)
++            for i in range(m2.sk_x509_REVOKED_num(revo_stk_ptr)):
++                revo_ptr = m2.sk_x509_REVOKED_get(revo_stk_ptr, i)
++                revo_sn = m2.asn1_integer_get(
++                    m2.x509_REVOKED_get_serial_number(revo_ptr))
++                cnt = m2.x509_REVOKED_get_ext_count(revo_ptr)
++                reason = None
++                for i in range(m2.x509_REVOKED_get_ext_count(revo_ptr)):
++                    ext_ptr = m2.x509_REVOKED_get_ext(revo_ptr, i)
++                    name = m2.x509_extension_get_name(ext_ptr)
++                    if name == "CRLReason":
++                        ext = X509_Extension(ext_ptr, _pyfree=0)
++                        reason = ext.get_value()
++                self.revocations[revo_sn] = (True, reason)
++        return self.revocations.get(cert.get_serial_number(), None)
++            
++
++def load_crl(file, format=FORMAT_PEM):
+     """
+     Load CRL from file.
+ 
+     @type file: string
+     @param file: Name of file containing CRL in PEM format.
+ 
++    @type format: int, either FORMAT_PEM or FORMAT_DER
++    @param format: Describes the format of the file to be loaded, either PEM or DER.
++
+     @rtype: M2Crypto.X509.CRL
+     @return: M2Crypto.X509.CRL object.
+     """
+     f=BIO.openfile(file)
+-    cptr=m2.x509_crl_read_pem(f.bio_ptr())
+-    f.close()
+-    if cptr is None:
+-        raise X509Error(Err.get_error())
+-    return CRL(cptr, 1)
+-
+-
++    if format == FORMAT_PEM:
++        cptr=m2.x509_crl_read_pem(f.bio_ptr())
++        f.close()
++        if cptr is None:
++            raise X509Error(Err.get_error())
++        return CRL(cptr, 1)
++    elif format == FORMAT_DER:
++        cptr=m2.d2i_x509_crl(f._ptr())
++        f.close()
++        if cptr is None:
++            raise X509Error(Err.get_error())
++        return CRL(cptr, 1)
++    else:
++        raise ValueError("Unknown format. Must be either FORMAT_DER or FORMAT_PEM")
+diff -r 49981e7aa9ca M2Crypto-0.20.2/SWIG/_x509.i
+--- SWIG/_x509.i	Mon Jun 14 13:46:27 2010 -0700
++++ SWIG/_x509.i	Thu Jul 08 17:48:27 2010 -0700
+@@ -61,6 +61,9 @@
+ %rename(x509_cmp_current_time) X509_cmp_current_time;
+ extern int X509_cmp_current_time(ASN1_UTCTIME *);
+ 
++%rename(x509_CRL_get_issuer) X509_CRL_get_issuer;
++extern X509_NAME *X509_CRL_get_issuer(X509_CRL *);
++
+                             
+ /* From x509.h */
+ /* standard trust ids */
+@@ -108,6 +111,9 @@
+ %rename(x509_get_verify_error) X509_verify_cert_error_string;
+ extern const char *X509_verify_cert_error_string(long);
+ 
++%rename(x509_CRL_verify) X509_CRL_verify;
++extern int X509_CRL_verify(X509_CRL *a, EVP_PKEY *r);
++
+ %constant long X509V3_EXT_UNKNOWN_MASK         = (0xfL << 16);
+ %constant long X509V3_EXT_DEFAULT              = 0;
+ %constant long X509V3_EXT_ERROR_UNKNOWN        = (1L << 16);
+@@ -124,6 +130,13 @@
+ %threadallow X509V3_EXT_print;
+ extern int X509V3_EXT_print(BIO *, X509_EXTENSION *, unsigned long, int);
+ 
++%rename(x509_REVOKED_get_ext_count) X509_REVOKED_get_ext_count;
++extern int X509_REVOKED_get_ext_count(X509_REVOKED *);
++%rename(x509_REVOKED_get_ext) X509_REVOKED_get_ext;
++extern X509_EXTENSION *X509_REVOKED_get_ext(X509_REVOKED *, int);
++%rename(x509_REVOKED_get_ext_by_NID) X509_REVOKED_get_ext_by_NID;
++extern X509_EXTENSION *X509_REVOKED_get_ext_by_NID(X509_REVOKED *, int, int);
++
+ %rename(x509_name_new) X509_NAME_new;
+ extern X509_NAME *X509_NAME_new( void );
+ %rename(x509_name_free) X509_NAME_free;
+@@ -332,6 +345,13 @@
+ }
+ %}
+ 
++%threadallow d2i_x509_crl;
++%inline %{
++X509_CRL *d2i_x509_crl(BIO *bio) {
++    return d2i_X509_CRL_bio(bio, NULL);
++}
++%}
++
+ %threadallow d2i_x509_req;
+ %inline %{
+ X509_REQ *d2i_x509_req(BIO *bio) {
+@@ -405,6 +425,33 @@
+     return X509_get_notAfter(x);
+ }
+ 
++/* X509_CRL_get_lastUpdate() is a macro. */
++ASN1_UTCTIME *x509_CRL_get_last_update(X509_CRL *x) {
++    return X509_CRL_get_lastUpdate(x);
++}
++
++/* X509_CRL_get_nextUpdate() is a macro. */
++ASN1_UTCTIME *x509_CRL_get_next_update(X509_CRL *x) {
++    return X509_CRL_get_nextUpdate(x);
++}
++
++/* X509_CRL_get_REVOKED() is a macro. */
++STACK *x509_CRL_get_revoked(X509_CRL *x) {
++    return X509_CRL_get_REVOKED(x);
++}
++
++int sk_x509_REVOKED_num(STACK *stack) {
++    return sk_X509_REVOKED_num((STACK_OF(X509_REVOKED) *)stack);
++}
++
++X509_REVOKED *sk_x509_REVOKED_get(STACK *stack, int x) {
++    return sk_X509_REVOKED_value((STACK_OF(X509_REVOKED) *)stack, x);
++}
++
++ASN1_INTEGER *x509_REVOKED_get_serial_number(X509_REVOKED *x) {
++    return x->serialNumber;
++}
++
+ int x509_sign(X509 *x, EVP_PKEY *pkey, EVP_MD *md) {
+     return X509_sign(x, pkey, md);
+ }
+@@ -477,6 +524,11 @@
+     return 1;
+ }
+ 
++
++int x509_CRL_type_check(X509_CRL *x509_CRL) {
++    return 1;
++}
++
+ int x509_name_type_check(X509_NAME *name) {
+     return 1;
+ }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pkg/license_files/lic_m2crypto	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,24 @@
+Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.
+
+Portions copyright (c) 2004-2006 Open Source Applications Foundation. 
+All rights reserved.
+
+Portions copyright (c) 2005-2006 Vrije Universiteit Amsterdam. 
+All rights reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation.
+
+THE AUTHOR PROVIDES THIS SOFTWARE ``AS IS'' AND ANY EXPRESSED OR 
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--- a/src/pkg/manifests/developer%2Fopensolaris%2Fpkg5.p5m	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/pkg/manifests/developer%2Fopensolaris%2Fpkg5.p5m	Mon Aug 16 16:48:50 2010 -0700
@@ -28,6 +28,7 @@
 depend fmri=pkg:/developer/build/onbld type=require
 depend fmri=pkg:/developer/gnome/gettext type=require
 depend fmri=pkg:/developer/gnome/gnome-doc-utils type=require
+depend fmri=pkg:/developer/swig type=require
 depend fmri=pkg:/developer/versioning/mercurial type=require
 depend fmri=pkg:/library/python-2/setuptools-26 type=require
 depend fmri=pkg:/package/svr4 type=require
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pkg/manifests/library%2Fpython-2%2Fm2crypto.p5m	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,89 @@
+#
+# 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) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+set name=pkg.fmri value=pkg:/library/python-2/[email protected],$(PKGVERS_BUILTON)-$(PKGVERS_BRANCH)
+set name=pkg.summary value="Python interface for openssl"
+set name=pkg.description value="M2Crypto provides a python interface to the openssl library."
+set name=info.classification value=org.opensolaris.category.2008:Development/Python
+
+dir path=usr
+dir path=usr/lib
+dir path=$(PYDIR)
+dir path=$(PYDIRVP)
+dir path=$(PYDIRVP)/M2Crypto
+dir path=$(PYDIRVP)/M2Crypto-0.20.2-py2.6.egg-info
+file NOHASH path=$(PYDIRVP)/M2Crypto-0.20.2-py2.6.egg-info/PKG-INFO
+file NOHASH path=$(PYDIRVP)/M2Crypto-0.20.2-py2.6.egg-info/SOURCES.txt
+file NOHASH path=$(PYDIRVP)/M2Crypto-0.20.2-py2.6.egg-info/dependency_links.txt
+file NOHASH path=$(PYDIRVP)/M2Crypto-0.20.2-py2.6.egg-info/top_level.txt
+file NOHASH path=$(PYDIRVP)/M2Crypto/ASN1.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/AuthCookie.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/BIO.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/BN.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/DH.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/DSA.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/EC.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/EVP.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/Engine.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/Err.py
+dir path=$(PYDIRVP)/M2Crypto/PGP
+file NOHASH path=$(PYDIRVP)/M2Crypto/PGP/PublicKey.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/PGP/PublicKeyRing.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/PGP/RSA.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/PGP/__init__.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/PGP/constants.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/PGP/packet.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/RC4.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/RSA.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/Rand.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/SMIME.py
+dir path=$(PYDIRVP)/M2Crypto/SSL
+file NOHASH path=$(PYDIRVP)/M2Crypto/SSL/Checker.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/SSL/Cipher.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/SSL/Connection.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/SSL/Context.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/SSL/SSLServer.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/SSL/Session.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/SSL/TwistedProtocolWrapper.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/SSL/__init__.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/SSL/cb.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/SSL/ssl_dispatcher.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/SSL/timeout.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/X509.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/__init__.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/__m2crypto.so
+file NOHASH path=$(PYDIRVP)/M2Crypto/callback.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/ftpslib.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/httpslib.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/m2.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/m2urllib.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/m2urllib2.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/m2xmlrpclib.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/threading.py
+file NOHASH path=$(PYDIRVP)/M2Crypto/util.py
+
+license lic_m2crypto license=lic_m2crypto
+
+depend type=require fmri=library/security/[email protected]
+depend type=require fmri=runtime/[email protected]
+depend type=require fmri=system/library
--- a/src/pkg/manifests/package%2Fpkg.p5m	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/pkg/manifests/package%2Fpkg.p5m	Mon Aug 16 16:48:50 2010 -0700
@@ -48,6 +48,7 @@
 file path=usr/bin/pkgrecv
 file path=usr/bin/pkgrepo
 file path=usr/bin/pkgsend
+file path=usr/bin/pkgsign
 dir path=usr/lib
 file path=usr/lib/pkg.depotd mode=0755
 dir path=$(PYDIR)
@@ -101,6 +102,7 @@
 file path=$(PYDIRVP)/pkg/client/progress.py
 file path=$(PYDIRVP)/pkg/client/publisher.py
 file path=$(PYDIRVP)/pkg/client/query_parser.py
+file path=$(PYDIRVP)/pkg/client/sigpolicy.py
 dir path=$(PYDIRVP)/pkg/client/transport
 file path=$(PYDIRVP)/pkg/client/transport/__init__.py
 file path=$(PYDIRVP)/pkg/client/transport/engine.py
@@ -235,6 +237,7 @@
 file path=usr/share/man/cat1/pkgrecv.1
 file path=usr/share/man/cat1/pkgrepo.1
 file path=usr/share/man/cat1/pkgsend.1
+file path=usr/share/man/cat1/pkgsign.1
 dir path=usr/share/man/cat1m
 file path=usr/share/man/cat1m/pkg.depotd.1m
 dir path=usr/share/man/cat5
@@ -258,6 +261,7 @@
 depend type=require fmri=crypto/ca-certificates
 depend type=require fmri=library/python-2/[email protected]
 depend type=require fmri=library/python-2/[email protected]
+depend type=require fmri=library/python-2/[email protected]
 depend type=require fmri=library/python-2/[email protected]
 depend type=require fmri=library/python-2/[email protected]
 depend type=require fmri=library/python-2/[email protected]
--- a/src/pkgrepo.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/pkgrepo.py	Mon Aug 16 16:48:50 2010 -0700
@@ -111,6 +111,11 @@
         pkgrepo rebuild [--no-index]
         pkgrepo refresh [--no-catalog] [--no-index]
 
+        pkgrepo add-signing-ca-cert path ...
+        pkgrepo add-signing-intermediate-cert path ...
+        pkgrepo remove-signing-ca-cert hash ...
+        pkgrepo remove-signing-intermediate-cert hash ...
+
         pkgrepo version
         pkgrepo help
 
@@ -175,6 +180,52 @@
             refresh_index=refresh_index, repo_root=path)
 
 
+def subcmd_add_signing_ca_cert(conf, args):
+        subcommand = "add-signing-ca-cert"
+        repo = get_repo(conf, read_only=False)
+        opts, pargs = getopt.getopt(args, "")
+
+        if len(pargs) < 1:
+                usage(_("At least one path to a certificate must be provided."))
+
+        fps = [os.path.abspath(f) for f in pargs]
+        repo.add_signing_certs(fps, ca=True)
+
+
+def subcmd_add_signing_intermediate_cert(conf, args):
+        subcommand = "add-signing-intermediate-cert"
+        repo = get_repo(conf, read_only=False)
+        opts, pargs = getopt.getopt(args, "")
+
+        if len(pargs) < 1:
+                usage(_("At least one path to a certificate must be provided."))
+
+        fps = [os.path.abspath(f) for f in pargs]
+        repo.add_signing_certs(fps, ca=False)
+
+
+def subcmd_remove_signing_ca_cert(conf, args):
+        subcommand = "remove-signing-ca-cert"
+        repo = get_repo(conf, read_only=False)
+        opts, pargs = getopt.getopt(args, "")
+
+        if len(pargs) < 1:
+                usage(_("At least one certificate hash must be provided."))
+
+        repo.remove_signing_certs(pargs, ca=True)
+
+
+def subcmd_remove_signing_intermediate_cert(conf, args):
+        subcommand = "remove-signing-intermediate-cert"
+        repo = get_repo(conf, read_only=False)
+        opts, pargs = getopt.getopt(args, "")
+
+        if len(pargs) < 1:
+                usage(_("At least one certificate hash must be provided."))
+
+        repo.remove_signing_certs(pargs, ca=False)
+
+
 def subcmd_create(conf, args):
         """Create a package repository at the given location."""
 
--- a/src/publish.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/publish.py	Mon Aug 16 16:48:50 2010 -0700
@@ -169,6 +169,35 @@
 
         return 0
 
+def trans_append(repo_uri, args):
+
+        opts, pargs = getopt.getopt(args, "en")
+
+        parsed = []
+        eval_form = True
+        for opt, arg in opts:
+                parsed.append(opt)
+                if opt == "-e":
+                        eval_form = True
+                if opt == "-n":
+                        eval_form = False
+
+        if "-e" in parsed and "-n" in parsed:
+                usage(_("only -e or -n may be specified"), cmd="open")
+
+        if len(pargs) != 1:
+                usage(_("append requires one package name"), cmd="open")
+
+        xport, pub = setup_transport_and_pubs(repo_uri)
+
+        t = trans.Transaction(repo_uri, pkg_name=pargs[0], xport=xport, pub=pub)
+        if eval_form:
+                msg("export PKG_TRANS_ID=%s" % t.append())
+        else:
+                msg(t.append())
+
+        return 0
+
 def trans_close(repo_uri, args):
         abandon = False
         trans_id = None
@@ -313,9 +342,15 @@
                 # don't publish this action
                 if a.name == "set" and a.attrs["name"] in ["pkg.fmri", "fmri"]:
                         continue
-                elif a.name == "file":
-                        path, bd = pkg.actions.set_action_data(
-                            a.hash, a, basedirs)
+                elif a.has_payload:
+                        path, bd = pkg.actions.set_action_data(a.hash, a,
+                            basedirs)
+                elif a.name in nopub_actions:
+                        error(_("invalid action for publication: %s") % action,
+                            cmd="publish")
+                        t.close(abandon=True)
+                        return 1
+                if a.name == "file":
                         basename = os.path.basename(a.attrs["path"])
                         for pattern in timestamp_files:
                                 if fnmatch.fnmatch(basename, pattern):
@@ -323,13 +358,6 @@
                                             os.stat(path).st_mtime)
                                         a.attrs["timestamp"] = ts
                                         break
-                elif a.name == "license":
-                        pkg.actions.set_action_data(a.hash, a, basedirs)
-                elif a.name in nopub_actions:
-                        error(_("invalid action for publication: %s") % action,
-                            cmd="publish")
-                        t.close(abandon=True)
-                        return 1
                 try:
                         t.add(a)
                 except:
@@ -416,9 +444,10 @@
                 # don't publish this action
                 if a.name == "set" and a.attrs["name"] in  ["pkg.fmri", "fmri"]:
                         continue
-                elif a.name == "file":
-                        path, bd = pkg.actions.set_action_data(
-                            a.hash, a, basedirs)
+                elif a.has_payload:
+                        path, bd = pkg.actions.set_action_data(a.hash, a,
+                            basedirs)
+                if a.name == "file":
                         basename = os.path.basename(a.attrs["path"])
                         for pattern in timestamp_files:
                                 if fnmatch.fnmatch(basename, pattern):
@@ -426,8 +455,6 @@
                                             os.stat(path).st_mtime)
                                         a.attrs["timestamp"] = ts
                                         break
-                elif a.name == "license":
-                        pkg.actions.set_action_data(a.hash, a, basedirs)
 
                 if a.name in nopub_actions:
                         error(_("invalid action for publication: %s") % str(a),
@@ -606,6 +633,8 @@
                         ret = trans_create_repository(repo_uri, pargs)
                 elif subcommand == "open":
                         ret = trans_open(repo_uri, pargs)
+                elif subcommand == "append":
+                        ret = trans_append(repo_uri, pargs)
                 elif subcommand == "close":
                         ret = trans_close(repo_uri, pargs)
                 elif subcommand == "add":
--- a/src/pull.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/pull.py	Mon Aug 16 16:48:50 2010 -0700
@@ -51,7 +51,7 @@
 import pkg.version as version
 
 from pkg.client import global_settings
-from pkg.misc import (emsg, get_pkg_otw_size, msg, PipeError)
+from pkg.misc import (config_temp_root, emsg, get_pkg_otw_size, msg, PipeError)
 
 # Globals
 cache_dir = None
@@ -378,26 +378,6 @@
         tracker.catalog_done()
         return fmri_list
 
-def config_temp_root():
-        """Examine the environment.  If the environment has set TMPDIR, TEMP,
-        or TMP, return None.  This tells tempfile to use the environment
-        settings when creating temporary files/directories.  Otherwise,
-        return a path that the caller should pass to tempfile instead."""
-
-        default_root = "/var/tmp"
-
-        # In Python's tempfile module, the default temp directory
-        # includes some paths that are suboptimal for holding large numbers
-        # of files.  If the user hasn't set TMPDIR, TEMP, or TMP in the
-        # environment, override the default directory for creating a tempfile.
-        tmp_envs = [ "TMPDIR", "TEMP", "TMP" ]
-        for ev in tmp_envs:
-                env_val = os.getenv(ev)
-                if env_val:
-                        return None
-
-        return default_root
-
 def main_func():
         global cache_dir, download_start, xport, xport_cfg
         all_timestamps = False
--- a/src/setup.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/setup.py	Mon Aug 16 16:48:50 2010 -0700
@@ -141,6 +141,14 @@
 if osname in ("sunos", "linux", "darwin"):
         PCENVIRON = {'CFLAGS': '-O3'}
 
+M2C = 'M2Crypto'
+M2CIDIR = 'm2crypto'
+M2CVER = '0.20.2'
+M2CARC = '%s-%s.tar.gz' % (M2C, M2CVER)
+M2CDIR = '%s-%s' % (M2C, M2CVER)
+M2CURL = 'http://pypi.python.org/packages/source/M/M2Crypto/%s' % (M2CARC)
+M2CHASH = '6e85d7035971c353db74a497fca0ec2eaea4dea0'
+
 pwd = os.path.normpath(sys.path[0])
 
 #
@@ -193,6 +201,7 @@
                 ['util/publish/pkgmogrify.py', 'pkgmogrify'],
                 ['publish.py', 'pkgsend'],
                 ['pull.py', 'pkgrecv'],
+                ['sign.py', 'pkgsign'],
                 ['packagemanager.py', 'packagemanager'],
                 ['updatemanager.py', 'pm-updatemanager'],
                 ],
@@ -261,6 +270,7 @@
         'man/pkgfmt.1',
         'man/pkgmogrify.1',
         'man/pkgsend.1',
+        'man/pkgsign.1',
         'man/pkgrecv.1',
         'man/pkgrepo.1',
         'man/pm-updatemanager.1',
@@ -502,6 +512,8 @@
                         prep_sw(PO, POARC, PODIR, POURL, POHASH)
                         install_sw(PO, PODIR, POIDIR)
                         os.environ = saveenv
+                prep_sw(M2C, M2CARC, M2CDIR, M2CURL, M2CHASH)
+                install_sw(M2C, M2CDIR, M2CIDIR)
                 prep_sw(MAKO, MAKOARC, MAKODIR, MAKOURL, MAKOHASH)
                 install_sw(MAKO, MAKODIR, MAKOIDIR)
                 prep_sw(PLY, PLYARC, PLYDIR, PLYURL, PLYHASH)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sign.py	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,327 @@
+#!/usr/bin/python2.6
+#
+# 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) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+import getopt
+import gettext
+import locale
+import os
+import shutil
+import sys
+import tempfile
+import traceback
+import urllib
+import urlparse
+
+import pkg
+import pkg.actions as actions
+import pkg.client.api_errors as api_errors
+import pkg.client.transport.transport as transport
+import pkg.config as cfg
+import pkg.fmri as fmri
+import pkg.manifest as manifest
+import pkg.misc as misc
+import pkg.publish.transaction as trans
+import pkg.server.repository as sr
+from pkg.client import global_settings
+from pkg.misc import emsg, msg, PipeError
+
+PKG_CLIENT_NAME = "pkgsign"
+
+# pkg exit codes
+EXIT_OK      = 0
+EXIT_OOPS    = 1
+EXIT_BADOPT  = 2
+EXIT_PARTIAL = 3
+
+repo_cache = {}
+
+def error(text, cmd=None):
+        """Emit an error message prefixed by the command name """
+
+        if cmd:
+                text = "%s: %s" % (cmd, text)
+                
+        else:
+                text = "%s: %s" % (PKG_CLIENT_NAME, text)
+
+
+        # If the message starts with whitespace, assume that it should come
+        # *before* the command-name prefix.
+        text_nows = text.lstrip()
+        ws = text[:len(text) - len(text_nows)]
+
+        # This has to be a constant value as we can't reliably get our actual
+        # program name on all platforms.
+        emsg(ws + text_nows)
+
+def usage(usage_error=None, cmd=None, retcode=EXIT_BADOPT):
+        """Emit a usage message and optionally prefix it with a more specific
+        error message.  Causes program to exit."""
+
+        if usage_error:
+                error(usage_error, cmd=cmd)
+        emsg (_("""\
+Usage:
+        pkgsign [-aciks] [--no-index] [--no-catalog]
+            [--sign-all | fmri-to-sign ...]
+"""))
+
+        sys.exit(retcode)
+
+def fetch_catalog(src_pub, xport, temp_root, list_packages=False):
+        """Fetch the catalog from src_uri."""
+        global complete_catalog
+
+        src_uri = src_pub.selected_repository.origins[0].uri
+        # tracker.catalog_start(src_uri)
+
+        if not src_pub.meta_root:
+                # Create a temporary directory for catalog.
+                cat_dir = tempfile.mkdtemp(dir=temp_root)
+                src_pub.meta_root = cat_dir
+
+        src_pub.transport = xport
+        src_pub.refresh(True, True)
+
+        if not list_packages:
+                return
+        
+        cat = src_pub.catalog
+
+        d = {}
+        fmri_list = []
+        for f in cat.fmris():
+                fmri_list.append(f)
+                d.setdefault(f.pkg_name, [f]).append(f)
+        for k in d.keys():
+                d[k].sort(reverse=True)
+
+        complete_catalog = d
+        return fmri_list
+
+def main_func():
+        misc.setlocale(locale.LC_ALL, "", error)
+        gettext.install("pkg", "/usr/share/locale")
+        global_settings.client_name = "pkgsign"
+
+        try:
+                opts, pargs = getopt.getopt(sys.argv[1:], "a:c:i:k:s:",
+                    ["help", "no-index", "no-catalog", "sign-all"])
+        except getopt.GetoptError, e:
+                usage(_("illegal global option -- %s") % e.opt)
+
+        show_usage = False
+        sig_alg = "rsa-sha256"
+        cert_path = None
+        key_path = None
+        chain_certs = []
+        refresh_index = True
+        add_to_catalog = True
+        set_alg = False
+        sign_all = False
+
+        try:
+                repo_uri = os.environ["PKG_REPO"]
+        except KeyError:
+                repo_uri = "http://localhost:10000"
+        
+        for opt, arg in opts:
+                if opt == "-a":
+                        sig_alg = arg
+                        set_alg = True
+                elif opt == "-c":
+                        cert_path = os.path.abspath(arg)
+                        if not os.path.isfile(cert_path):
+                                usage(_("%s was expected to be a certificate "
+                                    "but isn't a file.") % cert_path)
+                elif opt == "-i":
+                        p = os.path.abspath(arg)
+                        if not os.path.isfile(p):
+                                usage(_("%s was expected to be a certificate "
+                                    "but isn't a file.") % p)
+                        chain_certs.append(p)
+                elif opt == "-k":
+                        key_path = os.path.abspath(arg)
+                        if not os.path.isfile(key_path):
+                                usage(_("%s was expected to be a key file "
+                                    "but isn't a file.") % key_path)
+                elif opt == "-s":
+                        repo_uri = arg
+                elif opt == "--help":
+                        show_usage = True
+                elif opt == "--no-index":
+                        refresh_index = False
+                elif opt == "--no-catalog":
+                        add_to_catalog = False
+                elif opt == "--sign-all":
+                        sign_all = True
+
+        if show_usage:
+                usage(retcode=EXIT_OK)
+
+        if key_path and not cert_path:
+                usage(_("If a key is given to sign with, its associated "
+                    "certificate must be given."))
+
+        if cert_path and not key_path:
+                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 and not sign_all:
+                usage(_("At least one fmri must be provided for signing."))
+
+        if pargs and sign_all:
+                usage(_("No fmris may be provided if the sign-all option is "
+                    "set."))
+
+        if not set_alg and not key_path:
+                sig_alg = "sha256"
+
+        s, h = actions.signature.SignatureAction.decompose_sig_alg(sig_alg)
+        if h is None:
+                usage(_("%s is not a recognized signature algorithm.") %
+                    sig_alg)
+        if s and not key_path:
+                usage(_("Using %s as the signature algorithm requires that a "
+                    "key and certificate pair be presented using the -k and -c "
+                    "options.") % sig_alg)
+        if not s and key_path:
+                usage(_("The %s hash algorithm does not use a key or "
+                    "certificate.  Do not use the -k or -c options with this "
+                    "algorithm.") % sig_alg)
+
+        errors = []
+
+        t = misc.config_temp_root()
+        temp_root = tempfile.mkdtemp(dir=t)
+        del t
+        
+        cache_dir = tempfile.mkdtemp(dir=temp_root)
+        incoming_dir = tempfile.mkdtemp(dir=temp_root)
+
+        try:
+                xport, xport_cfg = transport.setup_transport()
+                xport_cfg.cached_download_dir = cache_dir
+                xport_cfg.incoming_download_dir = incoming_dir
+
+                # Configure src publisher
+                src_pub = transport.setup_publisher(repo_uri, "source", xport,
+                    xport_cfg, remote_prefix=True)
+                fmris = fetch_catalog(src_pub, xport, temp_root,
+                    list_packages=sign_all)
+                if not sign_all:
+                        fmris = pargs
+                succesful_publish = False
+
+                for pfmri in fmris:
+                        try:
+                                if isinstance(pfmri, basestring):
+                                        pfmri = fmri.PkgFmri(pfmri)
+
+                                # Get the existing manifest for the package to
+                                # be sign.
+                                m_str = xport.get_manifest(pfmri,
+                                    content_only=True, pub=src_pub)
+                                m = manifest.Manifest()
+                                m.set_content(m_str)
+
+                                # Construct the base signature action.
+                                attrs = { "algorithm": sig_alg }
+                                a = actions.signature.SignatureAction(cert_path,
+                                    **attrs)
+                                a.hash = cert_path
+
+                                # Add the action to the manifest to be signed
+                                # since the action signs itself.
+                                m.add_action(a, misc.EmptyI)
+
+                                # Set the signature value and certificate
+                                # information for the signature action.
+                                a.set_signature(m.gen_actions(),
+                                    key_path=key_path, chain_paths=chain_certs)
+
+                                # Append the finished signature action to the
+                                # published manifest.
+                                t = trans.Transaction(repo_uri,
+                                    pkg_name=str(pfmri), xport=xport,
+                                    pub=src_pub, refresh_index=refresh_index)
+                                t.append()
+                                try:
+                                        t.add(a)
+                                        for c in chain_certs:
+                                                t.add_file(c)
+                                        t.close(refresh_index=refresh_index,
+                                            add_to_catalog=add_to_catalog)
+                                except:
+                                        t.close(abandon=True)
+                                        raise
+                                msg(_("Signed %s") % pfmri)
+                                succesful_publish = True
+                        except (api_errors.ApiException, fmri.FmriError,
+                            trans.TransactionError), e:
+                                errors.append(e)
+                if errors:
+                        error("\n".join([str(e) for e in errors]))
+                        if succesful_publish:
+                                return EXIT_PARTIAL
+                        else:
+                                return EXIT_OOPS
+                return EXIT_OK
+        except (api_errors.TransportError,
+            api_errors.UnsupportedRepositoryURI),e:
+                error(e)
+                return EXIT_OOPS
+        finally:
+                shutil.rmtree(cache_dir)
+                shutil.rmtree(incoming_dir)
+
+#
+# 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:
+                __ret = main_func()
+        except (PipeError, KeyboardInterrupt):
+                # We don't want to display any messages here to prevent
+                # possible further broken pipe (EPIPE) errors.
+                __ret = EXIT_OOPS
+        except SystemExit, _e:
+                raise _e
+        except:
+                traceback.print_exc()
+                error(
+                    _("\n\nThis is an internal error.  Please let the "
+                    "developers know about this\nproblem by filing a bug at "
+                    "http://defect.opensolaris.org and including the\nabove "
+                    "traceback and this message.  The version of pkg(5) is "
+                    "'%s'.") % pkg.VERSION)
+                __ret = 99
+        sys.exit(__ret)
--- a/src/tests/api/t_action.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/tests/api/t_action.py	Mon Aug 16 16:48:50 2010 -0700
@@ -20,7 +20,9 @@
 # CDDL HEADER END
 #
 
+#
 # Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+#
 
 import testutils
 if __name__ == "__main__":
@@ -29,12 +31,60 @@
 
 import unittest
 import pkg.actions as action
+import pkg.actions.generic as generic
+import pkg.actions.signature as signature
+import pkg.client.api_errors as api_errors
 
 import os
 import sys
 
 class TestActions(pkg5unittest.Pkg5TestCase):
 
+
+        act_strings = [
+            "set name=foo value=foo",
+            "set name=foo value=\"\"",
+            "set name=foo value=f'o'o",
+            "set name=foo value='f\"o \"o'",
+            "set name=foo value='b\"a \"r' value='f\"o \"o'",
+            "set name=foo value=\"f'o 'o\"",
+            "set name=foo value=\"b'a 'r\" value=\"f'o 'o\"",
+            "set name=foo value='f\"o \\' \"o'",
+            "set name=foo value='b\"a \\' \"r' value='f\"o \\' \"o'",
+            "set name=foo value='\"foo\"'",
+            "set name=foo value='\"bar\"'value='\"foo\"'",
+            "set name=foo value=\"'foo'\"",
+            "set name=foo value=\"'bar'\" value=\"'foo'\"",
+            "set name=foo value='\"fo\\\'o\"'",
+            "set name=foo value='\"ba\\\'r\"' value='\"fo\\\'o\"'",
+            "set name=foo value=\"'fo\\\"o'\"",
+            "set name=foo value=\"'ba\\\"r'\" value=\"'fo\\\"o'\"",
+            'set name=foo value=ab value="" value=c',
+            "file 12345 name=foo path=/tmp/foo",
+            "file 12345 name=foo attr=bar path=/tmp/foo",
+            "file 12345 name=foo attr=bar attr=bar path=/tmp/foo",
+            "file 12345 name=foo     attr=bar path=/tmp/foo",
+            "file 12345 name=foo     path=/tmp/foo attr=bar   ",
+            "file 12345 name=foo     path=/tmp/foo attr=bar   ",
+            "file 12345 name=\"foo bar\"  attr=\"bar baz\" path=/tmp/foo",
+            "file 12345 name=\"foo bar\"  attr=\"bar baz\" path=/tmp/foo",
+            "file 12345 name=foo  value=barbaz path=/tmp/foo",
+            "file 12345 name=foo  value=\"bar baz\" path=/tmp/foo",
+            "file 12345 name=\"foo bar\"  value=baz path=/tmp/foo",
+            "file 12345 name=foo  value=barbazquux path=/tmp/foo",
+            "file 12345 name=foo  value=\"bar baz quux\" path=/tmp/foo",
+            "file 12345 name=\"foo bar baz\"  value=quux path=/tmp/foo",
+            "file 12345 name=\"foo\"  value=\"bar\" path=/tmp/foo",
+            "file 12345 name=foo  value=\"bar\" path=/tmp/foo",
+            "file 12345 name=\"foo\"  value=bar path=/tmp/foo",
+            "file 12345 name='foo' value=bar path=/tmp/foo",
+            "file 12345 name='f\"o\"o' value=bar path=/tmp/foo",
+            "file 12345 name='f\\'o\\'o' value=bar path=/tmp/foo",
+            "file 12345 name=foo\tvalue=bar path=/tmp/foo",
+            "driver alias=pci1234,56 alias=pci4567,89 class=scsi name=lsimega",
+            "signature 12345 algorithm=foo",
+        ]
+        
         def assertAttributeValue(self, action, attr, value):
                 attrs = action.attrs[attr]
 
@@ -80,7 +130,7 @@
                 action.fromstr("file 12345 name=foo  value=\"bar\" path=/tmp/foo")
                 action.fromstr("file 12345 name=\"foo\"  value=bar path=/tmp/foo")
 
-                action.fromstr("signature 12345 name=foo  value=bar")
+                action.fromstr("signature 12345 algorithm=foo")
 
                 # Single quoted value
                 a = action.fromstr("file 12345 name='foo' value=bar path=/tmp/foo")
@@ -194,51 +244,7 @@
                 that we can feed the resulting string back into fromstr() and
                 get an identical action back."""
 
-                strings = [
-                    "set name=foo value=foo",
-                    "set name=foo value=\"\"",
-                    "set name=foo value=f'o'o",
-                    "set name=foo value='f\"o \"o'",
-                    "set name=foo value='b\"a \"r' value='f\"o \"o'",
-                    "set name=foo value=\"f'o 'o\"",
-                    "set name=foo value=\"b'a 'r\" value=\"f'o 'o\"",
-                    "set name=foo value='f\"o \\' \"o'",
-                    "set name=foo value='b\"a \\' \"r' value='f\"o \\' \"o'",
-                    "set name=foo value='\"foo\"'",
-                    "set name=foo value='\"bar\"'value='\"foo\"'",
-                    "set name=foo value=\"'foo'\"",
-                    "set name=foo value=\"'bar'\" value=\"'foo'\"",
-                    "set name=foo value='\"fo\\\'o\"'",
-                    "set name=foo value='\"ba\\\'r\"' value='\"fo\\\'o\"'",
-                    "set name=foo value=\"'fo\\\"o'\"",
-                    "set name=foo value=\"'ba\\\"r'\" value=\"'fo\\\"o'\"",
-                    'set name=foo value=ab value="" value=c',
-                    "file 12345 name=foo path=/tmp/foo",
-                    "file 12345 name=foo attr=bar path=/tmp/foo",
-                    "file 12345 name=foo attr=bar attr=bar path=/tmp/foo",
-                    "file 12345 name=foo     attr=bar path=/tmp/foo",
-                    "file 12345 name=foo     path=/tmp/foo attr=bar   ",
-                    "file 12345 name=foo     path=/tmp/foo attr=bar   ",
-                    "file 12345 name=\"foo bar\"  attr=\"bar baz\" path=/tmp/foo",
-                    "file 12345 name=\"foo bar\"  attr=\"bar baz\" path=/tmp/foo",
-                    "file 12345 name=foo  value=barbaz path=/tmp/foo",
-                    "file 12345 name=foo  value=\"bar baz\" path=/tmp/foo",
-                    "file 12345 name=\"foo bar\"  value=baz path=/tmp/foo",
-                    "file 12345 name=foo  value=barbazquux path=/tmp/foo",
-                    "file 12345 name=foo  value=\"bar baz quux\" path=/tmp/foo",
-                    "file 12345 name=\"foo bar baz\"  value=quux path=/tmp/foo",
-                    "file 12345 name=\"foo\"  value=\"bar\" path=/tmp/foo",
-                    "file 12345 name=foo  value=\"bar\" path=/tmp/foo",
-                    "file 12345 name=\"foo\"  value=bar path=/tmp/foo",
-                    "file 12345 name='foo' value=bar path=/tmp/foo",
-                    "file 12345 name='f\"o\"o' value=bar path=/tmp/foo",
-                    "file 12345 name='f\\'o\\'o' value=bar path=/tmp/foo",
-                    "file 12345 name=foo\tvalue=bar path=/tmp/foo",
-                    "driver alias=pci1234,56 alias=pci4567,89 class=scsi name=lsimega",
-                    "signature foo=v bar=y",
-                ]
-
-                for s in strings:
+                for s in self.act_strings:
                         self.debug(str(s))
                         a = action.fromstr(s)
                         s2 = str(a)
@@ -248,6 +254,44 @@
                                 self.debug("a2 " + str(a2))
                                 self.assert_(not a.different(a2))
 
+        def test_action_sig_str(self):
+                sig_act = action.fromstr(
+                    "signature 54321 algorithm=baz")
+                for s in self.act_strings:
+                        # action.sig_str should return an identical string each
+                        # time it's called.  Also, parsing the result of
+                        # sig_str so produce the same action.
+                        a = action.fromstr(s)
+                        s2 = a.sig_str(sig_act, generic.Action.sig_version)
+                        s3 = a.sig_str(sig_act, generic.Action.sig_version)
+                        # If s2 is None, then s was a different signature
+                        # action, so there is no output to parse.
+                        if s2 is None:
+                                continue
+                        self.assertEqual(s2, s3)
+                        a2 = action.fromstr(s2)
+                        if a.different(a2):
+                                self.debug("a1 " + str(a))
+                                self.debug("a2 " + str(a2))
+                                self.assert_(not a.different(a2))
+                        s4 = a.sig_str(sig_act, generic.Action.sig_version)
+                        self.assertEqual(s2, s4)
+                # Test that using an unknown sig_version triggers the
+                # appropriate exception.
+                self.assertRaises(api_errors.UnsupportedSignatureVersion,
+                    sig_act.sig_str, sig_act, -1)
+                a = action.fromstr(self.act_strings[0])
+                self.assertRaises(api_errors.UnsupportedSignatureVersion,
+                    a.sig_str, sig_act, -1)
+                # Test that the sig_str of a signature action other than the
+                # argument action is None.
+                sig_act2 = action.fromstr(
+                    "signature 98765 algorithm=foobar")
+                self.assert_(sig_act.sig_str(sig_act2,
+                    generic.Action.sig_version) is None)
+                self.assert_(sig_act2.sig_str(sig_act,
+                    generic.Action.sig_version) is None)
+
         def assertMalformed(self, text):
                 malformed = False
 
@@ -328,6 +372,10 @@
                 self.assertMalformed("""legacy arch=i386 category=GNOME2,application,JDSosol desc="XScreenSaver is two things: it is both a large collection of screen savers (distributed in the "hacks" packages) and it is also the framework for blanking and locking the screen (this package)." hotline="Please contact your local service provider" name="XScreenSaver is two things: it is both a large collection of screen savers (distributed in the "hacks" packages) and it is also the framework for blanking and locking the screen (this package)." pkg=SUNWxscreensaver vendor="XScreenSaver Community" version=5.11,REV=110.0.4.2010.07.08.22.18""")
                 self.assertMalformed("""legacy arch=i386 category=GNOME2,application,JDSosol desc="XScreenSaver is two things: it is both a large collection of screen savers (distributed in the "hacks" packages) and it is also the framework for blanking and locking the screen (this package)." hotline="Please contact your local service provider" name="XScreenSaver is two things: it is both a large collection of screen savers (distributed in the "hacks" packages) and it is also the framework for blanking and locking the screen (this package)." pkg=SUNWxscreensaver-l10n vendor="XScreenSaver Community" version=5.11,REV=110.0.4.2010.07.08.22.18""")
 
+                # Missing required attribute 'algorithm'.
+                self.assertRaises(action.InvalidActionError, action.fromstr,
+                    "signature 12345 pkg.cert=bar")
+
         def test_validate(self):
                 """Verify that action validate() works as expected; currently
                 only used during publication or action execution failure."""
--- a/src/tests/api/t_api.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/tests/api/t_api.py	Mon Aug 16 16:48:50 2010 -0700
@@ -104,6 +104,7 @@
   "publishers": [
     {
       "alias": "cat", 
+      "intermediate_certs": [], 
       "name": "bobcat", 
       "packages": [
         "pkg:/[email protected],5.11-0"
@@ -124,7 +125,8 @@
           "registration_uri": "", 
           "related_uris": []
         }
-      ]
+      ], 
+      "signing_ca_certs": []
     }
   ], 
   "version": 1
--- a/src/tests/api/t_api_search.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/tests/api/t_api_search.py	Mon Aug 16 16:48:50 2010 -0700
@@ -64,7 +64,6 @@
             add set name=com.sun.service.info_url value=http://service.opensolaris.com/xml/pkg/[email protected],5.11-1:20080514I120000Z
             add set name=description value='FOOO bAr O OO OOO' value="whee fun"
             add set name='weirdness' value='] [ * ?'
-            add signature pkg.sig_bit1=sig_bit_val1 pkg.sig_bit2=sig_bit_val2
             add set name=opensolaris.smf.fmri value=svc:/milestone/multi-user-server:default
             close """
 
--- a/src/tests/api/t_file_manager.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/tests/api/t_file_manager.py	Mon Aug 16 16:48:50 2010 -0700
@@ -20,8 +20,9 @@
 # CDDL HEADER END
 #
 
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+#
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+#
 
 import testutils
 if __name__ == "__main__":
@@ -47,7 +48,7 @@
         def touch_old_file(self, s, data=None):
                 if data is None:
                         data = s
-                p = os.path.join(self.test_root, self.old_hash(s))
+                p = os.path.join(self.base_dir, self.old_hash(s))
                 if not os.path.exists(os.path.dirname(p)):
                         os.makedirs(os.path.dirname(p))
                 fh = open(p, "wb")
@@ -87,6 +88,13 @@
                     ["remove", unmoved], unmoved)
                 self.assert_(os.path.isfile(p))
 
+        def setUp(self):
+                pkg5unittest.Pkg5TestCase.setUp(self)
+                # Move base_dir down one level so that the tests don't assume
+                # sole control over the contents of self.test_root.
+                self.base_dir = os.path.join(self.test_root, "fm")
+                os.mkdir(self.base_dir)
+
         def test_1(self):
                 """Verify base functionality works as expected."""
 
@@ -99,8 +107,8 @@
 
                 # Test that a read only FileManager won't modify the file
                 # system.
-                fm = file_manager.FileManager(self.test_root, readonly=True)
-                self.assertEqual(os.listdir(self.test_root), [])
+                fm = file_manager.FileManager(self.base_dir, readonly=True)
+                self.assertEqual(os.listdir(self.base_dir), [])
 
                 unmoved = "4b7c923af3a047d4685a39ad7bc9b0382ccde671"
 
@@ -111,7 +119,7 @@
                     set([unmoved]))
 
                 # Test a FileManager that can write to the file system.
-                fm = file_manager.FileManager(self.test_root, False)
+                fm = file_manager.FileManager(self.base_dir, False)
 
                 hash1 = "584b6ab7d7eb446938a02e57101c3a2fecbfb3cb"
                 hash2 = "584b6ab7d7eb446938a02e57101c3a2fecbfb3cc"
@@ -132,7 +140,7 @@
                 self.assert_(os.path.isfile(p1))
                 self.assert_(os.path.isdir(os.path.dirname(p1)))
                 self.assertEqual(fm.lookup(hash1),
-                    os.path.join(self.test_root, l.lookup(hash1)))
+                    os.path.join(self.base_dir, l.lookup(hash1)))
                 self.assert_(not os.path.exists(p1))
                 self.assert_(not os.path.exists(os.path.dirname(p1)))
                 fm.remove(hash1)
@@ -148,7 +156,7 @@
                 self.assert_(os.path.isfile(p1))
                 self.assert_(os.path.isdir(os.path.dirname(p1)))
                 self.assertEqual(fm.lookup(hash1),
-                    os.path.join(self.test_root, l.lookup(hash1)))
+                    os.path.join(self.base_dir, l.lookup(hash1)))
                 self.assert_(not os.path.exists(p1))
                 self.assert_(os.path.exists(os.path.dirname(p1)))
                 fm.remove(hash2)
@@ -187,7 +195,7 @@
 
                 # Test that walking with a different set of layouts works as
                 # expected.
-                fm2 = file_manager.FileManager(self.test_root, readonly=True,
+                fm2 = file_manager.FileManager(self.base_dir, readonly=True,
                     layouts=[layout.get_preferred_layout()])
 
                 fs = set([hash1, hash4, hash3])
@@ -195,13 +203,13 @@
                         for i in fm2.walk():
                                 fs.remove(i)
                 except file_manager.UnrecognizedFilePaths, e:
-                        self.assertEqual(e.fps, [p[len(self.test_root) + 1:]])
+                        self.assertEqual(e.fps, [p[len(self.base_dir) + 1:]])
                 self.assertEqual(fs, set())
 
                 # Test removing a file works and removes the containing
                 # directory and that remove removes all instances of a hash
                 # from the file manager.
-                hash3_loc = os.path.join(self.test_root, l.lookup(hash3))
+                hash3_loc = os.path.join(self.base_dir, l.lookup(hash3))
                 v0_hash3_loc = self.touch_old_file(hash3)
 
                 self.assert_(os.path.isfile(hash3_loc))
@@ -214,7 +222,7 @@
                 self.assert_(not os.path.exists(os.path.dirname(v0_hash3_loc)))
                 self.assert_(os.path.isfile(fm.lookup(hash1)))
 
-                rh2_fd, raw_hash_2_loc = tempfile.mkstemp(dir=self.test_root)
+                rh2_fd, raw_hash_2_loc = tempfile.mkstemp(dir=self.base_dir)
                 rh2_fh = os.fdopen(rh2_fd, "w")
                 rh2_fh.write(hash2)
                 rh2_fh.close()
@@ -260,25 +268,25 @@
                         self.touch_old_file(fhash)
 
                 # Migrate it to the v1 layout.
-                fm = file_manager.FileManager(self.test_root, False)
+                fm = file_manager.FileManager(self.base_dir, False)
                 for fhash in fm.walk():
                         self.assertEqual(fm.lookup(fhash),
-                            os.path.join(self.test_root, l1.lookup(fhash)))
+                            os.path.join(self.base_dir, l1.lookup(fhash)))
 
                 # After migration verify that no v0 parent directories remain.
                 for fhash in fm.walk():
                         self.assertFalse(os.path.exists(os.path.dirname(
-                            os.path.join(self.test_root, l0.lookup(fhash)))))
+                            os.path.join(self.base_dir, l0.lookup(fhash)))))
 
                 # Re-create the FileManager using v0 as the preferred layout.
-                fm = file_manager.FileManager(self.test_root, False,
+                fm = file_manager.FileManager(self.base_dir, False,
                     layouts=[l0, l1])
 
                 # Test that looking up a file stored under the v1 layout is
                 # correctly moved to the v0 layout.
                 for fhash in fm.walk():
                         self.assertEqual(fm.lookup(fhash),
-                            os.path.join(self.test_root, l0.lookup(fhash)))
+                            os.path.join(self.base_dir, l0.lookup(fhash)))
 
         def test_3_replace(self):
                 """Verify that insert will replace an existing file even though
@@ -298,10 +306,10 @@
 
                 # Migrate it to the v1 layout and verify that each
                 # file contains the expected data.
-                fm = file_manager.FileManager(self.test_root, False)
+                fm = file_manager.FileManager(self.base_dir, False)
                 for fhash in fm.walk():
                         loc = fm.lookup(fhash)
-                        self.assertEqual(loc, os.path.join(self.test_root,
+                        self.assertEqual(loc, os.path.join(self.base_dir,
                             l1.lookup(fhash)))
 
                         f = open(loc, "rb")
@@ -311,10 +319,10 @@
                 # Now replace each file using the old hashnames and verify
                 # that the each contains the expected data.
                 for fhash in fm.walk():
-                        loc = os.path.join(self.test_root, l1.lookup(fhash))
+                        loc = os.path.join(self.base_dir, l1.lookup(fhash))
                         self.assertTrue(os.path.exists(loc))
 
-                        npath = os.path.join(self.test_root, "new-%s" % fhash)
+                        npath = os.path.join(self.base_dir, "new-%s" % fhash)
                         nfile = open(npath, "wb")
                         nfile.write("new-%s" % fhash)
                         nfile.close()
--- a/src/tests/api/t_p5i.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/tests/api/t_p5i.py	Mon Aug 16 16:48:50 2010 -0700
@@ -21,8 +21,7 @@
 #
 
 #
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 import testutils
@@ -61,6 +60,7 @@
   "publishers": [
     {
       "alias": "cat", 
+      "intermediate_certs": [], 
       "name": "bobcat", 
       "packages": [
         "pkg:/[email protected],5.11-0"
@@ -81,7 +81,8 @@
           "registration_uri": "", 
           "related_uris": []
         }
-      ]
+      ], 
+      "signing_ca_certs": []
     }
   ], 
   "version": 1
@@ -133,7 +134,7 @@
                 # Verify that output matches expected output.
                 fobj.seek(0)
                 output = fobj.read()
-                self.assertEqual(output, self.p5i_bobcat)
+                self.assertPrettyEqual(output, self.p5i_bobcat)
 
                 def validate_results(results):
                         # First result should be 'bobcat' publisher and its
@@ -225,9 +226,11 @@
   "publishers": [
     {
       "alias": "cat", 
+      "intermediate_certs": [], 
       "name": "bobcat", 
       "packages": [], 
-      "repositories": []
+      "repositories": [], 
+      "signing_ca_certs": []
     }
   ], 
   "version": 1
@@ -256,6 +259,7 @@
   "publishers": [
     {
       "alias": "cat", 
+      "intermediate_certs": [], 
       "name": "bobcat", 
       "packages": [], 
       "repositories": [
@@ -272,7 +276,8 @@
           "registration_uri": "", 
           "related_uris": []
         }
-      ]
+      ], 
+      "signing_ca_certs": []
     }
   ], 
   "version": 1
--- a/src/tests/api/t_publisher.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/tests/api/t_publisher.py	Mon Aug 16 16:48:50 2010 -0700
@@ -21,10 +21,10 @@
 #
 
 #
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
+
 import testutils
 if __name__ == "__main__":
         testutils.setup_environment("../../../proto")
@@ -431,6 +431,39 @@
                                 self.assertRaises(api_errors.UnknownRepository,
                                     pobj.get_repository, name=r.name)
 
+                # Verify that adding, removing, and unsetting ca certs works
+                # as expected.
+                pobj.create_meta_root()
+                self.pub_cas_dir = os.path.join(self.ro_data_root,
+                    "signing_certs", "produced", "publisher_cas")
+                ca_path = os.path.join(self.pub_cas_dir, "pubCA1_ta3_cert.pem")
+                with open(ca_path, "rb") as fh:
+                        ca_data = fh.read()
+                hsh = self.calc_file_hash(ca_path)
+                # Test revoking a ca cert.
+                pobj.revoke_ca_cert(hsh)
+                self.assert_(hsh in pobj.revoked_ca_certs)
+                # Test moving from revoked to approved
+                pobj.approve_ca_cert(ca_data, manual=True)
+                self.assert_(hsh not in pobj.revoked_ca_certs)
+                self.assert_(hsh in pobj.approved_ca_certs)
+                self.assert_(hsh in pobj.signing_ca_certs)
+                # Test unsetting from approved
+                pobj.unset_ca_cert(hsh)
+                self.assert_(hsh not in pobj.revoked_ca_certs)
+                self.assert_(hsh not in pobj.approved_ca_certs)
+                # Test approving a ca cert
+                pobj.approve_ca_cert(ca_data, manual=True)
+                self.assert_(hsh in pobj.approved_ca_certs)
+                # Test moving from approved to revoked
+                pobj.revoke_ca_cert(hsh)
+                self.assert_(hsh in pobj.revoked_ca_certs)
+                self.assert_(hsh not in pobj.approved_ca_certs)
+                # Test moving from revoked to unset
+                pobj.unset_ca_cert(hsh)
+                self.assert_(hsh not in pobj.revoked_ca_certs)
+                self.assert_(hsh not in pobj.approved_ca_certs)
+
 
 if __name__ == "__main__":
         unittest.main()
--- a/src/tests/cli/t_pkg_depotd.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/tests/cli/t_pkg_depotd.py	Mon Aug 16 16:48:50 2010 -0700
@@ -381,6 +381,27 @@
                 self.dc.set_socket_path(None)
                 os.unlink(spath)
 
+        def test_append_reopen(self):
+                """Test that if a depot has a partially finished append
+                transaction, that it reopens it correctly."""
+
+                durl = self.dc.get_depot_url()
+                plist = self.pkgsend_bulk(durl, self.foo10)
+                self.pkgsend(durl, "append %s" % plist[0])
+                self.dc.stop()
+                self.dc.start()
+                self.pkgsend(durl, "close")
+
+        def test_nonsig_append(self):
+                """Test that sending a non-signature action to an append
+                transaction results in an error."""
+
+                durl = self.dc.get_depot_url()
+                plist = self.pkgsend_bulk(durl, self.foo10)
+                self.pkgsend(durl, "append %s" % plist[0])
+                self.pkgsend(durl, "add dir path=tmp/foo mode=0755 "
+                    "owner=root group=bin", exit=1)
+
 
 class TestDepotController(pkg5unittest.CliTestCase):
 
--- a/src/tests/cli/t_pkg_image_create.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/tests/cli/t_pkg_image_create.py	Mon Aug 16 16:48:50 2010 -0700
@@ -73,6 +73,12 @@
                 self.pkg("image-create --bozo", exit=2)
                 self.pkg("image-create", exit=2)
 
+                self.pkg("image-create --set-property foo -p test1=%s %s" %
+                    (self.rurl1, self.test_root), exit=2)
+                self.pkg("image-create --set-property foo=bar --set-property "
+                    "foo=baz -p test1=%s %s" % (self.rurl1, self.test_root),
+                    exit=2)
+
         def __add_install_file(self, imgdir, fmri):
                 """Take an image path and fmri. Write a file to disk that
                 indicates that the package named by the fmri has been
@@ -133,7 +139,8 @@
                 # non-empty directory exists
                 p = os.path.join(self.get_img_path(), "3588_2_image")
                 os.mkdir(p)
-                self.cmdline_run("touch %s/%s" % (p, "somefile"))
+                self.cmdline_run("touch %s/%s" % (p, "somefile"),
+                    coverage=False)
                 self.pkg("image-create -p test1=%s %s" % (self.rurl1, p),
                     exit=1)
                 self.pkg("image-create -f -p test1=%s %s" % (self.rurl1, p))
--- a/src/tests/cli/t_pkg_install.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/tests/cli/t_pkg_install.py	Mon Aug 16 16:48:50 2010 -0700
@@ -53,7 +53,6 @@
             open [email protected],5.11-0
             add dir mode=0755 owner=root group=bin path=/lib
             add file tmp/libc.so.1 mode=0555 owner=root group=bin path=/lib/libc.so.1 timestamp="20080731T024051Z"
-            add signature pkg.sig_bit1=sig_bit_val1 pkg.sig_bit2=sig_bit_val2
             close """
         foo11_timestamp = 1217472051
 
--- a/src/tests/cli/t_pkg_property.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/tests/cli/t_pkg_property.py	Mon Aug 16 16:48:50 2010 -0700
@@ -61,6 +61,28 @@
                 self.pkg("unset-property description", exit=1)
                 self.pkg("unset-property", exit=2)
 
+                self.pkg("set-property signature-policy verify")
+                self.pkg("set-property signature-policy verify foo", exit=1)
+                self.pkg("set-property signature-policy vrify", exit=1)
+                self.pkg("set-property signature-policy require-names", exit=1)
+                self.pkg("set-property signature-policy require-names foo")
+
+                self.pkg("add-property-value signature-policy verify", exit=1)
+                self.pkg("add-property-value signature-required-names foo")
+                self.pkg("add-property-value signature-required-names bar")
+                self.pkg("remove-property-value signature-required-names foo")
+                self.pkg("remove-property-value signature-required-names baz",
+                    exit=1)
+                self.pkg("add-property-value foo", exit=2)
+                self.pkg("remove-property-value foo", exit=2)
+                self.pkg("set-property foo", exit=2)
+                self.pkg("set-property foo bar")
+                self.pkg("remove-property-value foo bar", exit=1)
+                self.pkg("set-property", exit=2)
+
+                self.pkg("set-property trust-anchor-directory %s %s" %
+                    (self.test_root, self.test_root), exit=1)
+
         def test_missing_permssions(self):
                 """Bug 2393"""
 
--- a/src/tests/cli/t_pkg_publisher.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/tests/cli/t_pkg_publisher.py	Mon Aug 16 16:48:50 2010 -0700
@@ -172,6 +172,32 @@
                 self.pkg('set-publisher --no-refresh -k "" test1')
                 self.pkg('publisher -H test1 | grep "SSL Key: None"')
 
+                self.pkg("set-publisher --set-property foo test1", exit=2)
+                self.pkg("set-publisher --set-property foo=bar --set-property "
+                    "foo=baz test1", exit=2)
+                self.pkg("set-publisher --add-property-value foo test1", exit=2)
+                self.pkg("set-publisher --remove-property-value foo test1",
+                    exit=2)
+                self.pkg("set-publisher --approve-ca-cert /shouldnotexist/foo "
+                    "test1", exit=1)
+
+                key_fh, key_path = tempfile.mkstemp()
+                self.pkg("set-publisher --approve-ca-cert %s test1" % key_path,
+                    exit=1, su_wrap=True)
+                os.close(key_fh)
+                os.unlink(key_path)
+
+                self.pkg("set-publisher --no-refresh --set-property "
+                    "signature-policy=ignore test1")
+                self.pkg("set-publisher --no-refresh --set-property foo=bar "
+                    "test1")
+                self.pkg("set-publisher --no-refresh  --remove-property-value "
+                    "foo=baz test1", exit=1)
+                self.pkg("set-publisher --no-refresh  --set-property "
+                    "signature-policy=require-names test1", exit=1)
+                self.pkg("set-publisher --no-refresh --remove-property-value "
+                    "bar=baz test1", exit=1)
+
         def test_publisher_validation(self):
                 """Verify that we catch poorly formed auth prefixes and URL"""
 
@@ -293,6 +319,57 @@
                     exit=1)
                 self.pkg("unset-publisher test1")
 
+        def test_old_publisher_ca_certs(self):
+                """Check that approving and revoking CA certs is reflected in
+                the output of pkg publisher and that setting the CA certs when
+                setting an existing publisher works correctly."""
+
+                cert_dir = os.path.join(self.ro_data_root,
+                    "signing_certs", "produced", "publisher_cas")
+
+                app1 = os.path.join(cert_dir, "pubCA1_ta1_cert.pem")
+                app2 = os.path.join(cert_dir, "pubCA1_ta3_cert.pem")
+                rev1 = os.path.join(cert_dir, "pubCA1_ta4_cert.pem")
+                rev2 = os.path.join(cert_dir, "pubCA1_ta5_cert.pem")
+                app1_h = self.calc_file_hash(app1)
+                app2_h = self.calc_file_hash(app2)
+                rev1_h = self.calc_file_hash(rev1)
+                rev2_h = self.calc_file_hash(rev2)
+                self.image_create(self.rurl)
+                self.pkg("set-publisher "
+                    "--approve-ca-cert %s "
+                    "--approve-ca-cert %s --revoke-ca-cert %s "
+                    "--revoke-ca-cert %s test " % (
+                    app1, app2, rev1_h, rev2_h))
+                self.pkg("publisher test")
+                r1 = "         Approved CAs: %s"
+                r2 = "                     : %s"
+                r3 = "          Revoked CAs: %s"
+                ls = self.output.splitlines()
+                found_approved = False
+                found_revoked = False
+                for i in range(0, len(ls)):
+                        if "Approved CAs" in ls[i]:
+                                found_approved = True
+                                if not ((r1 % app1_h == ls[i] and
+                                    r2 % app2_h == ls[i+1]) or \
+                                    (r1 % app2_h == ls[i] and
+                                    r2 % app1_h == ls[i+1])):
+                                        raise RuntimeError("Expected to see "
+                                            "%s and %s as approved certs. "
+                                            "Output was:\n%s" % (app1_h,
+                                            app2_h, self.output))
+                        elif "Revoked CAs" in ls[i]:
+                                found_approved = True
+                                if not ((r3 % rev1_h == ls[i] and
+                                    r2 % rev2_h == ls[i+1]) or \
+                                    (r3 % rev2_h == ls[i] and
+                                    r2 % rev1_h == ls[i+1])):
+                                        raise RuntimeError("Expected to see "
+                                            "%s and %s as revoked certs. "
+                                            "Output was:\n%s" % (rev1_h,
+                                            rev2_h, self.output))
+
 
 class TestPkgPublisherMany(pkg5unittest.ManyDepotTestCase):
         # Only start/stop the depot once (instead of for every test)
@@ -654,6 +731,115 @@
                 self.pkg("set-publisher --search-before=test3 test3", exit=1)
                 self.pkg("set-publisher --search-after=test3 test3", exit=1)
 
+class TestPkgPublisherCACerts(pkg5unittest.ManyDepotTestCase):
+
+        def setUp(self):
+                # This test suite needs actual depots.
+                pkg5unittest.ManyDepotTestCase.setUp(self, ["test1", "test2"])
+
+                self.rurl1 = self.dcs[1].get_repo_url()
+                self.rurl2 = self.dcs[2].get_repo_url()
+                self.image_create(self.rurl1, prefix="test1")
+                
+        def test_new_publisher_ca_certs_with_refresh(self):
+                """Check that approving and revoking CA certs is reflected in
+                the output of pkg publisher and that setting the CA certs when
+                setting a new publisher works correctly."""
+
+                cert_dir = os.path.join(self.ro_data_root,
+                    "signing_certs", "produced", "publisher_cas")
+
+                app1 = os.path.join(cert_dir, "pubCA1_ta1_cert.pem")
+                app2 = os.path.join(cert_dir, "pubCA1_ta3_cert.pem")
+                rev1 = os.path.join(cert_dir, "pubCA1_ta4_cert.pem")
+                rev2 = os.path.join(cert_dir, "pubCA1_ta5_cert.pem")
+                app1_h = self.calc_file_hash(app1)
+                app2_h = self.calc_file_hash(app2)
+                rev1_h = self.calc_file_hash(rev1)
+                rev2_h = self.calc_file_hash(rev2)
+                self.pkg("set-publisher -O %s "
+                    "--approve-ca-cert %s "
+                    "--approve-ca-cert %s --revoke-ca-cert %s "
+                    "--revoke-ca-cert %s test2 " % (self.dcs[2].get_repo_url(),
+                    app1, app2, rev1_h, rev2_h))
+                self.pkg("publisher test2")
+                r1 = "         Approved CAs: %s"
+                r2 = "                     : %s"
+                r3 = "          Revoked CAs: %s"
+                ls = self.output.splitlines()
+                found_approved = False
+                found_revoked = False
+                for i in range(0, len(ls)):
+                        if "Approved CAs" in ls[i]:
+                                found_approved = True
+                                if not ((r1 % app1_h == ls[i] and
+                                    r2 % app2_h == ls[i+1]) or \
+                                    (r1 % app2_h == ls[i] and
+                                    r2 % app1_h == ls[i+1])):
+                                        raise RuntimeError("Expected to see "
+                                            "%s and %s as approved certs. "
+                                            "Output was:\n%s" % (app1_h,
+                                            app2_h, self.output))
+                        elif "Revoked CAs" in ls[i]:
+                                found_approved = True
+                                if not ((r3 % rev1_h == ls[i] and
+                                    r2 % rev2_h == ls[i+1]) or \
+                                    (r3 % rev2_h == ls[i] and
+                                    r2 % rev1_h == ls[i+1])):
+                                        raise RuntimeError("Expected to see "
+                                            "%s and %s as revoked certs. "
+                                            "Output was:\n%s" % (rev1_h,
+                                            rev2_h, self.output))
+
+        def test_new_publisher_ca_certs_no_refresh(self):
+                """Check that approving and revoking CA certs is reflected in
+                the output of pkg publisher and that setting the CA certs when
+                setting a new publisher works correctly."""
+
+                cert_dir = os.path.join(self.ro_data_root,
+                    "signing_certs", "produced", "publisher_cas")
+
+                app1 = os.path.join(cert_dir, "pubCA1_ta1_cert.pem")
+                app2 = os.path.join(cert_dir, "pubCA1_ta3_cert.pem")
+                rev1 = os.path.join(cert_dir, "pubCA1_ta4_cert.pem")
+                rev2 = os.path.join(cert_dir, "pubCA1_ta5_cert.pem")
+                app1_h = self.calc_file_hash(app1)
+                app2_h = self.calc_file_hash(app2)
+                rev1_h = self.calc_file_hash(rev1)
+                rev2_h = self.calc_file_hash(rev2)
+                self.pkg("set-publisher -O %s --no-refresh "
+                    "--approve-ca-cert %s "
+                    "--approve-ca-cert %s --revoke-ca-cert %s "
+                    "--revoke-ca-cert %s test2 " % (self.dcs[2].get_repo_url(),
+                    app1, app2, rev1_h, rev2_h))
+                self.pkg("publisher test2")
+                r1 = "         Approved CAs: %s"
+                r2 = "                     : %s"
+                r3 = "          Revoked CAs: %s"
+                ls = self.output.splitlines()
+                found_approved = False
+                found_revoked = False
+                for i in range(0, len(ls)):
+                        if "Approved CAs" in ls[i]:
+                                found_approved = True
+                                if not ((r1 % app1_h == ls[i] and
+                                    r2 % app2_h == ls[i+1]) or \
+                                    (r1 % app2_h == ls[i] and
+                                    r2 % app1_h == ls[i+1])):
+                                        raise RuntimeError("Expected to see "
+                                            "%s and %s as approved certs. "
+                                            "Output was:\n%s" % (app1_h,
+                                            app2_h, self.output))
+                        elif "Revoked CAs" in ls[i]:
+                                found_approved = True
+                                if not ((r3 % rev1_h == ls[i] and
+                                    r2 % rev2_h == ls[i+1]) or \
+                                    (r3 % rev2_h == ls[i] and
+                                    r2 % rev1_h == ls[i+1])):
+                                        raise RuntimeError("Expected to see "
+                                            "%s and %s as revoked certs. "
+                                            "Output was:\n%s" % (rev1_h,
+                                            rev2_h, self.output))
 
 if __name__ == "__main__":
         unittest.main()
--- a/src/tests/cli/t_pkg_search.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/tests/cli/t_pkg_search.py	Mon Aug 16 16:48:50 2010 -0700
@@ -58,7 +58,6 @@
             add set name=com.sun.service.info_url value=http://service.opensolaris.com/xml/pkg/[email protected],5.11-1:20080514I120000Z
             add set description='FOOO bAr O OO OOO'
             add set name='weirdness' value='] [ * ?'
-            add signature pkg.sig_bit1=sig_bit_val1 pkg.sig_bit2=sig_bit_val2
             close """
 
         example_pkg11 = """
--- a/src/tests/cli/t_pkgfmt.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/tests/cli/t_pkgfmt.py	Mon Aug 16 16:48:50 2010 -0700
@@ -956,8 +956,10 @@
                 # remove backslashes in place
                 self.pkgfmt("-u < %s > %s" % (source_file, mod_file))
                 # sort into alternate order and format
-                self.cmdline_run("/usr/bin/sort -o %s %s" % (mod_file, mod_file)) 
+                self.cmdline_run("/usr/bin/sort -o %s %s" %
+                    (mod_file, mod_file), coverage=False)
                 self.pkgfmt("%s" % mod_file)
                 self.pkgfmt("%s" % source_file)
-                self.cmdline_run("/usr/bin/diff %s %s" % ( source_file, mod_file))
+                self.cmdline_run("/usr/bin/diff %s %s" %
+                    (source_file, mod_file), coverage=False)
 
--- a/src/tests/cli/t_pkgmogrify.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/tests/cli/t_pkgmogrify.py	Mon Aug 16 16:48:50 2010 -0700
@@ -418,7 +418,8 @@
                 output_file = os.path.join(self.test_root, "output_file")
 
                 self.pkgmogrify([source_file], output=output_file, defines={})
-                self.cmdline_run("diff %s %s" % (source_file, output_file))
+                self.cmdline_run("diff %s %s" % (source_file, output_file),
+                    coverage=False)
                 
         def test_11(self):
                 """Test the generation of new actions."""
--- a/src/tests/cli/t_pkgrepo.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/tests/cli/t_pkgrepo.py	Mon Aug 16 16:48:50 2010 -0700
@@ -91,6 +91,13 @@
                 self.make_misc_files(["tmp/empty", "tmp/truck1",
                     "tmp/truck2"])
 
+                self.path_to_certs = os.path.join(self.ro_data_root,
+                    "signing_certs", "produced")
+                self.pub_cas_dir = os.path.join(self.path_to_certs,
+                    "publisher_cas")
+                self.inter_certs_dir = os.path.join(self.path_to_certs,
+                    "inter_certs")
+
         def test_00_base(self):
                 """Verify pkgrepo handles basic option and subcommand parsing
                 as expected.
@@ -175,27 +182,29 @@
                 # Verify full default output.
                 self.pkgrepo("-s %s property" % repo_uri)
                 expected = """\
-SECTION    PROPERTY         VALUE
-feed       description      
-feed       icon             web/_themes/pkg-block-icon.png
-feed       id               
-feed       logo             web/_themes/pkg-block-logo.png
-feed       name             package repository feed
-feed       window           24
-publisher  alias            
-publisher  prefix           
-repository collection_type  core
-repository description      
-repository detailed_url     
-repository legal_uris       []
-repository maintainer       
-repository maintainer_url   
-repository mirrors          []
-repository name             package repository
-repository origins          []
-repository refresh_seconds  14400
-repository registration_uri 
-repository related_uris     []
+SECTION    PROPERTY           VALUE
+feed       description        
+feed       icon               web/_themes/pkg-block-icon.png
+feed       id                 
+feed       logo               web/_themes/pkg-block-logo.png
+feed       name               package repository feed
+feed       window             24
+publisher  alias              
+publisher  intermediate_certs []
+publisher  prefix             
+publisher  signing_ca_certs   []
+repository collection_type    core
+repository description        
+repository detailed_url       
+repository legal_uris         []
+repository maintainer         
+repository maintainer_url     
+repository mirrors            []
+repository name               package repository
+repository origins            []
+repository refresh_seconds    14400
+repository registration_uri   
+repository related_uris       []
 """
                 self.assertEqualDiff(expected, self.output)
 
@@ -210,7 +219,9 @@
 feed\tname\tpackage repository feed
 feed\twindow\t24
 publisher\talias\t
+publisher\tintermediate_certs\t[]
 publisher\tprefix\t
+publisher\tsigning_ca_certs\t[]
 repository\tcollection_type\tcore
 repository\tdescription\t
 repository\tdetailed_url\t
@@ -235,8 +246,8 @@
                 self.pkgrepo("-s %s property publisher/prefix" %
                     repo_uri)
                 expected = """\
-SECTION    PROPERTY         VALUE
-publisher  prefix           
+SECTION    PROPERTY           VALUE
+publisher  prefix             
 """
                 self.assertEqualDiff(expected, self.output)
 
@@ -244,8 +255,8 @@
                 self.pkgrepo("-s %s property -H publisher/prefix "
                     "repository/origins" % repo_uri)
                 expected = """\
-publisher  prefix           
-repository origins          []
+publisher  prefix             
+repository origins            []
 """
                 self.assertEqualDiff(expected, self.output)
 
@@ -591,6 +602,51 @@
                 self.pkgrepo("version")
                 self.assert_(self.output.find(pkg.VERSION) != -1)
 
+        def test_07_certs(self):
+                """Verify that certificate commands work as expected."""
+
+                # Create a repository.
+                repo_path = os.path.join(self.test_root, "repo")
+                repo_uri = "file:%s" % repo_path
+                self.assert_(not os.path.exists(repo_path))
+                self.pkgrepo("-s %s create" % repo_path)
+
+                ca3_pth = os.path.join(self.pub_cas_dir, "pubCA1_ta3_cert.pem")
+                ca1_pth = os.path.join(self.pub_cas_dir, "pubCA1_ta1_cert.pem")
+                
+                self.pkgrepo("-s %s add-signing-ca-cert %s" %
+                    (repo_uri, ca3_pth))
+                self.pkgrepo("-s %s add-signing-ca-cert %s" %
+                    (repo_uri, ca1_pth))
+
+                ca1_hsh = self.calc_file_hash(ca1_pth)
+                ca3_hsh = self.calc_file_hash(ca3_pth)
+
+                self.pkgrepo("-s %s remove-signing-intermediate-cert %s" %
+                    (repo_uri, ca1_hsh))
+                self.pkgrepo("-s %s remove-signing-intermediate-cert %s" %
+                    (repo_uri, ca3_hsh))
+                self.pkgrepo("-s %s remove-signing-ca-cert %s" %
+                    (repo_uri, ca1_hsh))
+                self.pkgrepo("-s %s remove-signing-ca-cert %s" %
+                    (repo_uri, ca3_hsh))
+
+                self.pkgrepo("-s %s add-signing-intermediate-cert %s" %
+                    (repo_uri, ca3_pth))
+                self.pkgrepo("-s %s add-signing-intermediate-cert %s" %
+                    (repo_uri, ca1_pth))
+
+                ca1_hsh = self.calc_file_hash(ca1_pth)
+                ca3_hsh = self.calc_file_hash(ca3_pth)
+
+                self.pkgrepo("-s %s remove-signing-ca-cert %s" %
+                    (repo_uri, ca1_hsh))
+                self.pkgrepo("-s %s remove-signing-ca-cert %s" %
+                    (repo_uri, ca3_hsh))
+                self.pkgrepo("-s %s remove-signing-intermediate-cert %s" %
+                    (repo_uri, ca1_hsh))
+                self.pkgrepo("-s %s remove-signing-intermediate-cert %s" %
+                    (repo_uri, ca3_hsh))
 
 if __name__ == "__main__":
         unittest.main()
--- a/src/tests/cli/t_pkgsend.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/tests/cli/t_pkgsend.py	Mon Aug 16 16:48:50 2010 -0700
@@ -628,7 +628,7 @@
                 prototype.close()
 
                 self.cmdline_run("pkgmk -o -r %s -d %s -f %s" %
-                         (pkgroot, rootdir, prototypepath))
+                         (pkgroot, rootdir, prototypepath), coverage=False)
 
                 shutil.rmtree(pkgroot)
 
@@ -655,7 +655,7 @@
                 rootdir = self.test_root
                 self.create_sysv_package(rootdir)
                 self.cmdline_run("pkgtrans -s %s %s nopkg" % (rootdir,
-                        os.path.join(rootdir, "nopkg.pkg")))
+                        os.path.join(rootdir, "nopkg.pkg")), coverage=False)
 
                 url = self.dc.get_depot_url()
                 self.pkgsend(url, "open [email protected]")
@@ -934,7 +934,7 @@
         def test_bundle_dir_hardlinks(self):
                 """Verify that hardlink targeting works correctly."""
 
-                rootdir = self.test_root
+                rootdir = os.path.join(self.test_root, "bundletest")
 
                 def diffmf(src, dst):
                         added, changed, removed = src.difference(dst)
@@ -980,7 +980,7 @@
                 def do_test_one(target, links):
                         self.debug("-" * 70)
                         self.debug("Testing: %s %s" % (target, links))
-                        tpath = self.make_misc_files(target)[0]
+                        tpath = self.make_misc_files(target, rootdir)[0]
                         expected_mf = "file %s path=%s\n" % (target, target)
                         dirs = set()
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/cli/t_pkgsign.py	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,1649 @@
+#!/usr/bin/python2.6
+#
+# 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) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+import testutils
+if __name__ == "__main__":
+        testutils.setup_environment("../../../proto")
+import pkg5unittest
+
+import os
+import unittest
+import sys
+
+import pkg.actions as action
+import pkg.actions.signature as signature
+import pkg.client.api_errors as apx
+import pkg.fmri as fmri
+import pkg.portable as portable
+import M2Crypto as m2
+
+class TestPkgSign(pkg5unittest.SingleDepotTestCase):
+
+        example_pkg10 = """
+            open [email protected],5.11-0
+            add dir mode=0755 owner=root group=bin path=/bin
+            add dir mode=0755 owner=root group=bin path=/bin/example_dir
+            add dir mode=0755 owner=root group=bin path=/usr/lib/python2.4/vendor-packages/OpenSSL
+            add file tmp/example_file mode=0555 owner=root group=bin path=/bin/example_path
+            add set name=com.sun.service.incorporated_changes value="6556919 6627937"
+            add set name=com.sun.service.random_test value=42 value=79
+            add set name=com.sun.service.bug_ids value="4641790 4725245 4817791 4851433 4897491 4913776 6178339 6556919 6627937"
+            add set name=com.sun.service.keywords value="sort null -n -m -t sort 0x86 separator"
+            add set name=com.sun.service.info_url value=http://service.opensolaris.com/xml/pkg/[email protected],5.11-1:20080514I120000Z
+            add set description='FOOO bAr O OO OOO'
+            add set name='weirdness' value='] [ * ?'
+            close """
+
+        varsig_pkg = """
+            open [email protected],5.15-0
+            add set name=variant.arch value=sparc value=i386
+            add dir mode=0755 owner=root group=bin path=/bin
+            add signature tmp/example_file value=d2ff algorithm=sha256 variant.arch=i386
+            close """
+
+        var_pkg = """
+            open [email protected],5.11-0
+            add set name=variant.arch value=sparc value=i386
+            add dir mode=0755 owner=root group=bin path=/bin variant.arch=sparc
+            add dir mode=0755 owner=root group=bin path=/baz variant.arch=i386
+            close """
+
+        misc_files = ['tmp/example_file']
+
+        def setUp(self):
+                pkg5unittest.SingleDepotTestCase.setUp(self)
+                self.make_misc_files(self.misc_files)
+                self.durl1 = self.dcs[1].get_depot_url()
+                self.rurl1 = self.dcs[1].get_repo_url()
+
+                self.path_to_certs = os.path.join(self.ro_data_root,
+                    "signing_certs", "produced")
+                self.keys_dir = os.path.join(self.path_to_certs, "keys")
+                self.cs_dir = os.path.join(self.path_to_certs,
+                    "code_signing_certs")
+                self.chain_certs_dir = os.path.join(self.path_to_certs,
+                    "chain_certs")
+                self.pub_cas_dir = os.path.join(self.path_to_certs,
+                    "publisher_cas")
+                self.inter_certs_dir = os.path.join(self.path_to_certs,
+                    "inter_certs")
+                self.trust_anchor_dir = os.path.join(self.path_to_certs,
+                    "trust_anchors")
+                self.crl_dir = os.path.join(self.path_to_certs, "crl")
+
+        def test_sign_0(self):
+                """Test that packages signed with hashes only work correctly."""
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+
+                # Test that things work with unsigned packages.
+                self.image_create(self.rurl1)
+
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-property signature-policy ignore")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-property signature-policy verify")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-property signature-policy require-signatures")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.RequiredSignaturePolicyException,
+                    self._api_install, api_obj, ["example_pkg"])
+                # Tests that the cli handles RequiredSignaturePolicyExceptions.
+                self.pkg("install example_pkg", exit=1)
+                self.pkg("set-property signature-policy require-names foo")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.MissingRequiredNamesException,
+                    self._api_install, api_obj, ["example_pkg"])
+                # Tests that the cli handles MissingRequiredNamesException.
+                self.pkg("install example_pkg", exit=1)
+
+                self.pkg("unset-property signature-policy")
+
+                self.pkg("set-publisher --set-property signature-policy=ignore "
+                    "test")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-publisher --set-property signature-policy=verify "
+                    "test")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-publisher "
+                    "--set-property signature-policy=require-signatures test")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.RequiredSignaturePolicyException,
+                    self._api_install, api_obj, ["example_pkg"])
+                self.pkg("set-publisher "
+                    "--set-property signature-policy=require-names "
+                    "--set-property signature-required-names=foo test")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.MissingRequiredNamesException,
+                    self._api_install, api_obj, ["example_pkg"])
+
+                self.pkgsign(self.rurl1, plist[0])
+                self.image_destroy()
+                self.image_create(self.rurl1)
+
+                # Test that things work hashes instead of signatures.
+                self.pkg("refresh --full")
+
+                self.pkg("set-publisher --unset-property signature-policy "
+                    "--unset-property signature-required-names test")
+
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self.pkg("search -l sha256")
+                self._api_uninstall(api_obj, ["example_pkg"])
+
+                self.pkg("set-property signature-policy ignore")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-property signature-policy verify")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-property signature-policy require-signatures")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.RequiredSignaturePolicyException,
+                    self._api_install, api_obj, ["example_pkg"])
+                self.pkg("set-property signature-policy require-names foo")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.MissingRequiredNamesException,
+                    self._api_install, api_obj, ["example_pkg"])
+
+                self.pkg("unset-property signature-policy")
+
+                self.pkg("set-publisher --set-property signature-policy=ignore "
+                    "test")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-publisher --set-property signature-policy=verify "
+                    "test")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-publisher --set-property "
+                    "signature-policy=require-signatures test")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.RequiredSignaturePolicyException,
+                    self._api_install, api_obj, ["example_pkg"])
+                self.pkg("set-publisher "
+                    "--set-property signature-policy=require-names "
+                    "--set-property signature-required-names=foo test")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.MissingRequiredNamesException,
+                    self._api_install, api_obj, ["example_pkg"])
+
+        def test_sign_1(self):
+                """Test that packages signed using private keys function
+                correctly.  Uses a chain of certificates three certificates
+                long."""
+
+                ca_path = os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta3_cert.pem")
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([ca_path], ca=True)
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+                sign_args = "-k %(key)s -c %(cert)s %(name)s" % {
+                        "name": plist[0],
+                        "key": os.path.join(self.keys_dir,
+                            "cs1_p1_ta3_key.pem"),
+                        "cert": os.path.join(self.cs_dir, "cs1_p1_ta3_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+
+                self.pkg_image_create(self.rurl1,
+                    additional_args="--set-property trust-anchor-directory='%s'" % os.path.join(self.path_to_certs, "ta3"))
+
+                # Find the hash of the publisher CA cert used.
+                hsh = self.calc_file_hash(ca_path)
+
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self.pkg("search -l rsa-sha256")
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-property signature-policy ignore")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-property signature-policy verify")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+
+                self.pkg("unset-property trust-anchor-directory")
+                # This should fail because the chain is root in an untrusted
+                # self-signed cert.
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.BrokenChain, self._api_install, api_obj,
+                    ["example_pkg"])
+                # Test that the cli handles BrokenChain exceptions.
+                self.pkg("install example_pkg", exit=1)
+                self.pkg("set-property trust-anchor-directory %s" %
+                    os.path.join(self.path_to_certs, "ta3"))
+                
+                self.pkg("set-property signature-policy require-signatures")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-property signature-policy require-names foo")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.MissingRequiredNamesException,
+                    self._api_install, api_obj, ["example_pkg"])
+                self.pkg("set-property signature-policy "
+                    "require-names 'cs1_p1_ta3'")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("add-property-value signature-required-names "
+                    "'pubCA1_ta3'")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("remove-property-value signature-required-names "
+                    "'cs1_p1_ta3'")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+
+                # Test setting publisher level policies.
+                self.pkg("unset-property signature-policy")
+
+                self.pkg("set-publisher --set-property signature-policy=ignore "
+                    "test")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-publisher --set-property signature-policy=verify "
+                    "test")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-publisher "
+                    "--set-property signature-policy=require-signatures test")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-publisher "
+                    "--set-property signature-policy=require-names "
+                    "--set-property signature-required-names='cs1_p1_ta3' test")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-publisher --add-property-value "
+                    "signature-required-names='pubCA1_ta3' test")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-publisher --remove-property-value "
+                    "signature-required-names='cs1_p1_ta3' test")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-publisher --add-property-value "
+                    "signature-required-names='foo' test")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.MissingRequiredNamesException,
+                    self._api_install, api_obj, ["example_pkg"])
+                self.pkg("set-publisher --remove-property-value "
+                    "signature-required-names='foo' test")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+
+                # Test combining publisher and image require-names policies.
+                self.pkg("set-property signature-policy require-names foo")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.MissingRequiredNamesException,
+                    self._api_install, api_obj, ["example_pkg"])
+                self.pkg("set-property signature-policy require-names "
+                    "pubCA1_ta3")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("unset-property signature-policy")
+
+                # Test removing and adding ca certs
+                self.pkg("set-publisher --set-property signature-policy=verify "
+                    "test")
+                self.pkg("set-publisher --revoke-ca-cert=%s test" % hsh)
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.BrokenChain, self._api_install, api_obj,
+                    ["example_pkg"])
+                self.pkg("set-publisher --approve-ca-cert=%s test" % ca_path)
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self.pkg("set-publisher --revoke-ca-cert=%s test" % hsh)
+                self.pkg("verify", exit=1)
+                self.pkg("fix", exit=1)
+                self.pkg("set-publisher --set-property signature-policy=ignore "
+                    "test")
+                # These should fail because the image, though not the publisher
+                # verifies signatures.
+                self.pkg("set-property signature-policy verify")
+                self.pkg("verify", exit=1)
+                self.pkg("fix", exit=1)
+                self.pkg("set-property signature-policy ignore")
+                self.pkg("verify")
+                self.pkg("fix")
+                self.pkg("set-publisher --set-property signature-policy=verify "
+                    "test")
+                # These should fail because the publisher, though not the image
+                # verifies signatures.
+                self.pkg("verify", exit=1)
+                self.pkg("fix", exit=1)
+                self.pkg("set-publisher --approve-ca-cert=%s test" % ca_path)
+                self.pkg("verify")
+                self.pkg("fix")
+                api_obj = self.get_img_api_obj()
+                self._api_uninstall(api_obj, ["example_pkg"])
+
+                # Test removing a signing cert.
+                # Find the hash of the publisher CA cert used.
+                hsh = self.calc_file_hash(ca_path)
+                r.remove_signing_certs([hsh], ca=True)
+                self.image_destroy()
+                self.image_create(self.rurl1)
+                self.pkg("set-property signature-policy verify")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.BrokenChain, self._api_install, api_obj,
+                    ["example_pkg"])
+
+        def test_sign_2(self):
+                """Test that verification of the CS cert failing means the
+                install fails."""
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+                sign_args = "-k %(key)s -c %(cert)s %(name)s" % {
+                        "name": plist[0],
+                        "key": os.path.join(self.keys_dir,
+                            "cs1_p1_ta3_key.pem"),
+                        "cert": os.path.join(self.cs_dir, "cs1_p1_ta3_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+                self.image_create(self.rurl1)
+                self.pkg("set-property signature-policy verify")
+
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.BrokenChain, self._api_install, api_obj,
+                    ["example_pkg"])
+
+        def test_sign_3(self):
+                """Test that using a chain seven certificates long works.  It
+                also tests that setting a second publisher ca cert doesn't
+                cause anything to break."""
+
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta1_cert.pem")], ca=True)
+                r.add_signing_certs([os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta3_cert.pem")], ca=True)
+                r.add_signing_certs([os.path.join(self.inter_certs_dir,
+                    "i1_ta1_cert.pem")], ca=False)
+                r.add_signing_certs([os.path.join(self.inter_certs_dir,
+                    "i2_ta1_cert.pem")], ca=False)
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+                sign_args = "-k %(key)s -c %(cert)s -i %(i1)s -i %(i2)s " \
+                    "%(pkg)s" % {
+                      "key": os.path.join(self.keys_dir, "cs1_pubCA1_key.pem"),
+                      "cert": os.path.join(self.cs_dir, "cs1_pubCA1_cert.pem"),
+                      "i1": os.path.join(self.chain_certs_dir,
+                          "ch1_pubCA1_cert.pem"),
+                      "i2": os.path.join(self.chain_certs_dir,
+                          "ch2_pubCA1_cert.pem"),
+                      "pkg": plist[0]
+                    }
+                
+                self.pkgsign(self.rurl1, sign_args)
+                self.pkg_image_create(self.rurl1)
+
+                self.pkg("set-property trust-anchor-directory %s" %
+                    self.trust_anchor_dir)
+
+                self.pkg("set-property signature-policy verify")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+
+        def test_multiple_signatures(self):
+                """Test that having a package signed with more than one
+                signature doesn't cause anything to break."""
+
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta1_cert.pem")], ca=True)
+                r.add_signing_certs([os.path.join(self.inter_certs_dir,
+                    "i1_ta1_cert.pem")], ca=False)
+                r.add_signing_certs([os.path.join(self.inter_certs_dir,
+                    "i2_ta1_cert.pem")], ca=False)
+                r.add_signing_certs([os.path.join(self.trust_anchor_dir,
+                    "ta2_cert.pem")], ca=True)
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+
+                sign_args = "-k %(key)s -c %(cert)s -i %(i1)s -i %(i2)s " \
+                    "%(pkg)s" % {
+                        "key":
+                        os.path.join(self.keys_dir, "cs1_pubCA1_key.pem"),
+                        "cert":
+                        os.path.join(self.cs_dir, "cs1_pubCA1_cert.pem"),
+                        "i1":
+                        os.path.join(self.chain_certs_dir,
+                            "ch1_pubCA1_cert.pem"),
+                        "i2":
+                        os.path.join(self.chain_certs_dir,
+                            "ch2_pubCA1_cert.pem"),
+                        "pkg": plist[0]
+                    }
+                self.pkgsign(self.rurl1, sign_args)
+
+                sign_args = "-k %(key)s -c %(cert)s %(name)s" % {
+                    "name": plist[0],
+                    "key": os.path.join(self.keys_dir, "cs1_ta2_key.pem"),
+                    "cert": os.path.join(self.cs_dir, "cs1_ta2_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+                
+                self.pkg_image_create(self.rurl1)
+                self.pkg("set-property trust-anchor-directory %s" %
+                    self.trust_anchor_dir)
+                self.pkg("set-property signature-policy verify")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-property signature-policy require-signatures")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-property signature-policy require-names "
+                    "'cs1_ta2'")
+                self.pkg("add-property-value signature-required-names 'i1_ta1'")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("add-property-value signature-required-names 'foo'")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.MissingRequiredNamesException,
+                    self._api_install, api_obj, ["example_pkg"])
+
+        def test_sign_4(self):
+                """Test that not providing a needed intermediate cert makes
+                verification fail."""
+
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta1_cert.pem")], ca=True)
+                r.add_signing_certs([os.path.join(self.inter_certs_dir,
+                    "i1_ta1_cert.pem")], ca=False)
+                r.add_signing_certs([os.path.join(self.inter_certs_dir,
+                    "i2_ta1_cert.pem")], ca=False)
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+                sign_args = "-k %(key)s -c %(cert)s -i %(i2)s %(pkg)s" % \
+                    { "key": os.path.join(self.keys_dir, "cs1_pubCA1_key.pem"),
+                      "cert": os.path.join(self.cs_dir, "cs1_pubCA1_cert.pem"),
+                      "i2": os.path.join(self.chain_certs_dir,
+                          "ch2_pubCA1_cert.pem"),
+                      "pkg": plist[0]
+                    }
+                self.pkgsign(self.rurl1, sign_args)
+                self.image_create(self.rurl1)
+                self.pkg("set-property signature-policy verify")
+
+                self.pkg("install example_pkg", exit=1)
+
+        def test_sign_5(self):
+                """Test that http repos work."""
+
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([
+                    os.path.join(self.pub_cas_dir, "pubCA1_ta1_cert.pem"),
+                    os.path.join(self.pub_cas_dir, "pubCA1_ta3_cert.pem")],
+                    ca=True)
+                r.add_signing_certs([
+                    os.path.join(self.inter_certs_dir, "i1_ta1_cert.pem"),
+                    os.path.join(self.inter_certs_dir, "i2_ta1_cert.pem")],
+                    ca=False)
+                self.dcs[1].start()
+                
+                plist = self.pkgsend_bulk(self.durl1, self.example_pkg10)
+                sign_args = "-k %(key)s -c %(cert)s -i %(i1)s -i %(i2)s " \
+                    "%(pkg)s" % {
+                      "key": os.path.join(self.keys_dir, "cs1_pubCA1_key.pem"),
+                      "cert": os.path.join(self.cs_dir, "cs1_pubCA1_cert.pem"),
+                      "i1": os.path.join(self.chain_certs_dir,
+                          "ch1_pubCA1_cert.pem"),
+                      "i2": os.path.join(self.chain_certs_dir,
+                          "ch2_pubCA1_cert.pem"),
+                      "pkg": plist[0]
+                    }
+                self.pkgsign(self.durl1, sign_args)
+                self.pkg_image_create(self.durl1)
+
+                self.pkg("set-property trust-anchor-directory %s" %
+                    self.trust_anchor_dir)
+
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+
+        def test_length_two_chains(self):
+                """Check that chains of length two work correctly."""
+
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([os.path.join(self.trust_anchor_dir,
+                    "ta2_cert.pem")], ca=True)
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+                sign_args = "-k %(key)s -c %(cert)s %(pkg)s" % \
+                    { "key": os.path.join(self.keys_dir, "cs1_ta2_key.pem"),
+                      "cert": os.path.join(self.cs_dir, "cs1_ta2_cert.pem"),
+                      "pkg": plist[0]
+                    }
+                
+                self.pkgsign(self.rurl1, sign_args)
+                self.pkg_image_create(self.rurl1)
+
+                self.pkg("set-property signature-policy verify")
+                # This should trigger a UntrustedSelfSignedCert error.
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.UntrustedSelfSignedCert,
+                    self._api_install, api_obj, ["example_pkg"])
+                # Test that the cli handles an UntrustedSelfSignedCert.
+                self.pkg("install example_pkg", exit=1)
+                
+                self.pkg("set-property trust-anchor-directory %s" %
+                    os.path.join(self.path_to_certs, "ta2"))
+
+                self.pkg("set-property signature-policy verify")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-property signature-policy require-names foo")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.MissingRequiredNamesException,
+                    self._api_install, api_obj, ["example_pkg"])
+                self.pkg("set-property signature-policy require-names "
+                    "'cs1_ta2'")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("add-property-value signature-required-names 'ta2'")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+
+        def test_variant_sigs(self):
+                """Test that variant tagged signatures are ignored."""
+                plist = self.pkgsend_bulk(self.rurl1, self.varsig_pkg)
+                self.pkg_image_create(self.rurl1)
+
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-property signature-policy verify")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("set-property signature-policy require-signatures")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.RequiredSignaturePolicyException,
+                    self._api_install, api_obj, ["example_pkg"])
+
+        def test_bad_opts_1(self):
+                self.pkgsign(self.durl1, "--help")
+                self.dcs[1].start()
+                self.pkgsign(self.durl1, "[email protected]", exit=1)
+                plist = self.pkgsend_bulk(self.durl1, self.example_pkg10)
+                # Test that passing sign-all and a fmri results in an error.
+                self.pkgsign(self.durl1, "--sign-all %(name)s" % {
+                      "name": plist[0]
+                    }, exit=2)
+
+                # Test that passing neither sign-all nor a fmri results in an
+                # error.
+                self.pkgsign(self.durl1, "", exit=2)
+                
+                # Test bad sig.alg setting.
+                self.pkgsign(self.durl1, "-a foo -k %(key)s -c %(cert)s "
+                    "%(name)s" % {
+                      "key": os.path.join(self.keys_dir, "cs1_pubCA1_key.pem"),
+                      "cert": os.path.join(self.cs_dir, "cs1_pubCA1_cert.pem"),
+                      "name": plist[0]
+                    }, exit=2)
+
+                # Test missing cert option
+                self.pkgsign(self.durl1, "-k %(key)s %(name)s" %
+                    { "key": os.path.join(self.keys_dir, "cs1_pubCA1_key.pem"),
+                      "name": plist[0]
+                    }, exit=2)
+                # Test missing key option
+                self.pkgsign(self.durl1, "-c %(cert) %(name)s" %
+                    { "cert": os.path.join(self.cs_dir, "cs1_pubCA1_cert.pem"),
+                      "name": plist[0]
+                    }, exit=2)
+                # Test -i with missing -c and -k
+                self.pkgsign(self.durl1, "-i %(i1)s %(name)s" %
+                    { "i1": os.path.join(self.chain_certs_dir,
+                          "ch1_pubCA1_cert.pem"),
+                      "name": plist[0]
+                    }, exit=2)
+                # Test passing a cert as a key
+                self.pkgsign(self.durl1, "-c %(cert)s -k %(cert)s %(name)s" %
+                    { "cert": os.path.join(self.cs_dir, "cs1_pubCA1_cert.pem"),
+                      "name": plist[0]
+                    }, exit=1)
+                # Test passing a non-existent certificate file
+                self.pkgsign(self.durl1, "-c /shouldnotexist -k %(key)s "
+                    "%(name)s" % {
+                      "key": os.path.join(self.keys_dir, "cs1_pubCA1_key.pem"),
+                      "name": plist[0]
+                    }, exit=2)
+                # Test passing a non-existent key file
+                self.pkgsign(self.durl1, "-c %(cert)s -k /shouldnotexist "
+                    "%(name)s" % {
+                      "cert": os.path.join(self.cs_dir, "cs1_pubCA1_cert.pem"),
+                      "name": plist[0]
+                    }, exit=2)
+                # Test passing a file that's not a key file as a key file
+                self.pkgsign(self.durl1, "-k %(key)s -c %(cert)s %(name)s" %
+                    { "key": os.path.join(self.test_root, "tmp/example_file"),
+                      "cert": os.path.join(self.cs_dir, "cs1_pubCA1_cert.pem"),
+                      "name": plist[0]
+                    }, exit=1)
+                # Test passing a non-existent file as an intermediate cert
+                self.pkgsign(self.durl1, "-k %(key)s -c %(cert)s -i %(i1)s "
+                    "%(name)s" % {
+                      "key": os.path.join(self.keys_dir, "cs1_pubCA1_key.pem"),
+                      "cert": os.path.join(self.cs_dir, "cs1_pubCA1_cert.pem"),
+                      "i1": os.path.join(self.chain_certs_dir,
+                          "shouldnot/exist"),
+                      "name": plist[0]
+                    }, exit=2)
+                # Test passing a directory as an intermediate cert
+                self.pkgsign(self.durl1, "-k %(key)s -c %(cert)s -i %(i1)s "
+                    "%(name)s" % {
+                      "key": os.path.join(self.keys_dir, "cs1_pubCA1_key.pem"),
+                      "cert": os.path.join(self.cs_dir, "cs1_pubCA1_cert.pem"),
+                      "i1": self.chain_certs_dir,
+                      "name": plist[0]
+                    }, exit=2)
+                # Test setting the signature algorithm to be one which requires
+                # a key and cert, but not passing -k or -c.
+                self.pkgsign(self.durl1, "-a rsa-sha256 %s" % plist[0], exit=2)
+                # Test setting the signature algorithm to be one which does not
+                # use a key and cert, but passing -k and -c.
+                self.pkgsign(self.durl1, "-a sha256 -k %(key)s -c %(cert)s "
+                    "%(name)s" % {
+                      "key": os.path.join(self.keys_dir, "cs1_pubCA1_key.pem"),
+                      "cert": os.path.join(self.cs_dir, "cs1_pubCA1_cert.pem"),
+                      "name": plist[0]
+                    }, exit=2)
+                # Test that installing a package signed using a bogus
+                # certificate fails.
+                self.pkgsign(self.durl1, "-k %(key)s -c %(cert)s %(name)s" %
+                    { "key": os.path.join(self.keys_dir, "cs1_pubCA1_key.pem"),
+                      "cert": os.path.join(self.test_root, "tmp/example_file"),
+                      "name": plist[0]
+                    })
+                self.pkg_image_create(self.durl1)
+                self.pkg("set-property signature-policy verify")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.BadFileFormat, self._api_install, api_obj,
+                    ["example_pkg"])
+                # Test that the cli handles a BadFileFormat exception.
+                self.pkg("install example_pkg", exit=1)
+                self.pkg("set-property trust-anchor-directory %s" %
+                    os.path.join(self.test_root, "tmp/example_file"))
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.InvalidPropertyValue, self._api_install,
+                    api_obj, ["example_pkg"])
+                # Test that the cli handles an InvalidPropertyValue exception.
+                self.pkg("install example_pkg", exit=1)
+
+        def test_bad_opts_2(self):
+                """Test that having a bogus trust anchor will stop install."""
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+                self.pkgsign(self.rurl1, "-k %(key)s -c %(cert)s %(name)s" %
+                    { "key": os.path.join(self.keys_dir, "cs1_pubCA1_key.pem"),
+                      "cert": os.path.join(self.cs_dir, "cs1_pubCA1_cert.pem"),
+                      "name": plist[0]
+                    })
+                self.pkg_image_create(self.rurl1)
+                self.pkg("set-property signature-policy verify")
+                self.pkg("set-property trust-anchor-directory %s" %
+                    os.path.join(self.test_root, "tmp/example_file"))
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.InvalidPropertyValue, self._api_install,
+                    api_obj, ["example_pkg"])
+
+        def test_multiple_hash_algs(self):
+                """Test that signing with other hash algorithms works
+                correctly."""
+
+                ca_path = os.path.join(os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta3_cert.pem"))
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([ca_path], ca=True)
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+                sign_args = "-k %(key)s -c %(cert)s %(name)s" % {
+                        "name": plist[0],
+                        "key": os.path.join(self.keys_dir,
+                            "cs1_p1_ta3_key.pem"),
+                        "cert": os.path.join(self.cs_dir, "cs1_p1_ta3_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+
+                sign_args = "-a rsa-sha512 -k %(key)s -c %(cert)s %(name)s" % {
+                        "name": plist[0],
+                        "key": os.path.join(self.keys_dir,
+                            "cs1_p1_ta3_key.pem"),
+                        "cert": os.path.join(self.cs_dir, "cs1_p1_ta3_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+
+                sign_args = "-a sha384 %(name)s" % {"name": plist[0]}
+                self.pkgsign(self.rurl1, sign_args)
+
+                self.pkg_image_create(self.rurl1,
+                    additional_args="--set-property trust-anchor-directory='%s'" % os.path.join(self.path_to_certs, "ta3"))
+
+                self.pkg("set-property require-signatures verify")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+
+        def test_mismatched_sigs(self):
+                """Test that if the certificate can't validate the signature,
+                an error happens."""
+
+                ca_path = os.path.join(os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta3_cert.pem"))
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([ca_path], ca=True)
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+                sign_args = "-k %(key)s -c %(cert)s %(name)s" % {
+                        "name": plist[0],
+                        "key": os.path.join(self.keys_dir, "cs1_ta2_key.pem"),
+                        "cert": os.path.join(self.cs_dir, "cs1_p1_ta3_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+                self.pkg_image_create(self.rurl1,
+                    additional_args="--set-property trust-anchor-directory='%s'" % os.path.join(self.path_to_certs, "ta3"))
+
+                self.pkg("set-property signature-policy verify")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.UnverifiedSignature, self._api_install,
+                    api_obj, ["example_pkg"])
+                # Test that the cli handles an UnverifiedSignature exception.
+                self.pkg("install example_pkg", exit=1)
+                self.pkg("set-property signature-policy ignore")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("unset-property signature-policy")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+
+        def test_mismatched_hashes(self):
+                """Test that if the hash signature isn't correct, an error
+                happens."""
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+                sign_args = "%(name)s" % { "name": plist[0] }
+                self.pkgsign(self.rurl1, sign_args)
+                self.pkg_image_create(self.rurl1)
+
+                # Make sure the manifest is locally stored.
+                self.pkg("install -n example_pkg")
+                # Append an action to the manifest.
+                pfmri = fmri.PkgFmri(plist[0])
+                s = self.get_img_manifest(pfmri)
+                s += "\nset name=foo value=bar"
+                self.write_img_manifest(pfmri, s)
+
+                self.pkg("set-property signature-policy verify")
+                # This should fail because the text of manifest has changed
+                # so the hash should no longer validate.
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.UnverifiedSignature, self._api_install,
+                    api_obj, ["example_pkg"])
+                self.pkg("set-property signature-policy ignore")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self.pkg("unset-property signature-policy")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+
+        def test_unknown_sig_alg(self):
+                """Test that if the certificate can't validate the signature,
+                an error happens."""
+
+                ca_path = os.path.join(os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta3_cert.pem"))
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([ca_path], ca=True)
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+                sign_args = "-k %(key)s -c %(cert)s %(name)s" % {
+                        "name": plist[0],
+                        "key": os.path.join(self.keys_dir, "cs1_ta2_key.pem"),
+                        "cert": os.path.join(self.cs_dir, "cs1_p1_ta3_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+                self.pkg_image_create(self.rurl1,
+                    additional_args="--set-property trust-anchor-directory='%s'" % os.path.join(self.path_to_certs, "ta3"))
+
+                # Make sure the manifest is locally stored.
+                api_obj = self.get_img_api_obj()
+                api_obj.plan_install(["example_pkg"], noexecute=True)
+                # Change the signature action.
+                pfmri = fmri.PkgFmri(plist[0])
+                s = self.get_img_manifest(pfmri)
+                s = s.replace("rsa-sha256", "rsa-foobar")
+                self.write_img_manifest(pfmri, s)
+                
+                self.pkg("set-property signature-policy require-signatures")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.RequiredSignaturePolicyException,
+                    self._api_install, api_obj, ["example_pkg"])
+                # This passes because 'foobar' isn't a recognized hash algorithm
+                # so the signature action is skipped.
+                self.pkg("set-property signature-policy verify")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+
+                # Change the signature action.
+                pfmri = fmri.PkgFmri(plist[0])
+                s = self.get_img_manifest(pfmri)
+                s = s.replace("rsa-foobar", "foo-sha256")
+                self.write_img_manifest(pfmri, s)
+
+                self.pkg("set-property signature-policy require-signatures")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.RequiredSignaturePolicyException,
+                    self._api_install, api_obj, ["example_pkg"])
+                self.pkg("install example_pkg", exit=1)
+                # This passes because 'foobar' isn't a recognized signature
+                # algorithm so the signature action is skipped.
+                self.pkg("set-property signature-policy verify")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+
+        def test_unsupported_critical_extension_1(self):
+                """Test that packages signed using a certificate with an
+                unsupported critical extension will not have valid signatures.
+                """
+
+                ca_path = os.path.join(os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta3_cert.pem"))
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([ca_path], ca=True)
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+                sign_args = "-k %(key)s -c %(cert)s %(name)s" % {
+                        "name": plist[0],
+                        "key": os.path.join(self.keys_dir,
+                            "cs2_p1_ta3_key.pem"),
+                        "cert": os.path.join(self.cs_dir, "cs2_p1_ta3_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+
+                self.pkg_image_create(self.rurl1,
+                    additional_args="--set-property trust-anchor-directory='%s'" % os.path.join(self.path_to_certs, "ta3"))
+
+                self.pkg("set-property signature-policy verify")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.UnsupportedCriticalExtension,
+                    self._api_install, api_obj, ["example_pkg"])
+                # Tests that the cli can handle an UnsupportedCriticalExtension.
+                self.pkg("install example_pkg", exit=1)
+                self.pkg("set-property signature-policy ignore")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+
+        def test_unsupported_critical_extension_2(self):
+                """Test that packages signed using a certificate whose chain of
+                trust contains a certificate with an unsupported critical
+                extension will not have valid signatures."""
+
+                ca_path = os.path.join(os.path.join(self.pub_cas_dir,
+                    "pubCA2_ta3_cert.pem"))
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([ca_path], ca=True)
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+                sign_args = "-k %(key)s -c %(cert)s %(name)s" % {
+                        "name": plist[0],
+                        "key": os.path.join(self.keys_dir,
+                            "cs1_p2_ta3_key.pem"),
+                        "cert": os.path.join(self.cs_dir, "cs1_p2_ta3_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+
+                self.pkg_image_create(self.rurl1,
+                    additional_args="--set-property trust-anchor-directory='%s'" % os.path.join(self.path_to_certs, "ta3"))
+
+                self.pkg("set-property signature-policy verify")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.UnsupportedCriticalExtension,
+                    self._api_install, api_obj, ["example_pkg"])
+
+        def test_unsupported_critical_extension_3(self):
+                """Test that packages signed using a certificate whose chain of
+                trust contains a certificate with an unsupported critical
+                extension will not have valid signatures."""
+
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta1_cert.pem")], ca=True)
+                r.add_signing_certs([os.path.join(self.inter_certs_dir,
+                    "i1_ta1_cert.pem")], ca=False)
+                r.add_signing_certs([os.path.join(self.inter_certs_dir,
+                    "i2_ta1_cert.pem")], ca=False)
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+                sign_args = "-k %(key)s -c %(cert)s -i %(i1)s -i %(i2)s " \
+                    "%(name)s" % {
+                        "name": plist[0],
+                        "key": os.path.join(self.keys_dir,
+                            "cs4_pubCA1_key.pem"),
+                        "cert": os.path.join(self.cs_dir,
+                            "cs4_pubCA1_cert.pem"),
+                        "i1": os.path.join(self.chain_certs_dir,
+                            "ch1_pubCA1_cert.pem"),
+                        "i2": os.path.join(self.chain_certs_dir,
+                            "ch2.2_pubCA1_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+
+                self.pkg_image_create(self.rurl1,
+                    additional_args="--set-property trust-anchor-directory='%s'" % os.path.join(self.path_to_certs, "ta1"))
+
+                self.pkg("set-property signature-policy verify")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.BrokenChain, self._api_install, api_obj,
+                    ["example_pkg"])
+                # Test that the cli handles a BrokenChain exception which
+                # contains other exceptions.
+                self.pkg("install example_pkg", exit=1)
+
+        def test_sign_no_server_update(self):
+                """Test that packages signed using private keys function
+                correctly.  Uses a chain of certificates three certificates
+                long."""
+
+                ca_path = os.path.join(os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta3_cert.pem"))
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([ca_path], ca=True)
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+                sign_args = "--no-index --no-catalog -k %(key)s -c %(cert)s " \
+                    "%(name)s" % {
+                        "name": plist[0],
+                        "key": os.path.join(self.keys_dir,
+                            "cs1_p1_ta3_key.pem"),
+                        "cert": os.path.join(self.cs_dir, "cs1_p1_ta3_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+
+                self.pkg_image_create(self.rurl1,
+                    additional_args="--set-property trust-anchor-directory='%s'" % os.path.join(self.path_to_certs, "ta3"))
+
+                # This fails because the index hasn't been updated.
+                self.pkg("search -r rsa-sha256", exit=1)
+                self.pkg("set-property signature-policy require-signatures")
+                # This fails because the catalog hasn't been updated with
+                # the signed manifest yet.
+                self.pkg("install example_pkg", exit=1)
+                r.rebuild()
+                self.pkg("install example_pkg")
+
+        def test_bogus_client_certs(self):
+                """Tests that if a certificate stored on the client is replaced
+                with a different certificate, installation fails."""
+
+                ca_path = os.path.join(os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta3_cert.pem"))
+                cs_path = os.path.join(self.cs_dir, "cs1_p1_ta3_cert.pem")
+                cs2_path = os.path.join(self.cs_dir, "cs1_ta2_cert.pem")
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([ca_path], ca=True)
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+                sign_args = "-k %(key)s -c %(cert)s " \
+                    "%(name)s" % {
+                        "name": plist[0],
+                        "key": os.path.join(self.keys_dir,
+                            "cs1_p1_ta3_key.pem"),
+                        "cert": cs_path
+                }
+                self.pkgsign(self.rurl1, sign_args)
+
+                self.pkg_image_create(self.rurl1,
+                    additional_args="--set-property trust-anchor-directory='%s'" % os.path.join(self.path_to_certs, "ta3"))
+
+                self.pkg("set-property signature-policy verify")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+
+                # Replace the client CS cert.
+                hsh = self.calc_file_hash(cs_path)
+                pth = os.path.join(self.img_path, "var", "pkg", "publisher",
+                    "test", "certs", hsh)
+                portable.copyfile(cs2_path, pth)
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.ModifiedCertificateException,
+                    self._api_install, api_obj, ["example_pkg"])
+                # Test that the cli handles a ModifiedCertificateException.
+                self.pkg("install example_pkg", exit=1)
+
+                # Test that removing the CS cert will cause it to be downloaded
+                # again and the installation will then work.
+
+                portable.remove(pth)
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+
+                # Repeat the test but change the CA cert instead of the CS cert.
+
+                # Replace the client CA cert.
+                hsh = self.calc_file_hash(ca_path)
+                pth = os.path.join(self.img_path, "var", "pkg", "publisher",
+                    "test", "certs", hsh)
+                portable.copyfile(cs2_path, pth)
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.ModifiedCertificateException,
+                    self._api_install, api_obj, ["example_pkg"])
+
+                # Test that removing the CA cert will cause it to be downloaded
+                # again and the installation will then work.
+
+                portable.remove(pth)
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+
+        def test_crl_0(self):
+                """Test that the X509 CRL revocation works correctly."""
+
+                crl = m2.X509.load_crl(os.path.join(self.crl_dir,
+                    "pubCA1_ta4_crl.pem"))
+                revoked_cert = m2.X509.load_cert(os.path.join(self.cs_dir,
+                    "cs1_ta4_cert.pem"))
+                assert crl.is_revoked(revoked_cert)[0]
+
+        def test_bogus_inter_certs(self):
+                """Test that if SignatureAction.set_signature is given invalid
+                paths to intermediate certs, it errors as expected.  This
+                cannot be tested from the command line because the command
+                line rejects certificates that aren't of the right format."""
+
+                attrs = {
+                    "algorithm": "sha256",
+                }
+                key_pth = os.path.join(self.keys_dir, "cs_pubCA1_key.pem")
+                cert_pth = os.path.join(self.cs_dir, "cs1_pubCA1_cert.pem")
+                sig_act = signature.SignatureAction(cert_pth, **attrs)
+                self.assertRaises(action.ActionDataError, sig_act.set_signature,
+                    [sig_act], key_path=key_pth,
+                    chain_paths=["/shouldnot/exist"])
+                self.assertRaises(action.ActionDataError, sig_act.set_signature,
+                    [sig_act], key_path=key_pth, chain_paths=[self.test_root])
+
+        def test_sign_all(self):
+                """Test that the --sign-all option works correctly, signing
+                all packages in a repository."""
+
+                ca_path = os.path.join(os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta3_cert.pem"))
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([ca_path], ca=True)
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+                plist = self.pkgsend_bulk(self.rurl1, self.var_pkg)
+
+                sign_args = "-k %(key)s -c %(cert)s --sign-all" % {
+                        "key": os.path.join(self.keys_dir,
+                            "cs1_p1_ta3_key.pem"),
+                        "cert": os.path.join(self.cs_dir, "cs1_p1_ta3_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+
+                self.pkg_image_create(self.rurl1,
+                    additional_args="--set-property trust-anchor-directory='%s'" % os.path.join(self.path_to_certs, "ta3"))
+
+                self.pkg("set-property signature-policy require-signatures")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self._api_install(api_obj, ["var_pkg"])
+                self._api_uninstall(api_obj, ["example_pkg"])
+                self._api_uninstall(api_obj, ["var_pkg"])
+
+        def test_crl_1(self):
+                """Test that revoking a code signing certificate by the
+                publisher CA works correctly."""
+                
+                ca_path = os.path.join(os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta4_cert.pem"))
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([ca_path], ca=True)
+
+                os.makedirs(os.path.join(r.file_root, "pu"))
+                portable.copyfile(os.path.join(self.crl_dir,
+                    "pubCA1_ta4_crl.pem"),
+                    os.path.join(r.file_root, "pu", "pubCA1_ta4_crl.pem"))
+                
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+
+                sign_args = "-k %(key)s -c %(cert)s %(name)s" % {
+                        "name": plist[0],
+                        "key": os.path.join(self.keys_dir, "cs1_ta4_key.pem"),
+                        "cert": os.path.join(self.cs_dir, "cs1_ta4_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+
+                self.dcs[1].start()
+                
+                self.pkg_image_create(self.durl1,
+                    additional_args="--set-property trust-anchor-directory='%s'" % os.path.join(self.path_to_certs, "ta4"))
+
+                self.pkg("set-property signature-policy require-signatures")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.RevokedCertificate, self._api_install,
+                    api_obj, ["example_pkg"])
+                # Test that cli handles RevokedCertificate exception.
+                self.pkg("install example_pkg", exit=1)
+
+        def test_crl_2(self):
+                """Test that revoking a code signing certificate by the
+                publisher CA works correctly."""
+                
+                ca_path = os.path.join(os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta5_cert.pem"))
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([ca_path], ca=True)
+
+                os.makedirs(os.path.join(r.file_root, "ta"))
+                portable.copyfile(os.path.join(self.crl_dir,
+                    "ta5_crl.pem"),
+                    os.path.join(r.file_root, "ta", "ta5_crl.pem"))
+                
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+
+                sign_args = "-k %(key)s -c %(cert)s %(name)s" % {
+                        "name": plist[0],
+                        "key": os.path.join(self.keys_dir, "cs1_ta5_key.pem"),
+                        "cert": os.path.join(self.cs_dir, "cs1_ta5_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+
+                self.dcs[1].start()
+                
+                self.pkg_image_create(self.durl1,
+                    additional_args="--set-property trust-anchor-directory='%s'" % os.path.join(self.path_to_certs, "ta5"))
+
+                self.pkg("set-property signature-policy require-signatures")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.BrokenChain, self._api_install, api_obj,
+                    ["example_pkg"])
+
+        def test_crl_3(self):
+                """Test that a CRL with a bad file format does not cause
+                breakage."""
+                
+                ca_path = os.path.join(os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta4_cert.pem"))
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([ca_path], ca=True)
+
+                os.makedirs(os.path.join(r.file_root, "ex"))
+                portable.copyfile(os.path.join(self.test_root,
+                    "tmp/example_file"),
+                    os.path.join(r.file_root, "ex", "example_file"))
+                
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+
+                sign_args = "-k %(key)s -c %(cert)s %(name)s" % {
+                        "name": plist[0],
+                        "key": os.path.join(self.keys_dir, "cs2_ta4_key.pem"),
+                        "cert": os.path.join(self.cs_dir, "cs2_ta4_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+
+                self.dcs[1].start()
+                
+                self.pkg_image_create(self.durl1,
+                    additional_args="--set-property trust-anchor-directory='%s'" % os.path.join(self.path_to_certs, "ta4"))
+
+                self.pkg("set-property signature-policy require-signatures")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+
+        def test_crl_4(self):
+                """Test that a CRL which cannot be retrieved does not cause
+                breakage."""
+                
+                ca_path = os.path.join(os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta4_cert.pem"))
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([ca_path], ca=True)
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+
+                sign_args = "-k %(key)s -c %(cert)s %(name)s" % {
+                        "name": plist[0],
+                        "key": os.path.join(self.keys_dir, "cs2_ta4_key.pem"),
+                        "cert": os.path.join(self.cs_dir, "cs2_ta4_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+
+                self.dcs[1].start()
+                
+                self.pkg_image_create(self.durl1,
+                    additional_args="--set-property trust-anchor-directory='%s'" % os.path.join(self.path_to_certs, "ta4"))
+
+                self.pkg("set-property signature-policy require-signatures")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+
+        def test_crl_5(self):
+                """Test that revocation by CRL validated by a grandparent of the
+                certificate in question works."""
+
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta1_cert.pem")], ca=True)
+                r.add_signing_certs([os.path.join(self.inter_certs_dir,
+                    "i1_ta1_cert.pem")], ca=False)
+                r.add_signing_certs([os.path.join(self.inter_certs_dir,
+                    "i2_ta1_cert.pem")], ca=False)
+
+                os.makedirs(os.path.join(r.file_root, "pu"))
+                portable.copyfile(os.path.join(self.crl_dir,
+                    "pubCA1_ta1_crl.pem"),
+                    os.path.join(r.file_root, "pu", "pubCA1_ta1_crl.pem"))
+
+                self.dcs[1].start()
+                
+                plist = self.pkgsend_bulk(self.durl1, self.example_pkg10)
+                sign_args = "-k %(key)s -c %(cert)s -i %(i1)s -i %(i2)s " \
+                    "%(pkg)s" % {
+                      "key": os.path.join(self.keys_dir, "cs2_pubCA1_key.pem"),
+                      "cert": os.path.join(self.cs_dir, "cs2_pubCA1_cert.pem"),
+                      "i1": os.path.join(self.chain_certs_dir,
+                          "ch1_pubCA1_cert.pem"),
+                      "i2": os.path.join(self.chain_certs_dir,
+                          "ch2_pubCA1_cert.pem"),
+                      "pkg": plist[0]
+                    }
+                
+                self.pkgsign(self.durl1, sign_args)
+                self.pkg_image_create(self.durl1)
+
+                self.pkg("set-property trust-anchor-directory %s" %
+                    self.trust_anchor_dir)
+
+                self.pkg("set-property signature-policy verify")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.RevokedCertificate, self._api_install,
+                    api_obj, ["example_pkg"])
+
+        def test_crl_6(self):
+                """Test that revocation by CRL validated by an intermediate
+                certificate of the certificate in question works."""
+
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta1_cert.pem")], ca=True)
+                r.add_signing_certs([os.path.join(self.inter_certs_dir,
+                    "i1_ta1_cert.pem")], ca=False)
+                r.add_signing_certs([os.path.join(self.inter_certs_dir,
+                    "i2_ta1_cert.pem")], ca=False)
+
+                os.makedirs(os.path.join(r.file_root, "ch"))
+                portable.copyfile(os.path.join(self.crl_dir,
+                    "ch1_pubCA1_crl.pem"),
+                    os.path.join(r.file_root, "ch", "ch1_pubCA1_crl.pem"))
+
+                self.dcs[1].start()
+                
+                plist = self.pkgsend_bulk(self.durl1, self.example_pkg10)
+                sign_args = "-k %(key)s -c %(cert)s -i %(i1)s -i %(i2)s " \
+                    "%(pkg)s" % {
+                      "key": os.path.join(self.keys_dir, "cs3_pubCA1_key.pem"),
+                      "cert": os.path.join(self.cs_dir, "cs3_pubCA1_cert.pem"),
+                      "i1": os.path.join(self.chain_certs_dir,
+                          "ch1_pubCA1_cert.pem"),
+                      "i2": os.path.join(self.chain_certs_dir,
+                          "ch2_pubCA1_cert.pem"),
+                      "pkg": plist[0]
+                    }
+                
+                self.pkgsign(self.durl1, sign_args)
+                self.pkg_image_create(self.durl1)
+
+                self.pkg("set-property trust-anchor-directory %s" %
+                    self.trust_anchor_dir)
+
+                self.pkg("set-property signature-policy verify")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.RevokedCertificate, self._api_install,
+                    api_obj, ["example_pkg"])
+
+        def test_crl_7(self):
+                """Test that a CRL location which isn't in a known URI format
+                doesn't cause breakage."""
+                
+                ca_path = os.path.join(os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta4_cert.pem"))
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([ca_path], ca=True)
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+
+                sign_args = "-k %(key)s -c %(cert)s %(name)s" % {
+                        "name": plist[0],
+                        "key": os.path.join(self.keys_dir, "cs3_ta4_key.pem"),
+                        "cert": os.path.join(self.cs_dir, "cs3_ta4_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+
+                self.dcs[1].start()
+                
+                self.pkg_image_create(self.durl1,
+                    additional_args="--set-property trust-anchor-directory='%s'" % os.path.join(self.path_to_certs, "ta4"))
+
+                self.pkg("set-property signature-policy require-signatures")
+                api_obj = self.get_img_api_obj()
+                self.assertRaises(apx.InvalidResourceLocation,
+                    self._api_install, api_obj, ["example_pkg"])
+                # Test that the cli can handle a InvalidResourceLocation
+                # exception.
+                self.pkg("install example_pkg", exit=1)
+                self.pkg("set-property signature-policy ignore")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
+                self.pkg("set-property signature-policy require-signatures")
+                self.pkg("verify", exit=1)
+
+        def test_var_pkg(self):
+                """Test that actions tagged with variants don't break signing.
+                """
+
+                ca_path = os.path.join(os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta3_cert.pem"))
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([ca_path], ca=True)
+
+                plist = self.pkgsend_bulk(self.rurl1, self.var_pkg)
+
+                sign_args = "-k %(key)s -c %(cert)s %(pkg)s" % {
+                        "key": os.path.join(self.keys_dir,
+                            "cs1_p1_ta3_key.pem"),
+                        "cert": os.path.join(self.cs_dir,
+                            "cs1_p1_ta3_cert.pem"),
+                        "pkg": plist[0]
+                }
+                self.pkgsign(self.rurl1, sign_args)
+
+                self.pkg_image_create(self.rurl1,
+                    additional_args="--set-property trust-anchor-directory='%s'  --variant variant.arch=i386" % os.path.join(self.path_to_certs, "ta3"))
+
+                self.pkg("set-property signature-policy require-signatures")
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["var_pkg"])
+                self.assert_(os.path.exists(os.path.join(self.img_path, "baz")))
+                self.assert_(not os.path.exists(
+                    os.path.join(self.img_path, "bin")))
+
+        def test_disabled_append(self):
+                """Test that publishing to a depot which doesn't support append
+                fails as expected."""
+
+                self.dcs[1].set_disable_ops(["append"])
+                self.dcs[1].start()
+                
+                plist = self.pkgsend_bulk(self.durl1, self.example_pkg10)
+                
+                sign_args = "-k %(key)s -c %(cert)s %(pkg)s" % {
+                        "key": os.path.join(self.keys_dir,
+                            "cs1_p1_ta3_key.pem"),
+                        "cert": os.path.join(self.cs_dir,
+                            "cs1_p1_ta3_cert.pem"),
+                        "pkg": plist[0]
+                }
+                self.pkgsign(self.durl1, sign_args, exit=1)
+
+        def test_disabled_add(self):
+                """Test that publishing to a depot which doesn't support add
+                fails as expected."""
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+
+                self.dcs[1].set_disable_ops(["add"])
+                self.dcs[1].start()
+                
+                sign_args = "-k %(key)s -c %(cert)s %(pkg)s" % {
+                        "key": os.path.join(self.keys_dir,
+                            "cs1_p1_ta3_key.pem"),
+                        "cert": os.path.join(self.cs_dir,
+                            "cs1_p1_ta3_cert.pem"),
+                        "pkg": plist[0]
+                }
+                self.pkgsign(self.durl1, sign_args, exit=1)
+
+        def test_disabled_file(self):
+                """Test that publishing to a depot which doesn't support file
+                fails as expected."""
+
+                self.dcs[1].set_disable_ops(["file"])
+                self.dcs[1].start()
+
+                plist = self.pkgsend_bulk(self.durl1, self.example_pkg10)
+                
+                sign_args = "-k %(key)s -c %(cert)s -i %(i1)s %(pkg)s" % {
+                    "key": os.path.join(self.keys_dir, "cs1_p1_ta3_key.pem"),
+                    "cert": os.path.join(self.cs_dir, "cs1_p1_ta3_cert.pem"),
+                    "i1": os.path.join(self.chain_certs_dir,
+                        "ch1_pubCA1_cert.pem"),
+                    "pkg": plist[0]
+                }
+                self.pkgsign(self.durl1, sign_args, exit=1)
+
+        def test_expired_certs(self):
+                """Test that expiration dates on the signing cert are
+                ignored."""
+
+                ca_path = os.path.join(os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta3_cert.pem"))
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([ca_path], ca=True)
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+                sign_args = "-k %(key)s -c %(cert)s %(name)s" % {
+                        "name": plist[0],
+                        "key": os.path.join(self.keys_dir,
+                            "cs3_p1_ta3_key.pem"),
+                        "cert": os.path.join(self.cs_dir, "cs3_p1_ta3_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+
+                self.pkg_image_create(self.rurl1,
+                    additional_args="--set-property trust-anchor-directory='%s'" % os.path.join(self.path_to_certs, "ta3"))
+
+                self.pkg("set-property signature-policy require-signatures")
+                api_obj = self.get_img_api_obj()
+                # This should succeed because we currently ignore certificate
+                # expiration and start dates.
+                self._api_install(api_obj, ["example_pkg"])
+
+        def test_future_certs(self):
+                """Test that expiration dates on the signing cert are
+                ignored."""
+
+                ca_path = os.path.join(os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta3_cert.pem"))
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([ca_path], ca=True)
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+                sign_args = "-k %(key)s -c %(cert)s %(name)s" % {
+                        "name": plist[0],
+                        "key": os.path.join(self.keys_dir,
+                            "cs4_p1_ta3_key.pem"),
+                        "cert": os.path.join(self.cs_dir, "cs4_p1_ta3_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+
+                self.pkg_image_create(self.rurl1,
+                    additional_args="--set-property trust-anchor-directory='%s'" % os.path.join(self.path_to_certs, "ta3"))
+
+                self.pkg("set-property signature-policy require-signatures")
+                api_obj = self.get_img_api_obj()
+                # This should succeed because we currently ignore certificate
+                # expiration and start dates.
+                self._api_install(api_obj, ["example_pkg"])
+
+        def test_expired_ca_certs(self):
+                """Test that expiration dates on a CA cert are ignored."""
+
+                ca_path = os.path.join(os.path.join(self.pub_cas_dir,
+                    "pubCA3_ta3_cert.pem"))
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([ca_path], ca=True)
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+                sign_args = "-k %(key)s -c %(cert)s %(name)s" % {
+                        "name": plist[0],
+                        "key": os.path.join(self.keys_dir,
+                            "cs1_p3_ta3_key.pem"),
+                        "cert": os.path.join(self.cs_dir, "cs1_p3_ta3_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+
+                self.pkg_image_create(self.rurl1,
+                    additional_args="--set-property trust-anchor-directory='%s'" % os.path.join(self.path_to_certs, "ta3"))
+
+                self.pkg("set-property signature-policy require-signatures")
+                api_obj = self.get_img_api_obj()
+                # This should succeed because we currently ignore certificate
+                # expiration and start dates.
+                self._api_install(api_obj, ["example_pkg"])
+
+        def test_future_ca_certs(self):
+                """Test that expiration dates on a CA cert are ignored."""
+
+                ca_path = os.path.join(os.path.join(self.pub_cas_dir,
+                    "pubCA4_ta3_cert.pem"))
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([ca_path], ca=True)
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+                sign_args = "-k %(key)s -c %(cert)s %(name)s" % {
+                        "name": plist[0],
+                        "key": os.path.join(self.keys_dir,
+                            "cs1_p4_ta3_key.pem"),
+                        "cert": os.path.join(self.cs_dir, "cs1_p4_ta3_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+
+                self.pkg_image_create(self.rurl1,
+                    additional_args="--set-property trust-anchor-directory='%s'" % os.path.join(self.path_to_certs, "ta3"))
+
+                self.pkg("set-property signature-policy require-signatures")
+                api_obj = self.get_img_api_obj()
+                # This should succeed because we currently ignore certificate
+                # expiration and start dates.
+                self._api_install(api_obj, ["example_pkg"])
+
+        def test_cert_retrieval_failure(self):
+                """Test that a certificate that can't be retrieved doesn't
+                cause a traceback."""
+
+                ca_path = os.path.join(os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta3_cert.pem"))
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([ca_path], ca=True)
+
+                plist = self.pkgsend_bulk(self.rurl1, self.var_pkg)
+                sign_args = "-k %(key)s -c %(cert)s %(name)s" % {
+                        "name": plist[0],
+                        "key": os.path.join(self.keys_dir,
+                            "cs1_p1_ta3_key.pem"),
+                        "cert": os.path.join(self.cs_dir, "cs1_p1_ta3_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+
+                self.dcs[1].start()
+                
+                self.pkg_image_create(self.durl1,
+                    additional_args="--set-property trust-anchor-directory='%s'" % os.path.join(self.path_to_certs, "ta3"))
+
+                self.pkg("info -r var_pkg")
+                self.dcs[1].stop()
+                self.pkg("set-property signature-policy require-signatures")
+                api_obj = self.get_img_api_obj()
+                # This should succeed because we currently ignore certificate
+                # expiration and start dates.
+                self.assertRaises(apx.TransportError, self._api_install,
+                    api_obj, ["var_pkg"], refresh_catalogs=False)
+                # Test that a TransportError from certificate retrieval is
+                # handled correctly.
+                self.pkg("install --no-refresh var_pkg", exit=1)
+
+        def test_manual_pub_cert_approval(self):
+                ca_path = os.path.join(os.path.join(self.pub_cas_dir,
+                    "pubCA1_ta3_cert.pem"))
+                r = self.get_repo(self.dcs[1].get_repodir())
+                r.add_signing_certs([ca_path], ca=True)
+
+                plist = self.pkgsend_bulk(self.rurl1, self.example_pkg10)
+                sign_args = "-k %(key)s -c %(cert)s %(name)s" % {
+                        "name": plist[0],
+                        "key": os.path.join(self.keys_dir,
+                            "cs1_p1_ta3_key.pem"),
+                        "cert": os.path.join(self.cs_dir, "cs1_p1_ta3_cert.pem")
+                }
+                self.pkgsign(self.rurl1, sign_args)
+
+                self.pkg_image_create(self.rurl1,
+                    additional_args="--set-property signature-policy=require-signatures")
+                self.pkg("set-publisher --approve-ca-cert %s test" % ca_path)
+                api_obj = self.get_img_api_obj()
+                self._api_install(api_obj, ["example_pkg"])
--- a/src/tests/cli/t_util_merge.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/tests/cli/t_util_merge.py	Mon Aug 16 16:48:50 2010 -0700
@@ -149,12 +149,6 @@
                             "repository's configuration data is not "
                             "valid:\n%s") % e)
 
-        def merge(self, args=misc.EmptyI, exit=0):
-                prog = os.path.realpath(os.path.join(path_to_pub_util,
-                    "merge.py"))
-                cmd = "%s %s" % (prog, " ".join(args))
-                self.cmdline_run(cmd, exit=exit)
-
         def test_0_merge(self):
                 """Verify that merge functionality works as expected."""
 
--- a/src/tests/cli/t_util_update_file_layout.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/tests/cli/t_util_update_file_layout.py	Mon Aug 16 16:48:50 2010 -0700
@@ -20,8 +20,9 @@
 # CDDL HEADER END
 #
 
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+#
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+#
 
 import testutils
 if __name__ == "__main__":
@@ -44,13 +45,15 @@
 
         def setUp(self):
                 pkg5unittest.CliTestCase.setUp(self)
+                self.base_dir = os.path.join(self.test_root, "fm")
+                os.mkdir(self.base_dir)
 
         @staticmethod
         def old_hash(s):
                 return os.path.join(s[0:2], s[2:8], s)
 
         def touch_old_file(self, s):
-                p = os.path.join(self.test_root, self.old_hash(s))
+                p = os.path.join(self.base_dir, self.old_hash(s))
                 if not os.path.exists(os.path.dirname(p)):
                         os.makedirs(os.path.dirname(p))
                 fh = open(p, "wb")
@@ -77,7 +80,7 @@
 
                 old_paths = [self.touch_old_file(h) for h in hashes]
 
-                self.update_file_layout(self.test_root)
+                self.update_file_layout(self.base_dir)
                 for p in old_paths:
                         if os.path.exists(p):
                                 raise RuntimeError("%s should not exist" % p)
@@ -86,13 +89,13 @@
                                     "exist")
                 l = layout.get_preferred_layout()
                 for h in hashes:
-                        if not os.path.exists(os.path.join(self.test_root,
+                        if not os.path.exists(os.path.join(self.base_dir,
                             l.lookup(h))):
                                 raise RuntimeError("file for %s is missing" % h)
 
-                self.update_file_layout(self.test_root)
+                self.update_file_layout(self.base_dir)
                 for h in hashes:
-                        if not os.path.exists(os.path.join(self.test_root,
+                        if not os.path.exists(os.path.join(self.base_dir,
                             l.lookup(h))):
                                 raise RuntimeError("file for %s is missing" % h)
 
@@ -102,10 +105,10 @@
 
                 self.update_file_layout("", exit=2)
                 self.update_file_layout("%s %s" %
-                    (self.test_root, self.test_root), exit=2)
+                    (self.base_dir, self.base_dir), exit=2)
                 self.update_file_layout("/foo/doesntexist/", exit=2)
 
-                empty_dir = tempfile.mkdtemp(dir=self.test_root)
+                empty_dir = tempfile.mkdtemp(dir=self.base_dir)
                 self.update_file_layout(empty_dir)
                  
 if __name__ == "__main__":
--- a/src/tests/pkg5unittest.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/tests/pkg5unittest.py	Mon Aug 16 16:48:50 2010 -0700
@@ -27,6 +27,7 @@
 import difflib
 import errno
 import gettext
+import hashlib
 import os
 import pprint
 import shutil
@@ -46,6 +47,8 @@
 EmptyI = tuple()
 EmptyDict = dict()
 
+path_to_pub_util = "../util/publish"
+
 #
 # These are initialized by pkg5testenv.setup_environment.
 #
@@ -186,6 +189,13 @@
         #
         test_root = property(fget=lambda self: self.__test_root)
 
+        def __get_ro_data_root(self):
+                if not self.__test_root:
+                        return None
+                return os.path.join(self.__test_root, "ro_data")
+        
+        ro_data_root = property(fget=__get_ro_data_root)
+
         def cmdline_run(self, cmdline, comment="", coverage=True, exit=0,
             handle=False, out=False, prefix="", raise_error=True, su_wrap=None):
                 wrapper = ""
@@ -210,7 +220,6 @@
                 if handle:
                         # Do nothing more.
                         return p
-
                 self.output, self.errout = p.communicate()
                 retcode = p.returncode
                 self.debugresult(retcode, exit, self.output)
@@ -301,6 +310,8 @@
                 except OSError, e:
                         if e.errno != errno.EEXIST:
                                 raise e
+                shutil.copytree(os.path.join(self.__pwd, "ro_data"),
+                    self.ro_data_root)
                 #
                 # TMPDIR affects the behavior of mkdtemp and mkstemp.
                 # Setting this here should ensure that tests will make temp
@@ -552,6 +563,16 @@
                 self.debugfilecreate(content, t_path)
                 return t_path
 
+        @staticmethod
+        def calc_file_hash(pth):
+                # Find the hash of the file.
+                fh = open(pth, "rb")
+                s = fh.read()
+                fh.close()
+                hsh = hashlib.sha1()
+                hsh.update(s)
+                return hsh.hexdigest()
+
         def reduceSpaces(self, string):
                 """Reduce runs of spaces down to a single space."""
                 return re.sub(" +", " ", string)
@@ -1357,6 +1378,18 @@
                 return self.cmdline_run(cmdline, comment=comment, exit=exit,
                     su_wrap=su_wrap)
 
+        def pkgsign(self, depot_url, command, exit=0, comment=""):
+                args = []
+                if depot_url:
+                        args.append("-s %s" % depot_url)
+
+                if command:
+                        args.append(command)
+
+                cmdline = "%s/usr/bin/pkgsign %s" % (g_proto_area,
+                    " ".join(args))
+                return self.cmdline_run(cmdline, comment=comment, exit=exit)
+
         def pkgsend(self, depot_url="", command="", exit=0, comment="",
             retry400=True):
                 args = []
@@ -1375,7 +1408,7 @@
                 errout = self.errout
 
                 cmdop = command.split(' ')[0]
-                if cmdop == "open" and retcode == 0:
+                if cmdop in ("open", "append") and retcode == 0:
                         out = out.rstrip()
                         assert out.startswith("export PKG_TRANS_ID=")
                         arr = out.split("=")
@@ -1497,6 +1530,12 @@
 
                 return plist
 
+        def merge(self, args=EmptyI, exit=0):
+                prog = os.path.realpath(os.path.join(path_to_pub_util,
+                    "merge.py"))
+                cmd = "%s %s" % (prog, " ".join(args))
+                self.cmdline_run(cmd, exit=exit)
+
         def copy_repository(self, src, src_pub, dest, dest_pub):
                 """Copies the packages from the src repository to a new
                 destination repository that will be created at dest.  In
@@ -1553,16 +1592,21 @@
                                 msrc.close()
                                 mdest.close()
 
+        def get_img_manifest_path(self, pfmri, img_path=None):
+                """Returns the path to the manifest for the fiven fmri."""
+
+                if not img_path:
+                        img_path = self.get_img_path()
+
+                return os.path.join(img_path, "var", "pkg", "pkg",
+                    pfmri.get_dir_path(), "manifest")
+
         def get_img_manifest(self, pfmri, img_path=None):
                 """Retrieves the client's cached copy of the manifest for the
                 given package FMRI and returns it as a string.  Callers are
                 responsible for all error handling."""
 
-                if not img_path:
-                        img_path = self.get_img_path()
-
-                mpath = os.path.join(img_path, "var", "pkg", "pkg",
-                    pfmri.get_dir_path(), "manifest")
+                mpath = self.get_img_manifest_path(pfmri, img_path)
                 with open(mpath, "rb") as f:
                         return f.read()
 
@@ -1623,7 +1667,8 @@
         def validate_html_file(self, fname, exit=0, comment="",
             options="-quiet -utf8"):
                 cmdline = "tidy %s %s" % (options, fname)
-                return self.cmdline_run(cmdline, comment=comment, exit=exit)
+                return self.cmdline_run(cmdline, comment=comment,
+                    coverage=False, exit=exit)
 
         def create_repo(self, repodir, properties=EmptyI):
                 """ Convenience routine to help subclasses create a package
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/generate_certs.py	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,273 @@
+#!/usr/bin/python2.6
+#
+# 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) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+import os
+import shutil
+import subprocess
+import sys
+
+# Locations defined in openssl.cnf
+output_dir = "./produced"
+cnf_file = "openssl.cnf"
+mk_file = "Makefile"
+
+subj_str = "/C=US/ST=California/L=Menlo Park/O=pkg5/CN=%s/emailAddress=%s"
+
+def convert_pem_to_text(tmp_pth, out_pth, kind="x509"):
+        """Convert a pem file to a human friendly text file."""
+
+        assert not os.path.exists(out_pth)
+        
+        cmd = ["openssl", kind, "-in", tmp_pth,
+            "-text"]
+
+        fh = open(out_pth, "wb")
+        p = subprocess.Popen(cmd, stdout=fh)
+        assert p.wait() == 0
+        fh.close()
+
+def make_ca_cert(new_loc, new_name, parent_loc, parent_name, ext="v3_ca",
+    expired=False, future=False):
+        """Create a new CA cert."""
+
+        cmd = ["openssl", "req", "-new", "-nodes",
+            "-keyout", "./keys/%s_key.pem" % new_name,
+            "-out", "./%s/%s.csr" % (new_loc, new_name),
+            "-sha256", "-subj", subj_str % (new_name, new_name)]
+        p = subprocess.Popen(cmd)
+        assert p.wait() == 0
+
+        cmd = ["openssl", "ca", "-policy", "policy_anything",
+            "-extensions", ext,
+            "-out", "./%s/%s_cert.pem" % (new_loc, new_name),
+            "-in", "./%s/%s.csr" % (new_loc, new_name),
+            "-cert", "./%s/%s_cert.pem" % (parent_loc, parent_name),
+            "-outdir", "./%s" % new_loc,
+            "-keyfile", "./keys/%s_key.pem" % parent_name, "-config", cnf_file,
+            "-batch"]
+        if expired:
+                cmd.append("-startdate")
+                cmd.append("090101010101Z")
+                cmd.append("-enddate")
+                cmd.append("090102010101Z")
+        elif future:
+                cmd.append("-startdate")
+                cmd.append("350101010101Z")
+                cmd.append("-enddate")
+                cmd.append("350102010101Z")
+        else:
+                cmd.append("-days")
+                cmd.append("1000")
+        p = subprocess.Popen(cmd)
+        assert p.wait() == 0
+
+
+def make_cs_cert(new_loc, new_name, parent_loc, parent_name, ext="v3_req",
+    expired=False, future=False):
+        """Create a new code signing cert."""
+
+        cmd = ["openssl", "req", "-new", "-nodes",
+            "-keyout", "./keys/%s_key.pem" % new_name,
+            "-out", "./%s/%s.csr" % (new_loc, new_name),
+            "-sha256", "-subj", subj_str % (new_name, new_name)]
+        p = subprocess.Popen(cmd)
+        assert p.wait() == 0
+
+        cmd = ["openssl", "ca", "-policy", "policy_anything",
+            "-extensions", ext,
+            "-out", "./%s/%s_cert.pem" % (new_loc, new_name),
+            "-in", "./%s/%s.csr" % (new_loc, new_name),
+            "-cert", "./%s/%s_cert.pem" % (parent_loc, parent_name),
+            "-outdir", "./%s" % new_loc,
+            "-keyfile", "./keys/%s_key.pem" % parent_name, "-config", cnf_file,
+            "-batch"]
+        if expired:
+                cmd.append("-startdate")
+                cmd.append("090101010101Z")
+                cmd.append("-enddate")
+                cmd.append("090102010101Z")
+        elif future:
+                cmd.append("-startdate")
+                cmd.append("350101010101Z")
+                cmd.append("-enddate")
+                cmd.append("350102010101Z")
+        else:
+                cmd.append("-days")
+                cmd.append("1000")
+        p = subprocess.Popen(cmd)
+        assert p.wait() == 0
+
+def make_trust_anchor(name):
+        """Make a new trust anchor."""
+
+        cmd = ["openssl", "req", "-new", "-x509", "-nodes",
+            "-keyout", "./keys/%s_key.pem" % name,
+            "-subj", subj_str % (name, name),
+            "-out", "./%s/%s_cert.tmp" % (name, name), "-days", "1000",
+            "-sha256"]
+
+        os.mkdir("./%s" % name)
+
+        p = subprocess.Popen(cmd)
+        assert p.wait() == 0
+        convert_pem_to_text("./%s/%s_cert.tmp" % (name, name),
+            "./%s/%s_cert.pem" % (name, name))
+
+        try:
+                os.link("./%s/%s_cert.pem" % (name, name),
+                    "./trust_anchors/%s_cert.pem" % name)
+        except:
+                shutil.copy("./%s/%s_cert.pem" % (name, name),
+                    "./trust_anchors/%s_cert.pem" % name)
+
+def revoke_cert(ca, revoked_cert, ca_dir=None, cert_dir="code_signing_certs"):
+        """Revoke a certificate using the CA given."""
+
+        if not ca_dir:
+                ca_dir = ca
+        cmd = ["openssl", "ca", "-keyfile", "keys/%s_key.pem" % ca,
+            "-cert", "%s/%s_cert.pem" % (ca_dir, ca),
+            "-config", cnf_file,
+            "-revoke", "%s/%s_cert.pem" % (cert_dir, revoked_cert)]
+        p = subprocess.Popen(cmd)
+        assert p.wait() == 0
+
+        cmd = ["openssl", "ca", "-gencrl",
+            "-keyfile", "keys/%s_key.pem" % ca,
+            "-cert", "%s/%s_cert.pem" % (ca_dir, ca),
+            "-config", cnf_file,
+            "-out", "crl/%s_crl.tmp" % ca,
+            "-crldays", "1000"]
+        p = subprocess.Popen(cmd)
+        assert p.wait() == 0
+        convert_pem_to_text("crl/%s_crl.tmp" % ca, "crl/%s_crl.pem" % ca,
+            kind="crl")
+
+        
+if __name__ == "__main__":
+        # Remove any existing output from previous runs of this program.
+        if os.path.isdir(output_dir):
+                shutil.rmtree(output_dir)
+        os.mkdir(output_dir)
+        shutil.copy(cnf_file, os.path.join(output_dir, cnf_file))
+        os.chdir(output_dir)
+
+        # Set up the needed files and directories.
+        fh = open("index", "wb")
+        fh.close()
+
+        fh = open("serial", "wb")
+        fh.write("01\n")
+        fh.close()
+
+        os.mkdir("crl")
+        os.mkdir("keys")
+        os.mkdir("trust_anchors")
+        os.mkdir("inter_certs")
+        os.mkdir("publisher_cas")
+        os.mkdir("chain_certs")
+        os.mkdir("code_signing_certs")
+
+        # Make a length 7 chain.
+        make_trust_anchor("ta1")
+        make_ca_cert("inter_certs", "i1_ta1", "trust_anchors", "ta1")
+        make_ca_cert("inter_certs", "i2_ta1", "inter_certs", "i1_ta1")
+        make_ca_cert("publisher_cas", "pubCA1_ta1", "inter_certs", "i2_ta1")
+        make_ca_cert("chain_certs", "ch1_pubCA1", "publisher_cas", "pubCA1_ta1")
+        make_ca_cert("chain_certs", "ch2_pubCA1", "chain_certs", "ch1_pubCA1")
+        make_cs_cert("code_signing_certs", "cs1_pubCA1",
+            "chain_certs", "ch2_pubCA1")
+        # Make a chain where the publisher CA has revoked the code signing cert.
+        make_cs_cert("code_signing_certs", "cs2_pubCA1",
+            "chain_certs", "ch2_pubCA1", ext="pubCA1_ta1_crl")
+        revoke_cert("pubCA1_ta1", "cs2_pubCA1", ca_dir="publisher_cas")
+        # Make a chain where the chain cert has revoked the code signing cert.
+        make_cs_cert("code_signing_certs", "cs3_pubCA1",
+            "chain_certs", "ch2_pubCA1", ext="ch1_ta1_crl")
+        revoke_cert("ch1_pubCA1", "cs3_pubCA1", ca_dir="chain_certs")
+        # Make a chain where the chain cert has an unsupported critical
+        # extension.
+        make_ca_cert("chain_certs", "ch2.2_pubCA1", "chain_certs", "ch1_pubCA1",
+            ext="issuer_ext_ca")
+        make_cs_cert("code_signing_certs", "cs4_pubCA1",
+            "chain_certs", "ch2.2_pubCA1")
+
+        # Make a length 2 chain
+        make_trust_anchor("ta2")
+        make_cs_cert("code_signing_certs", "cs1_ta2", "trust_anchors", "ta2")
+
+        # Make a length 3 chain
+        make_trust_anchor("ta3")
+        make_ca_cert("publisher_cas", "pubCA1_ta3", "trust_anchors", "ta3")
+        make_cs_cert("code_signing_certs", "cs1_p1_ta3",
+            "publisher_cas", "pubCA1_ta3")
+        # Add a certificate to the length 3 chain with an unsupported critical
+        # extension.
+        make_cs_cert("code_signing_certs", "cs2_p1_ta3",
+            "publisher_cas", "pubCA1_ta3", ext="issuer_ext")
+        # Add a certificate to the length 3 chain that has already expired.
+        make_cs_cert("code_signing_certs", "cs3_p1_ta3",
+            "publisher_cas", "pubCA1_ta3", expired=True)
+        # Add a certificate to the length 3 chain that is in the future.
+        make_cs_cert("code_signing_certs", "cs4_p1_ta3",
+            "publisher_cas", "pubCA1_ta3", future=True)
+        # Make a chain where the CA has an unsupported critical extension.
+        make_ca_cert("publisher_cas", "pubCA2_ta3", "trust_anchors", "ta3",
+            ext="issuer_ext_ca")
+        make_cs_cert("code_signing_certs", "cs1_p2_ta3",
+            "publisher_cas", "pubCA2_ta3")
+        # Make a chain where the CA is expired but the CS is current.
+        make_ca_cert("publisher_cas", "pubCA3_ta3", "trust_anchors", "ta3",
+            expired=True)
+        make_cs_cert("code_signing_certs", "cs1_p3_ta3",
+            "publisher_cas", "pubCA3_ta3")
+        # Make a chain where the CA is in the future but the CS is current.
+        make_ca_cert("publisher_cas", "pubCA4_ta3", "trust_anchors", "ta3",
+            future=True)
+        make_cs_cert("code_signing_certs", "cs1_p4_ta3",
+            "publisher_cas", "pubCA4_ta3")
+
+        # Revoke a code signing certificate from the publisher.
+        make_trust_anchor("ta4")
+        make_ca_cert("publisher_cas", "pubCA1_ta4", "trust_anchors", "ta4")
+        make_cs_cert("code_signing_certs", "cs1_ta4",
+            "publisher_cas", "pubCA1_ta4", ext="crl_ext")
+        revoke_cert("pubCA1_ta4", "cs1_ta4", ca_dir="publisher_cas")
+        make_cs_cert("code_signing_certs", "cs2_ta4",
+            "publisher_cas", "pubCA1_ta4", ext="bad_crl")
+        make_cs_cert("code_signing_certs", "cs3_ta4",
+            "publisher_cas", "pubCA1_ta4", ext="bad_crl_loc")
+
+        # Revoke a CA cert from the trust anchor
+        make_trust_anchor("ta5")
+        make_ca_cert("publisher_cas", "pubCA1_ta5", "trust_anchors", "ta5",
+            ext="crl_ca")
+        make_cs_cert("code_signing_certs", "cs1_ta5",
+            "publisher_cas", "pubCA1_ta5")
+        revoke_cert("ta5", "pubCA1_ta5", cert_dir="publisher_cas")
+
+        os.remove(cnf_file)
+        os.chdir("../")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/openssl.cnf	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,169 @@
+#
+# 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) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+# OpenSSL configuration file for use with generate_certs.py.
+
+HOME                    = .
+RANDFILE                = $ENV::HOME/.rnd
+
+[ ca ]
+default_ca      = CA_default
+
+[ CA_default ]
+dir             = .
+crl_dir         = $dir/crl
+database        = $dir/index
+serial          = $dir/serial
+
+x509_extensions = usr_cert
+unique_subject  = no
+
+default_md      = sha256
+preserve        = no
+
+policy          = policy_match
+
+# For the 'anything' policy
+# At this point in time, you must list all acceptable 'object'
+# types.
+[ policy_anything ]
+countryName             = optional
+stateOrProvinceName     = optional
+localityName            = optional
+organizationName        = optional
+organizationalUnitName  = optional
+commonName              = supplied
+emailAddress            = optional
+
+####################################################################
+[ req ]
+default_bits            = 2048
+default_keyfile         = ./private/ca-key.pem
+default_md              = sha256
+
+prompt                  = no
+distinguished_name      = root_ca_distinguished_name
+
+x509_extensions = v3_ca
+string_mask = nombstr
+
+[ root_ca_distinguished_name ]
+commonName = ta1
+countryName = US
+stateOrProvinceName = California
+localityName = Menlo Park
+0.organizationName = pkg5
+emailAddress = ta1@pkg5
+
+[ usr_cert ]
+
+# These extensions are added when 'ca' signs a request.
+
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer:always
+
+[ v3_req ]
+
+# Extensions to add to a certificate request
+
+basicConstraints = critical,CA:FALSE
+keyUsage = digitalSignature
+
+[ v3_ca ]
+
+
+# Extensions for a typical CA
+
+# PKIX recommendation.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always,issuer:always
+basicConstraints = critical,CA:true
+
+[ issuer_ext ]
+
+# Used for a code signing cert with an unsupported critical extension.
+
+basicConstraints = critical,CA:FALSE
+issuerAltName = critical,issuer:copy
+
+[ issuer_ext_ca ]
+
+# Used for a CA cert with an unsupported critical extension.
+
+basicConstraints = critical,CA:TRUE
+issuerAltName = critical,issuer:copy
+
+[ crl_ext ]
+
+# Used for testing certificate revocation.
+
+basicConstraints = critical,CA:FALSE
+crlDistributionPoints = URI:http://localhost:12001/file/0/pubCA1_ta4_crl.pem
+
+[ pubCA1_ta1_crl ]
+
+# Used for testing certificate revocation.
+
+basicConstraints = critical,CA:FALSE
+crlDistributionPoints = URI:http://localhost:12001/file/0/pubCA1_ta1_crl.pem
+
+[ ch1_ta1_crl ]
+
+# Used for testing certificate revocation at the level of a chain certificate.
+
+basicConstraints = critical,CA:FALSE
+crlDistributionPoints = URI:http://localhost:12001/file/0/ch1_pubCA1_crl.pem
+
+[ crl_ca ]
+
+# Used for testing CA certificate revocation by a trust anchor.
+
+# PKIX recommendation.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always,issuer:always
+basicConstraints = critical,CA:true
+crlDistributionPoints = URI:http://localhost:12001/file/0/ta5_crl.pem
+
+[ bad_crl ]
+
+# Used for testing a CRL with a bad file format.
+
+# PKIX recommendation.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always,issuer:always
+
+basicConstraints = critical,CA:false
+
+crlDistributionPoints = URI:http://localhost:12001/file/0/example_file
+
+[ bad_crl_loc ]
+
+# PKIX recommendation.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always,issuer:always
+
+basicConstraints = critical,CA:false
+
+crlDistributionPoints = URI:foo://bar/baz
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/chain_certs/04.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,63 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 4 (0x4)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta1/emailAddress=pubCA1_ta1
+        Validity
+            Not Before: Aug  4 20:59:23 2010 GMT
+            Not After : Apr 30 20:59:23 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ch1_pubCA1/emailAddress=ch1_pubCA1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:df:49:4c:8c:dd:25:e1:4d:81:08:01:65:e4:37:
+                    db:d4:87:be:f1:ca:f3:c2:e5:82:b0:d2:c9:09:a4:
+                    3d:41:2a:c9:40:c5:55:aa:0b:8f:41:42:82:3c:2e:
+                    47:23:23:88:e5:55:7e:3f:71:ae:c9:f9:d8:bf:b9:
+                    e0:4b:74:6d:82:af:20:f0:8c:03:4b:fb:d9:40:99:
+                    bf:94:90:f9:00:36:be:a7:97:0d:af:6f:e3:e6:43:
+                    0c:22:a7:2b:92:dd:24:8f:78:2e:dd:5a:6d:05:77:
+                    b6:16:d1:8a:07:4f:a1:af:71:c3:7a:b4:d3:54:2e:
+                    f5:9a:d3:b1:40:7f:e0:35:71
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                D1:05:EC:55:23:1D:1E:53:EC:AE:71:88:8C:12:C2:AE:14:FE:12:5E
+            X509v3 Authority Key Identifier: 
+                keyid:E8:81:62:06:D5:A6:C6:2E:6C:2A:4F:A3:21:42:59:CD:19:5B:32:ED
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=i2_ta1/emailAddress=i2_ta1
+                serial:03
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        75:00:7d:53:6d:fb:70:10:81:5c:71:2e:c9:17:29:7b:fb:b8:
+        b0:97:c4:49:79:44:9e:ab:50:b5:65:aa:fe:99:18:2d:29:af:
+        8d:72:77:72:aa:ca:a5:1e:47:a9:a1:8d:a2:f5:10:ec:d5:a4:
+        95:d9:e0:1f:37:94:c3:e5:c5:75:17:d5:00:55:a5:d9:7c:38:
+        c2:07:18:b3:f3:48:33:15:7c:25:2d:61:16:71:a1:dc:7f:82:
+        85:c0:af:62:48:cf:ca:29:69:23:c5:cc:9e:dd:fa:40:3f:b9:
+        b5:1c:82:41:fa:53:50:f9:03:eb:42:de:a5:b4:bd:78:01:dc:
+        86:9b
+-----BEGIN CERTIFICATE-----
+MIIDMTCCApqgAwIBAgIBBDANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0ExX3RhMTEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0ExX3RhMTAeFw0xMDA4MDQyMDU5MjNaFw0xMzA0MzAyMDU5MjNaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjaDFfcHViQ0ExMRkwFwYJKoZIhvcN
+AQkBFgpjaDFfcHViQ0ExMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfSUyM
+3SXhTYEIAWXkN9vUh77xyvPC5YKw0skJpD1BKslAxVWqC49BQoI8LkcjI4jlVX4/
+ca7J+di/ueBLdG2CryDwjANL+9lAmb+UkPkANr6nlw2vb+PmQwwipyuS3SSPeC7d
+Wm0Fd7YW0YoHT6GvccN6tNNULvWa07FAf+A1cQIDAQABo4HOMIHLMB0GA1UdDgQW
+BBTRBexVIx0eU+yucYiMEsKuFP4SXjCBmAYDVR0jBIGQMIGNgBTogWIG1abGLmwq
+T6MhQlnNGVsy7aFypHAwbjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3Ju
+aWExEzARBgNVBAcTCk1lbmxvIFBhcmsxDTALBgNVBAoTBHBrZzUxDzANBgNVBAMU
+BmkyX3RhMTEVMBMGCSqGSIb3DQEJARYGaTJfdGExggEDMA8GA1UdEwEB/wQFMAMB
+Af8wDQYJKoZIhvcNAQELBQADgYEAdQB9U237cBCBXHEuyRcpe/u4sJfESXlEnqtQ
+tWWq/pkYLSmvjXJ3cqrKpR5HqaGNovUQ7NWkldngHzeUw+XFdRfVAFWl2Xw4wgcY
+s/NIMxV8JS1hFnGh3H+ChcCvYkjPyilpI8XMnt36QD+5tRyCQfpTUPkD60LepbS9
+eAHchps=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/chain_certs/05.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,63 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 5 (0x5)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ch1_pubCA1/emailAddress=ch1_pubCA1
+        Validity
+            Not Before: Aug  4 20:59:23 2010 GMT
+            Not After : Apr 30 20:59:23 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ch2_pubCA1/emailAddress=ch2_pubCA1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:b1:17:94:03:99:12:09:1e:f2:3f:76:e3:63:11:
+                    75:3c:41:46:ca:3f:2c:9d:2f:e3:2f:39:90:63:a1:
+                    d0:31:e1:b7:eb:94:f3:c5:7c:2b:4a:da:9b:d2:28:
+                    29:68:72:4e:c8:53:0c:84:9b:6b:a1:7d:63:49:3b:
+                    65:e6:be:11:a5:ba:41:5e:74:0d:16:ae:95:26:02:
+                    79:ca:38:df:13:e9:f7:97:52:cd:d3:85:49:ec:cf:
+                    75:cd:54:13:f0:15:0d:65:ee:ea:e5:7b:3b:63:3e:
+                    5f:a9:4b:56:d3:10:1d:9b:47:ed:2f:46:54:53:19:
+                    b0:2e:63:cd:12:f4:40:4a:6b
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                3D:8C:8F:DF:07:E7:F3:5E:C1:50:68:37:8B:8A:DB:BD:15:5B:4C:2E
+            X509v3 Authority Key Identifier: 
+                keyid:D1:05:EC:55:23:1D:1E:53:EC:AE:71:88:8C:12:C2:AE:14:FE:12:5E
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=pubCA1_ta1/emailAddress=pubCA1_ta1
+                serial:04
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        aa:60:e0:f8:bb:6d:07:de:5a:d1:58:07:27:64:29:68:49:2b:
+        42:67:25:da:c0:dc:52:82:98:b8:1b:79:a9:65:2a:fe:c7:78:
+        46:ca:76:1a:fe:b0:b1:9f:2f:d3:4c:4b:02:65:39:57:2a:a1:
+        48:ba:6b:9d:f7:67:80:70:8f:38:00:0f:4e:b2:57:ac:59:ad:
+        97:b7:46:67:39:3d:75:12:ff:8f:ac:d9:65:0f:a7:05:a5:1e:
+        49:94:a5:a1:44:4f:e7:ba:b9:af:5d:2c:3d:29:cd:a2:e2:c5:
+        2c:ac:1f:1e:7f:64:bf:97:d4:a9:6c:d1:91:9c:50:20:af:50:
+        ad:6b
+-----BEGIN CERTIFICATE-----
+MIIDOTCCAqKgAwIBAgIBBTANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKY2gxX3B1YkNBMTEZMBcGCSqGSIb3DQEJARYKY2gx
+X3B1YkNBMTAeFw0xMDA4MDQyMDU5MjNaFw0xMzA0MzAyMDU5MjNaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjaDJfcHViQ0ExMRkwFwYJKoZIhvcN
+AQkBFgpjaDJfcHViQ0ExMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxF5QD
+mRIJHvI/duNjEXU8QUbKPyydL+MvOZBjodAx4bfrlPPFfCtK2pvSKClock7IUwyE
+m2uhfWNJO2XmvhGlukFedA0WrpUmAnnKON8T6feXUs3ThUnsz3XNVBPwFQ1l7url
+eztjPl+pS1bTEB2bR+0vRlRTGbAuY80S9EBKawIDAQABo4HWMIHTMB0GA1UdDgQW
+BBQ9jI/fB+fzXsFQaDeLitu9FVtMLjCBoAYDVR0jBIGYMIGVgBTRBexVIx0eU+yu
+cYiMEsKuFP4SXqF6pHgwdjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3Ju
+aWExEzARBgNVBAcTCk1lbmxvIFBhcmsxDTALBgNVBAoTBHBrZzUxEzARBgNVBAMU
+CnB1YkNBMV90YTExGTAXBgkqhkiG9w0BCQEWCnB1YkNBMV90YTGCAQQwDwYDVR0T
+AQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQCqYOD4u20H3lrRWAcnZCloSStC
+ZyXawNxSgpi4G3mpZSr+x3hGynYa/rCxny/TTEsCZTlXKqFIumud92eAcI84AA9O
+slesWa2Xt0ZnOT11Ev+PrNllD6cFpR5JlKWhRE/nurmvXSw9Kc2i4sUsrB8ef2S/
+l9SpbNGRnFAgr1Ctaw==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/chain_certs/09.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,55 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 9 (0x9)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ch1_pubCA1/emailAddress=ch1_pubCA1
+        Validity
+            Not Before: Aug  4 20:59:24 2010 GMT
+            Not After : Apr 30 20:59:24 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ch2.2_pubCA1/emailAddress=ch2.2_pubCA1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:b8:4f:d8:46:38:cf:4d:f8:68:64:10:4a:2f:8b:
+                    2c:d6:5f:89:32:44:90:89:25:76:ff:54:65:59:d2:
+                    75:86:d0:94:cf:2d:f0:94:18:23:32:fd:ce:f4:6b:
+                    a0:c7:0e:f9:aa:18:f9:0b:fe:e7:85:aa:ff:8a:e1:
+                    04:53:f9:a4:34:75:45:07:6f:f1:80:06:ca:c3:0f:
+                    3b:b4:45:97:fe:09:f5:17:18:6c:05:e9:34:68:b9:
+                    de:61:a3:ac:e1:22:0f:69:72:6f:a9:a8:64:cb:89:
+                    a3:3d:32:02:25:64:5f:49:1e:0f:50:47:14:f2:0a:
+                    bf:8c:72:57:44:f9:2e:9e:69
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 Issuer Alternative Name: critical
+                <EMPTY>
+
+    Signature Algorithm: sha256WithRSAEncryption
+        9c:a9:be:da:f7:df:71:83:f0:eb:cb:f1:a3:68:cf:e1:eb:7f:
+        a2:6d:1f:52:19:46:de:f1:8c:d0:1d:52:2b:a7:f0:70:2a:2f:
+        e6:7e:48:4b:2a:3f:68:4d:4d:c7:39:2a:bd:65:84:67:d1:73:
+        cd:a2:6f:38:59:29:2b:e4:71:ad:59:10:ff:ae:b2:c9:89:e1:
+        32:6e:87:6c:e2:6d:8c:24:d1:64:a8:19:3c:68:ee:b5:f2:f2:
+        5b:6c:36:0e:0f:85:3f:e6:9e:a1:6e:6e:2b:98:b4:94:3f:16:
+        a2:37:7b:45:bc:8f:b1:bc:e5:26:2b:dd:0d:55:34:1d:ee:7c:
+        70:a9
+-----BEGIN CERTIFICATE-----
+MIIChzCCAfCgAwIBAgIBCTANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKY2gxX3B1YkNBMTEZMBcGCSqGSIb3DQEJARYKY2gx
+X3B1YkNBMTAeFw0xMDA4MDQyMDU5MjRaFw0xMzA0MzAyMDU5MjRaMHoxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRUwEwYDVQQDFAxjaDIuMl9wdWJDQTExGzAZBgkqhkiG
+9w0BCQEWDGNoMi4yX3B1YkNBMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
+uE/YRjjPTfhoZBBKL4ss1l+JMkSQiSV2/1RlWdJ1htCUzy3wlBgjMv3O9Gugxw75
+qhj5C/7nhar/iuEEU/mkNHVFB2/xgAbKww87tEWX/gn1FxhsBek0aLneYaOs4SIP
+aXJvqahky4mjPTICJWRfSR4PUEcU8gq/jHJXRPkunmkCAwEAAaMhMB8wDwYDVR0T
+AQH/BAUwAwEB/zAMBgNVHRIBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4GBAJypvtr3
+33GD8OvL8aNoz+Hrf6JtH1IZRt7xjNAdUiun8HAqL+Z+SEsqP2hNTcc5Kr1lhGfR
+c82ibzhZKSvkca1ZEP+ussmJ4TJuh2zibYwk0WSoGTxo7rXy8ltsNg4PhT/mnqFu
+biuYtJQ/FqI3e0W8j7G85SYr3Q1VNB3ufHCp
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/chain_certs/ch1_pubCA1_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,63 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 4 (0x4)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta1/emailAddress=pubCA1_ta1
+        Validity
+            Not Before: Aug  4 20:59:23 2010 GMT
+            Not After : Apr 30 20:59:23 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ch1_pubCA1/emailAddress=ch1_pubCA1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:df:49:4c:8c:dd:25:e1:4d:81:08:01:65:e4:37:
+                    db:d4:87:be:f1:ca:f3:c2:e5:82:b0:d2:c9:09:a4:
+                    3d:41:2a:c9:40:c5:55:aa:0b:8f:41:42:82:3c:2e:
+                    47:23:23:88:e5:55:7e:3f:71:ae:c9:f9:d8:bf:b9:
+                    e0:4b:74:6d:82:af:20:f0:8c:03:4b:fb:d9:40:99:
+                    bf:94:90:f9:00:36:be:a7:97:0d:af:6f:e3:e6:43:
+                    0c:22:a7:2b:92:dd:24:8f:78:2e:dd:5a:6d:05:77:
+                    b6:16:d1:8a:07:4f:a1:af:71:c3:7a:b4:d3:54:2e:
+                    f5:9a:d3:b1:40:7f:e0:35:71
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                D1:05:EC:55:23:1D:1E:53:EC:AE:71:88:8C:12:C2:AE:14:FE:12:5E
+            X509v3 Authority Key Identifier: 
+                keyid:E8:81:62:06:D5:A6:C6:2E:6C:2A:4F:A3:21:42:59:CD:19:5B:32:ED
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=i2_ta1/emailAddress=i2_ta1
+                serial:03
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        75:00:7d:53:6d:fb:70:10:81:5c:71:2e:c9:17:29:7b:fb:b8:
+        b0:97:c4:49:79:44:9e:ab:50:b5:65:aa:fe:99:18:2d:29:af:
+        8d:72:77:72:aa:ca:a5:1e:47:a9:a1:8d:a2:f5:10:ec:d5:a4:
+        95:d9:e0:1f:37:94:c3:e5:c5:75:17:d5:00:55:a5:d9:7c:38:
+        c2:07:18:b3:f3:48:33:15:7c:25:2d:61:16:71:a1:dc:7f:82:
+        85:c0:af:62:48:cf:ca:29:69:23:c5:cc:9e:dd:fa:40:3f:b9:
+        b5:1c:82:41:fa:53:50:f9:03:eb:42:de:a5:b4:bd:78:01:dc:
+        86:9b
+-----BEGIN CERTIFICATE-----
+MIIDMTCCApqgAwIBAgIBBDANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0ExX3RhMTEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0ExX3RhMTAeFw0xMDA4MDQyMDU5MjNaFw0xMzA0MzAyMDU5MjNaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjaDFfcHViQ0ExMRkwFwYJKoZIhvcN
+AQkBFgpjaDFfcHViQ0ExMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfSUyM
+3SXhTYEIAWXkN9vUh77xyvPC5YKw0skJpD1BKslAxVWqC49BQoI8LkcjI4jlVX4/
+ca7J+di/ueBLdG2CryDwjANL+9lAmb+UkPkANr6nlw2vb+PmQwwipyuS3SSPeC7d
+Wm0Fd7YW0YoHT6GvccN6tNNULvWa07FAf+A1cQIDAQABo4HOMIHLMB0GA1UdDgQW
+BBTRBexVIx0eU+yucYiMEsKuFP4SXjCBmAYDVR0jBIGQMIGNgBTogWIG1abGLmwq
+T6MhQlnNGVsy7aFypHAwbjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3Ju
+aWExEzARBgNVBAcTCk1lbmxvIFBhcmsxDTALBgNVBAoTBHBrZzUxDzANBgNVBAMU
+BmkyX3RhMTEVMBMGCSqGSIb3DQEJARYGaTJfdGExggEDMA8GA1UdEwEB/wQFMAMB
+Af8wDQYJKoZIhvcNAQELBQADgYEAdQB9U237cBCBXHEuyRcpe/u4sJfESXlEnqtQ
+tWWq/pkYLSmvjXJ3cqrKpR5HqaGNovUQ7NWkldngHzeUw+XFdRfVAFWl2Xw4wgcY
+s/NIMxV8JS1hFnGh3H+ChcCvYkjPyilpI8XMnt36QD+5tRyCQfpTUPkD60LepbS9
+eAHchps=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/chain_certs/ch2.2_pubCA1_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,55 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 9 (0x9)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ch1_pubCA1/emailAddress=ch1_pubCA1
+        Validity
+            Not Before: Aug  4 20:59:24 2010 GMT
+            Not After : Apr 30 20:59:24 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ch2.2_pubCA1/emailAddress=ch2.2_pubCA1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:b8:4f:d8:46:38:cf:4d:f8:68:64:10:4a:2f:8b:
+                    2c:d6:5f:89:32:44:90:89:25:76:ff:54:65:59:d2:
+                    75:86:d0:94:cf:2d:f0:94:18:23:32:fd:ce:f4:6b:
+                    a0:c7:0e:f9:aa:18:f9:0b:fe:e7:85:aa:ff:8a:e1:
+                    04:53:f9:a4:34:75:45:07:6f:f1:80:06:ca:c3:0f:
+                    3b:b4:45:97:fe:09:f5:17:18:6c:05:e9:34:68:b9:
+                    de:61:a3:ac:e1:22:0f:69:72:6f:a9:a8:64:cb:89:
+                    a3:3d:32:02:25:64:5f:49:1e:0f:50:47:14:f2:0a:
+                    bf:8c:72:57:44:f9:2e:9e:69
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 Issuer Alternative Name: critical
+                <EMPTY>
+
+    Signature Algorithm: sha256WithRSAEncryption
+        9c:a9:be:da:f7:df:71:83:f0:eb:cb:f1:a3:68:cf:e1:eb:7f:
+        a2:6d:1f:52:19:46:de:f1:8c:d0:1d:52:2b:a7:f0:70:2a:2f:
+        e6:7e:48:4b:2a:3f:68:4d:4d:c7:39:2a:bd:65:84:67:d1:73:
+        cd:a2:6f:38:59:29:2b:e4:71:ad:59:10:ff:ae:b2:c9:89:e1:
+        32:6e:87:6c:e2:6d:8c:24:d1:64:a8:19:3c:68:ee:b5:f2:f2:
+        5b:6c:36:0e:0f:85:3f:e6:9e:a1:6e:6e:2b:98:b4:94:3f:16:
+        a2:37:7b:45:bc:8f:b1:bc:e5:26:2b:dd:0d:55:34:1d:ee:7c:
+        70:a9
+-----BEGIN CERTIFICATE-----
+MIIChzCCAfCgAwIBAgIBCTANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKY2gxX3B1YkNBMTEZMBcGCSqGSIb3DQEJARYKY2gx
+X3B1YkNBMTAeFw0xMDA4MDQyMDU5MjRaFw0xMzA0MzAyMDU5MjRaMHoxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRUwEwYDVQQDFAxjaDIuMl9wdWJDQTExGzAZBgkqhkiG
+9w0BCQEWDGNoMi4yX3B1YkNBMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
+uE/YRjjPTfhoZBBKL4ss1l+JMkSQiSV2/1RlWdJ1htCUzy3wlBgjMv3O9Gugxw75
+qhj5C/7nhar/iuEEU/mkNHVFB2/xgAbKww87tEWX/gn1FxhsBek0aLneYaOs4SIP
+aXJvqahky4mjPTICJWRfSR4PUEcU8gq/jHJXRPkunmkCAwEAAaMhMB8wDwYDVR0T
+AQH/BAUwAwEB/zAMBgNVHRIBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4GBAJypvtr3
+33GD8OvL8aNoz+Hrf6JtH1IZRt7xjNAdUiun8HAqL+Z+SEsqP2hNTcc5Kr1lhGfR
+c82ibzhZKSvkca1ZEP+ussmJ4TJuh2zibYwk0WSoGTxo7rXy8ltsNg4PhT/mnqFu
+biuYtJQ/FqI3e0W8j7G85SYr3Q1VNB3ufHCp
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/chain_certs/ch2_pubCA1_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,63 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 5 (0x5)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ch1_pubCA1/emailAddress=ch1_pubCA1
+        Validity
+            Not Before: Aug  4 20:59:23 2010 GMT
+            Not After : Apr 30 20:59:23 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ch2_pubCA1/emailAddress=ch2_pubCA1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:b1:17:94:03:99:12:09:1e:f2:3f:76:e3:63:11:
+                    75:3c:41:46:ca:3f:2c:9d:2f:e3:2f:39:90:63:a1:
+                    d0:31:e1:b7:eb:94:f3:c5:7c:2b:4a:da:9b:d2:28:
+                    29:68:72:4e:c8:53:0c:84:9b:6b:a1:7d:63:49:3b:
+                    65:e6:be:11:a5:ba:41:5e:74:0d:16:ae:95:26:02:
+                    79:ca:38:df:13:e9:f7:97:52:cd:d3:85:49:ec:cf:
+                    75:cd:54:13:f0:15:0d:65:ee:ea:e5:7b:3b:63:3e:
+                    5f:a9:4b:56:d3:10:1d:9b:47:ed:2f:46:54:53:19:
+                    b0:2e:63:cd:12:f4:40:4a:6b
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                3D:8C:8F:DF:07:E7:F3:5E:C1:50:68:37:8B:8A:DB:BD:15:5B:4C:2E
+            X509v3 Authority Key Identifier: 
+                keyid:D1:05:EC:55:23:1D:1E:53:EC:AE:71:88:8C:12:C2:AE:14:FE:12:5E
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=pubCA1_ta1/emailAddress=pubCA1_ta1
+                serial:04
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        aa:60:e0:f8:bb:6d:07:de:5a:d1:58:07:27:64:29:68:49:2b:
+        42:67:25:da:c0:dc:52:82:98:b8:1b:79:a9:65:2a:fe:c7:78:
+        46:ca:76:1a:fe:b0:b1:9f:2f:d3:4c:4b:02:65:39:57:2a:a1:
+        48:ba:6b:9d:f7:67:80:70:8f:38:00:0f:4e:b2:57:ac:59:ad:
+        97:b7:46:67:39:3d:75:12:ff:8f:ac:d9:65:0f:a7:05:a5:1e:
+        49:94:a5:a1:44:4f:e7:ba:b9:af:5d:2c:3d:29:cd:a2:e2:c5:
+        2c:ac:1f:1e:7f:64:bf:97:d4:a9:6c:d1:91:9c:50:20:af:50:
+        ad:6b
+-----BEGIN CERTIFICATE-----
+MIIDOTCCAqKgAwIBAgIBBTANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKY2gxX3B1YkNBMTEZMBcGCSqGSIb3DQEJARYKY2gx
+X3B1YkNBMTAeFw0xMDA4MDQyMDU5MjNaFw0xMzA0MzAyMDU5MjNaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjaDJfcHViQ0ExMRkwFwYJKoZIhvcN
+AQkBFgpjaDJfcHViQ0ExMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxF5QD
+mRIJHvI/duNjEXU8QUbKPyydL+MvOZBjodAx4bfrlPPFfCtK2pvSKClock7IUwyE
+m2uhfWNJO2XmvhGlukFedA0WrpUmAnnKON8T6feXUs3ThUnsz3XNVBPwFQ1l7url
+eztjPl+pS1bTEB2bR+0vRlRTGbAuY80S9EBKawIDAQABo4HWMIHTMB0GA1UdDgQW
+BBQ9jI/fB+fzXsFQaDeLitu9FVtMLjCBoAYDVR0jBIGYMIGVgBTRBexVIx0eU+yu
+cYiMEsKuFP4SXqF6pHgwdjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3Ju
+aWExEzARBgNVBAcTCk1lbmxvIFBhcmsxDTALBgNVBAoTBHBrZzUxEzARBgNVBAMU
+CnB1YkNBMV90YTExGTAXBgkqhkiG9w0BCQEWCnB1YkNBMV90YTGCAQQwDwYDVR0T
+AQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQCqYOD4u20H3lrRWAcnZCloSStC
+ZyXawNxSgpi4G3mpZSr+x3hGynYa/rCxny/TTEsCZTlXKqFIumud92eAcI84AA9O
+slesWa2Xt0ZnOT11Ev+PrNllD6cFpR5JlKWhRE/nurmvXSw9Kc2i4sUsrB8ef2S/
+l9SpbNGRnFAgr1Ctaw==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/06.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,54 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 6 (0x6)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ch2_pubCA1/emailAddress=ch2_pubCA1
+        Validity
+            Not Before: Aug  4 20:59:24 2010 GMT
+            Not After : Apr 30 20:59:24 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs1_pubCA1/emailAddress=cs1_pubCA1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:97:a7:b6:9a:40:63:12:2f:3c:4b:3f:75:d2:53:
+                    5b:c9:c9:6e:7c:fc:f6:8e:35:7f:7a:5a:b2:fa:00:
+                    eb:dd:f0:f2:87:2a:c9:9b:4d:7e:2d:3c:f1:0e:4e:
+                    ff:b4:b1:91:88:2f:c3:ab:ae:65:39:1e:da:e8:7e:
+                    50:b5:94:48:a6:5c:b0:bb:42:aa:70:e6:50:9c:41:
+                    2c:67:38:6c:e0:5d:9a:7d:b4:95:36:54:ea:e8:48:
+                    24:31:1c:30:39:24:2c:2a:1f:de:c2:c8:bf:e8:82:
+                    35:4a:9b:52:8e:15:e8:34:df:0c:78:be:e5:c6:85:
+                    c6:79:88:75:c0:04:e4:b8:77
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+    Signature Algorithm: sha256WithRSAEncryption
+        61:86:7f:54:cd:2f:e0:7f:2a:9a:20:55:23:af:00:79:13:25:
+        2e:29:4e:c6:40:d5:66:60:ea:34:b8:9a:cc:d9:39:04:63:d7:
+        f8:ae:a3:3d:73:54:34:8d:67:5a:92:b1:1a:f8:f0:38:f3:64:
+        2e:45:32:bd:29:a1:e3:32:d6:c7:73:77:70:c0:f0:e6:d4:00:
+        62:3b:e2:23:12:bb:f4:f7:d7:0c:15:74:2a:b0:cb:90:00:f3:
+        ba:ad:3c:15:35:4b:ef:c3:08:34:4e:02:e7:6c:bd:2c:e6:45:
+        43:fa:c5:1d:14:3c:6b:33:01:1d:22:b2:12:2e:0e:e7:82:53:
+        49:9b
+-----BEGIN CERTIFICATE-----
+MIICfzCCAeigAwIBAgIBBjANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKY2gyX3B1YkNBMTEZMBcGCSqGSIb3DQEJARYKY2gy
+X3B1YkNBMTAeFw0xMDA4MDQyMDU5MjRaFw0xMzA0MzAyMDU5MjRaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjczFfcHViQ0ExMRkwFwYJKoZIhvcN
+AQkBFgpjczFfcHViQ0ExMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCXp7aa
+QGMSLzxLP3XSU1vJyW58/PaONX96WrL6AOvd8PKHKsmbTX4tPPEOTv+0sZGIL8Or
+rmU5HtroflC1lEimXLC7Qqpw5lCcQSxnOGzgXZp9tJU2VOroSCQxHDA5JCwqH97C
+yL/ogjVKm1KOFeg03wx4vuXGhcZ5iHXABOS4dwIDAQABox0wGzAMBgNVHRMBAf8E
+AjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQsFAAOBgQBhhn9UzS/gfyqaIFUj
+rwB5EyUuKU7GQNVmYOo0uJrM2TkEY9f4rqM9c1Q0jWdakrEa+PA482QuRTK9KaHj
+MtbHc3dwwPDm1ABiO+IjErv099cMFXQqsMuQAPO6rTwVNUvvwwg0TgLnbL0s5kVD
++sUdFDxrMwEdIrISLg7nglNJmw==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/07.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,56 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 7 (0x7)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ch2_pubCA1/emailAddress=ch2_pubCA1
+        Validity
+            Not Before: Aug  4 20:59:24 2010 GMT
+            Not After : Apr 30 20:59:24 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs2_pubCA1/emailAddress=cs2_pubCA1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:bc:d4:1e:7a:76:36:24:10:2f:84:b3:ed:24:8f:
+                    0b:85:8a:17:39:2f:15:26:0a:80:e2:60:aa:c0:00:
+                    af:d5:ba:9c:ef:b0:3a:09:31:e7:97:37:82:ea:32:
+                    a0:c5:75:c3:0e:0f:6a:77:ef:66:77:2f:6a:a2:60:
+                    5b:b7:86:39:df:12:94:4e:61:79:de:dd:d2:fc:d1:
+                    a0:ba:fe:6a:24:09:3b:4f:1e:35:19:e2:15:25:8b:
+                    7c:03:19:66:3d:10:45:91:9c:83:9a:71:c9:b2:eb:
+                    df:a9:64:c7:2d:5a:93:23:d3:5d:ec:64:03:64:f4:
+                    34:b9:ee:40:1d:df:0c:c5:3d
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 CRL Distribution Points: 
+                URI:http://localhost:12001/file/0/pubCA1_ta1_crl.pem
+
+    Signature Algorithm: sha256WithRSAEncryption
+        39:29:a1:18:73:e2:98:bd:03:ed:99:eb:dc:f3:a3:da:cb:3e:
+        b3:5e:4c:f5:27:2f:c0:9d:7b:d1:3b:97:dc:cc:00:ca:f3:81:
+        48:65:d5:a8:07:42:25:8e:9e:66:38:eb:ca:68:f3:f0:15:95:
+        21:7b:c9:ec:9b:b1:af:dc:63:95:a2:cd:8c:dc:88:f5:7d:37:
+        2f:20:02:ea:b9:c5:e3:64:c2:4a:2d:94:54:10:4e:b9:07:8a:
+        46:99:7c:26:40:82:e5:65:30:df:66:02:6c:17:d8:6e:95:d4:
+        ff:09:25:15:0b:68:7b:ab:84:35:c9:3f:ec:3f:92:76:f2:59:
+        c2:50
+-----BEGIN CERTIFICATE-----
+MIICtTCCAh6gAwIBAgIBBzANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKY2gyX3B1YkNBMTEZMBcGCSqGSIb3DQEJARYKY2gy
+X3B1YkNBMTAeFw0xMDA4MDQyMDU5MjRaFw0xMzA0MzAyMDU5MjRaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjczJfcHViQ0ExMRkwFwYJKoZIhvcN
+AQkBFgpjczJfcHViQ0ExMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC81B56
+djYkEC+Es+0kjwuFihc5LxUmCoDiYKrAAK/VupzvsDoJMeeXN4LqMqDFdcMOD2p3
+72Z3L2qiYFu3hjnfEpROYXne3dL80aC6/mokCTtPHjUZ4hUli3wDGWY9EEWRnIOa
+ccmy69+pZMctWpMj013sZANk9DS57kAd3wzFPQIDAQABo1MwUTAMBgNVHRMBAf8E
+AjAAMEEGA1UdHwQ6MDgwNqA0oDKGMGh0dHA6Ly9sb2NhbGhvc3Q6MTIwMDEvZmls
+ZS8wL3B1YkNBMV90YTFfY3JsLnBlbTANBgkqhkiG9w0BAQsFAAOBgQA5KaEYc+KY
+vQPtmevc86Payz6zXkz1Jy/AnXvRO5fczADK84FIZdWoB0Iljp5mOOvKaPPwFZUh
+e8nsm7Gv3GOVos2M3Ij1fTcvIALqucXjZMJKLZRUEE65B4pGmXwmQILlZTDfZgJs
+F9huldT/CSUVC2h7q4Q1yT/sP5J28lnCUA==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/08.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,56 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 8 (0x8)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ch2_pubCA1/emailAddress=ch2_pubCA1
+        Validity
+            Not Before: Aug  4 20:59:24 2010 GMT
+            Not After : Apr 30 20:59:24 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs3_pubCA1/emailAddress=cs3_pubCA1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:ae:1e:e7:bd:54:fe:74:88:e0:34:0d:32:b2:1b:
+                    ea:3e:63:fd:7b:1b:13:cc:84:29:e1:f8:7d:c4:9c:
+                    65:aa:3a:2b:fd:c9:7c:03:57:03:b2:12:75:b9:c9:
+                    5e:02:a4:8e:6d:c7:54:c1:cd:e1:30:28:5f:a8:64:
+                    c9:c2:02:e2:3b:af:5e:b3:ec:2c:1c:5c:48:50:07:
+                    87:e4:19:80:ef:b4:78:6f:f2:6f:dd:64:61:97:ce:
+                    a7:29:0a:07:3c:6f:2e:44:fe:38:70:5b:c6:44:bb:
+                    cf:f5:3f:b3:20:3b:3b:81:fa:77:25:ab:1f:4f:f6:
+                    db:28:fd:7f:ba:2f:57:18:47
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 CRL Distribution Points: 
+                URI:http://localhost:12001/file/0/ch1_pubCA1_crl.pem
+
+    Signature Algorithm: sha256WithRSAEncryption
+        22:d6:f3:a1:9f:65:9a:2d:d1:3f:50:ea:ba:52:99:1e:1f:95:
+        38:e4:e0:cb:7e:fc:7f:5a:82:75:a4:fa:23:64:7b:4f:63:b1:
+        b5:30:34:38:8e:d1:54:13:a6:1e:7b:3b:f0:3e:94:54:1e:a4:
+        5c:19:3c:38:18:d7:ee:b0:31:ea:ac:d1:b2:18:4b:a7:19:93:
+        45:8f:a2:b6:cf:0b:39:73:b6:80:2e:3d:48:de:18:af:98:4e:
+        cc:15:a2:a4:98:a0:d1:03:36:05:b1:e7:81:94:3b:cd:da:b2:
+        fc:2b:ff:9f:e5:fe:9c:b8:2b:5c:1a:75:00:58:54:a3:f1:4e:
+        cf:53
+-----BEGIN CERTIFICATE-----
+MIICtTCCAh6gAwIBAgIBCDANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKY2gyX3B1YkNBMTEZMBcGCSqGSIb3DQEJARYKY2gy
+X3B1YkNBMTAeFw0xMDA4MDQyMDU5MjRaFw0xMzA0MzAyMDU5MjRaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjczNfcHViQ0ExMRkwFwYJKoZIhvcN
+AQkBFgpjczNfcHViQ0ExMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCuHue9
+VP50iOA0DTKyG+o+Y/17GxPMhCnh+H3EnGWqOiv9yXwDVwOyEnW5yV4CpI5tx1TB
+zeEwKF+oZMnCAuI7r16z7CwcXEhQB4fkGYDvtHhv8m/dZGGXzqcpCgc8by5E/jhw
+W8ZEu8/1P7MgOzuB+nclqx9P9tso/X+6L1cYRwIDAQABo1MwUTAMBgNVHRMBAf8E
+AjAAMEEGA1UdHwQ6MDgwNqA0oDKGMGh0dHA6Ly9sb2NhbGhvc3Q6MTIwMDEvZmls
+ZS8wL2NoMV9wdWJDQTFfY3JsLnBlbTANBgkqhkiG9w0BAQsFAAOBgQAi1vOhn2Wa
+LdE/UOq6UpkeH5U45ODLfvx/WoJ1pPojZHtPY7G1MDQ4jtFUE6YeezvwPpRUHqRc
+GTw4GNfusDHqrNGyGEunGZNFj6K2zws5c7aALj1I3hivmE7MFaKkmKDRAzYFseeB
+lDvN2rL8K/+f5f6cuCtcGnUAWFSj8U7PUw==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/0A.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,54 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 10 (0xa)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ch2.2_pubCA1/emailAddress=ch2.2_pubCA1
+        Validity
+            Not Before: Aug  4 20:59:25 2010 GMT
+            Not After : Apr 30 20:59:25 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs4_pubCA1/emailAddress=cs4_pubCA1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:b7:e6:67:c1:7f:08:9e:27:00:00:ce:8e:e4:5b:
+                    f5:65:d0:f2:4e:ac:d4:07:b8:21:a2:5a:9b:bd:e3:
+                    48:24:ff:f1:ec:05:49:c2:34:5a:ca:f5:9b:91:2b:
+                    3c:6a:31:ea:3b:25:53:c9:09:3b:2b:24:32:8b:8c:
+                    4c:30:95:78:e9:7c:f0:d7:bc:f8:4e:24:8b:c5:dd:
+                    b4:50:5a:a8:68:78:15:ee:52:73:6e:5a:9a:f9:dd:
+                    7c:39:90:f1:ef:bf:e5:a5:18:dc:d4:d8:a1:8f:2e:
+                    6a:9c:17:dc:20:93:59:e6:c4:3d:bb:f2:a8:0e:ea:
+                    1a:be:a9:54:7f:a2:7b:48:73
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+    Signature Algorithm: sha256WithRSAEncryption
+        6a:34:f8:4a:4b:80:50:1e:e8:bd:17:75:d4:c5:e5:30:b7:63:
+        2f:18:18:e8:24:38:ec:a3:e9:a9:39:f0:2c:4c:83:22:b6:ed:
+        38:9e:08:d4:3e:3d:b6:5e:2f:2d:cd:84:43:60:92:f0:1e:6c:
+        06:6a:86:f3:d9:bb:c7:1c:77:aa:21:b0:0d:34:c6:86:b2:7c:
+        cc:66:12:89:16:eb:39:a6:2f:2b:4b:0e:95:87:4f:28:e3:62:
+        73:c2:99:68:26:ee:5f:e4:64:99:d1:a7:b7:25:66:a8:19:f3:
+        36:c5:b8:1e:7e:ed:10:af:6e:38:a9:9a:03:55:3f:2f:4e:2a:
+        af:9a
+-----BEGIN CERTIFICATE-----
+MIICgzCCAeygAwIBAgIBCjANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEVMBMGA1UEAxQMY2gyLjJfcHViQ0ExMRswGQYJKoZIhvcNAQkBFgxj
+aDIuMl9wdWJDQTEwHhcNMTAwODA0MjA1OTI1WhcNMTMwNDMwMjA1OTI1WjB2MQsw
+CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8g
+UGFyazENMAsGA1UEChMEcGtnNTETMBEGA1UEAxQKY3M0X3B1YkNBMTEZMBcGCSqG
+SIb3DQEJARYKY3M0X3B1YkNBMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
+t+ZnwX8InicAAM6O5Fv1ZdDyTqzUB7gholqbveNIJP/x7AVJwjRayvWbkSs8ajHq
+OyVTyQk7KyQyi4xMMJV46Xzw17z4TiSLxd20UFqoaHgV7lJzblqa+d18OZDx77/l
+pRjc1Nihjy5qnBfcIJNZ5sQ9u/KoDuoavqlUf6J7SHMCAwEAAaMdMBswDAYDVR0T
+AQH/BAIwADALBgNVHQ8EBAMCB4AwDQYJKoZIhvcNAQELBQADgYEAajT4SkuAUB7o
+vRd11MXlMLdjLxgY6CQ47KPpqTnwLEyDIrbtOJ4I1D49tl4vLc2EQ2CS8B5sBmqG
+89m7xxx3qiGwDTTGhrJ8zGYSiRbrOaYvK0sOlYdPKONic8KZaCbuX+RkmdGntyVm
+qBnzNsW4Hn7tEK9uOKmaA1U/L04qr5o=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/0B.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,53 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 11 (0xb)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta2/emailAddress=ta2
+        Validity
+            Not Before: Aug  4 20:59:25 2010 GMT
+            Not After : Apr 30 20:59:25 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs1_ta2/emailAddress=cs1_ta2
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:b7:0f:a6:ed:f2:e7:d2:c1:de:09:a9:5b:7d:ba:
+                    41:14:76:aa:26:fc:f6:a5:0b:d5:42:a5:e1:f0:5b:
+                    2a:15:f0:60:b7:df:06:13:02:06:03:e3:df:31:b9:
+                    4f:60:1c:ed:04:55:28:11:bd:8b:7b:9d:98:6a:2c:
+                    18:e8:45:85:a5:8b:ce:4c:87:3e:91:46:dd:76:91:
+                    ca:d1:0d:36:02:1b:23:18:4c:44:01:a4:8e:30:01:
+                    fe:09:a8:46:28:e3:2e:e5:5f:45:66:f9:a5:81:2a:
+                    f3:97:0d:c8:ed:22:cf:59:82:4b:cc:c6:eb:14:35:
+                    48:48:df:a8:58:a4:3c:80:63
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+    Signature Algorithm: sha256WithRSAEncryption
+        79:48:fb:8f:11:f5:8b:94:10:b2:09:f5:ee:de:34:e9:61:b7:
+        00:53:0b:82:99:dd:34:13:cf:de:73:54:12:af:62:24:a8:9b:
+        10:1e:04:f6:39:ac:10:20:80:70:d5:ee:29:40:00:91:ae:e5:
+        62:cf:1c:22:19:b2:bf:3a:b5:b1:b1:89:29:d7:c2:50:c6:5c:
+        1b:d8:e5:02:f1:c1:a9:f1:bc:b7:6c:37:65:2b:25:18:31:10:
+        56:73:b0:71:30:6e:2a:f5:82:31:81:75:81:05:0b:11:5e:ed:
+        28:85:0a:cc:17:1e:a0:c8:37:01:a6:75:71:9a:89:89:c9:24:
+        1e:5b
+-----BEGIN CERTIFICATE-----
+MIICazCCAdSgAwIBAgIBCzANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEMMAoGA1UEAxMDdGEyMRIwEAYJKoZIhvcNAQkBFgN0YTIwHhcNMTAw
+ODA0MjA1OTI1WhcNMTMwNDMwMjA1OTI1WjBwMQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UEChMEcGtn
+NTEQMA4GA1UEAxQHY3MxX3RhMjEWMBQGCSqGSIb3DQEJARYHY3MxX3RhMjCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtw+m7fLn0sHeCalbfbpBFHaqJvz2pQvV
+QqXh8FsqFfBgt98GEwIGA+PfMblPYBztBFUoEb2Le52YaiwY6EWFpYvOTIc+kUbd
+dpHK0Q02AhsjGExEAaSOMAH+CahGKOMu5V9FZvmlgSrzlw3I7SLPWYJLzMbrFDVI
+SN+oWKQ8gGMCAwEAAaMdMBswDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCB4AwDQYJ
+KoZIhvcNAQELBQADgYEAeUj7jxH1i5QQsgn17t406WG3AFMLgpndNBPP3nNUEq9i
+JKibEB4E9jmsECCAcNXuKUAAka7lYs8cIhmyvzq1sbGJKdfCUMZcG9jlAvHBqfG8
+t2w3ZSslGDEQVnOwcTBuKvWCMYF1gQULEV7tKIUKzBceoMg3AaZ1cZqJickkHls=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/0D.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,54 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 13 (0xd)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta3/emailAddress=pubCA1_ta3
+        Validity
+            Not Before: Aug  4 20:59:25 2010 GMT
+            Not After : Apr 30 20:59:25 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs1_p1_ta3/emailAddress=cs1_p1_ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:dd:8e:8a:e1:5f:20:65:74:0d:91:f3:d6:bd:76:
+                    67:58:99:ae:d7:99:bc:78:1f:d0:bb:d9:97:95:41:
+                    3b:42:4b:cc:cc:36:d8:27:00:2a:c3:27:92:4c:2d:
+                    5f:62:81:0c:b2:6d:1b:93:ca:a4:1c:18:09:8c:26:
+                    22:bf:80:a4:fe:48:37:87:64:63:32:95:41:8f:f6:
+                    35:98:93:f0:61:f2:4b:eb:b0:34:36:67:85:a1:9d:
+                    21:75:de:ab:9f:32:ae:3a:93:64:48:7f:ef:5a:fa:
+                    44:e2:1b:9f:9d:10:3c:c3:9c:90:dd:e1:fe:33:31:
+                    4a:22:cb:82:ab:84:2a:1e:af
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+    Signature Algorithm: sha256WithRSAEncryption
+        3c:c2:d6:d7:6b:2a:e4:79:6d:b3:c8:48:64:b6:54:0c:30:d0:
+        3b:cd:4e:b8:f8:cd:0a:94:53:e5:10:b9:9e:93:f3:5a:a5:5e:
+        8c:4f:a6:d9:6c:98:ac:b6:e9:87:5e:85:ca:80:7f:34:5f:8a:
+        97:7a:f3:fc:8e:8d:de:6c:58:02:dc:ee:46:96:46:38:60:13:
+        7d:3a:5e:b8:32:e9:15:33:3f:0f:f2:21:2c:ea:ef:cf:0b:ff:
+        b8:07:58:2a:61:15:2c:fe:69:86:02:78:76:60:ce:51:30:8a:
+        26:ed:aa:9e:ee:b0:64:81:2f:0f:5c:a5:cd:47:cd:59:0b:3b:
+        aa:12
+-----BEGIN CERTIFICATE-----
+MIICfzCCAeigAwIBAgIBDTANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0ExX3RhMzEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0ExX3RhMzAeFw0xMDA4MDQyMDU5MjVaFw0xMzA0MzAyMDU5MjVaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjczFfcDFfdGEzMRkwFwYJKoZIhvcN
+AQkBFgpjczFfcDFfdGEzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdjorh
+XyBldA2R89a9dmdYma7Xmbx4H9C72ZeVQTtCS8zMNtgnACrDJ5JMLV9igQyybRuT
+yqQcGAmMJiK/gKT+SDeHZGMylUGP9jWYk/Bh8kvrsDQ2Z4WhnSF13qufMq46k2RI
+f+9a+kTiG5+dEDzDnJDd4f4zMUoiy4KrhCoerwIDAQABox0wGzAMBgNVHRMBAf8E
+AjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQsFAAOBgQA8wtbXayrkeW2zyEhk
+tlQMMNA7zU64+M0KlFPlELmek/NapV6MT6bZbJistumHXoXKgH80X4qXevP8jo3e
+bFgC3O5GlkY4YBN9Ol64MukVMz8P8iEs6u/PC/+4B1gqYRUs/mmGAnh2YM5RMIom
+7aqe7rBkgS8PXKXNR81ZCzuqEg==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/0E.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,55 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 14 (0xe)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta3/emailAddress=pubCA1_ta3
+        Validity
+            Not Before: Aug  4 20:59:26 2010 GMT
+            Not After : Apr 30 20:59:26 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs2_p1_ta3/emailAddress=cs2_p1_ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:c4:33:d5:18:cf:f2:82:d5:e6:c0:68:5a:3a:2a:
+                    50:30:fc:d6:df:61:cc:c1:35:16:cd:22:bf:72:42:
+                    2a:08:aa:93:f8:52:18:e9:e4:45:f3:d1:0a:a2:38:
+                    c6:44:73:e1:27:84:98:88:2f:f8:b2:b1:e2:46:39:
+                    bd:1f:cf:7a:bc:51:7f:31:e4:f5:b8:56:f3:54:4c:
+                    a5:57:ae:70:cc:f6:a4:46:8b:2c:7e:d3:6f:9b:c2:
+                    bb:e6:a4:f2:2a:15:e1:48:54:2c:63:fd:b3:eb:9e:
+                    6d:3a:bd:cc:3d:ce:3d:16:52:c1:6b:2a:82:8c:ca:
+                    60:50:6d:d6:aa:88:e7:c5:29
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Issuer Alternative Name: critical
+                <EMPTY>
+
+    Signature Algorithm: sha256WithRSAEncryption
+        04:c7:86:2b:af:5e:8c:eb:fc:5f:b4:ab:40:f2:57:b4:2c:db:
+        bc:14:6c:9c:49:5c:79:c9:55:a2:6b:ff:2a:d0:98:d7:66:83:
+        cc:48:58:f1:e8:a8:14:17:80:bc:18:bd:cf:d4:f9:02:a1:44:
+        6d:7c:91:f9:3c:97:03:28:2c:9e:c6:14:a9:8d:3a:bd:c7:c4:
+        ef:93:df:62:b5:41:2b:63:ed:16:a6:de:f2:f7:ab:54:b9:04:
+        b6:8f:ba:25:45:76:89:51:b2:c3:bc:67:db:78:93:3d:ae:77:
+        b2:0c:26:14:be:9e:89:ed:bb:f6:df:a4:b4:61:b1:18:bf:b8:
+        e6:38
+-----BEGIN CERTIFICATE-----
+MIICgDCCAemgAwIBAgIBDjANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0ExX3RhMzEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0ExX3RhMzAeFw0xMDA4MDQyMDU5MjZaFw0xMzA0MzAyMDU5MjZaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjczJfcDFfdGEzMRkwFwYJKoZIhvcN
+AQkBFgpjczJfcDFfdGEzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEM9UY
+z/KC1ebAaFo6KlAw/NbfYczBNRbNIr9yQioIqpP4Uhjp5EXz0QqiOMZEc+EnhJiI
+L/iyseJGOb0fz3q8UX8x5PW4VvNUTKVXrnDM9qRGiyx+02+bwrvmpPIqFeFIVCxj
+/bPrnm06vcw9zj0WUsFrKoKMymBQbdaqiOfFKQIDAQABox4wHDAMBgNVHRMBAf8E
+AjAAMAwGA1UdEgEB/wQCMAAwDQYJKoZIhvcNAQELBQADgYEABMeGK69ejOv8X7Sr
+QPJXtCzbvBRsnElceclVomv/KtCY12aDzEhY8eioFBeAvBi9z9T5AqFEbXyR+TyX
+AygsnsYUqY06vcfE75PfYrVBK2PtFqbe8verVLkEto+6JUV2iVGyw7xn23iTPa53
+sgwmFL6eie279t+ktGGxGL+45jg=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/0F.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,54 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 15 (0xf)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta3/emailAddress=pubCA1_ta3
+        Validity
+            Not Before: Jan  1 01:01:01 2009 GMT
+            Not After : Jan  2 01:01:01 2009 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs3_p1_ta3/emailAddress=cs3_p1_ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:ce:9e:aa:9a:44:62:e4:9d:f2:cd:d1:ef:39:cc:
+                    cb:b8:e9:1a:06:cf:7e:e4:e1:99:52:e0:5a:17:a9:
+                    78:b3:e7:25:c0:97:f8:72:d4:75:50:c5:d9:84:84:
+                    90:cc:53:5e:46:c0:66:d8:0a:76:0c:cf:f7:ff:f8:
+                    fd:e9:f4:60:88:49:74:97:3d:34:f0:90:da:97:5d:
+                    40:1e:78:cb:bf:84:1b:c2:7e:70:cb:b6:79:26:7d:
+                    62:a1:63:60:0b:9f:b3:5a:5f:13:a8:1c:5e:f5:39:
+                    0c:14:d4:67:58:16:09:3b:cf:5c:4a:4a:e6:17:80:
+                    90:69:b5:6d:8d:c8:27:88:9d
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+    Signature Algorithm: sha256WithRSAEncryption
+        41:c7:40:05:62:dd:88:6f:07:66:78:9b:56:0d:55:77:9e:b7:
+        d1:08:f6:b1:59:cd:85:72:b3:19:fd:0f:c7:4f:a9:54:52:6a:
+        4b:f0:c2:d1:35:6c:1c:cd:71:ee:6f:61:c3:a9:a2:f9:13:68:
+        6a:56:f9:95:c6:da:82:61:9d:de:dd:4b:e1:42:2f:db:80:62:
+        49:31:45:60:c8:d6:3d:1b:49:82:6f:df:1c:a4:ca:01:9a:6f:
+        bc:ff:9e:a8:ec:42:f8:22:f9:70:b3:3a:e6:e2:3e:d2:18:58:
+        89:95:d8:01:fe:b1:25:5e:bc:a2:70:1c:59:5d:e5:af:b1:02:
+        ac:d3
+-----BEGIN CERTIFICATE-----
+MIICfzCCAeigAwIBAgIBDzANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0ExX3RhMzEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0ExX3RhMzAeFw0wOTAxMDEwMTAxMDFaFw0wOTAxMDIwMTAxMDFaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjczNfcDFfdGEzMRkwFwYJKoZIhvcN
+AQkBFgpjczNfcDFfdGEzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOnqqa
+RGLknfLN0e85zMu46RoGz37k4ZlS4FoXqXiz5yXAl/hy1HVQxdmEhJDMU15GwGbY
+CnYMz/f/+P3p9GCISXSXPTTwkNqXXUAeeMu/hBvCfnDLtnkmfWKhY2ALn7NaXxOo
+HF71OQwU1GdYFgk7z1xKSuYXgJBptW2NyCeInQIDAQABox0wGzAMBgNVHRMBAf8E
+AjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQsFAAOBgQBBx0AFYt2IbwdmeJtW
+DVV3nrfRCPaxWc2FcrMZ/Q/HT6lUUmpL8MLRNWwczXHub2HDqaL5E2hqVvmVxtqC
+YZ3e3UvhQi/bgGJJMUVgyNY9G0mCb98cpMoBmm+8/56o7EL4Ivlwszrm4j7SGFiJ
+ldgB/rElXryicBxZXeWvsQKs0w==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/10.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,54 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 16 (0x10)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta3/emailAddress=pubCA1_ta3
+        Validity
+            Not Before: Jan  1 01:01:01 2035 GMT
+            Not After : Jan  2 01:01:01 2035 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs4_p1_ta3/emailAddress=cs4_p1_ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:a5:72:6c:c4:dc:df:15:f5:b0:2f:fb:d2:e2:d9:
+                    f2:2c:5e:0a:c5:04:34:99:0f:06:13:9a:e8:86:2d:
+                    44:2f:57:67:81:a1:93:0e:cd:b5:4b:ca:1a:4b:31:
+                    c6:a7:73:b3:70:66:21:03:6a:cd:a5:bf:4a:6d:96:
+                    d8:50:9e:95:d7:42:84:86:80:f1:15:3f:5c:85:8f:
+                    dd:ee:13:61:c9:2c:71:c1:c1:cb:e8:e9:4d:eb:ce:
+                    d9:57:98:2d:93:81:0e:fb:6d:00:31:9d:db:6f:c2:
+                    aa:b1:36:65:0d:8d:82:7b:e7:df:7c:03:76:f9:b8:
+                    6c:6e:7e:13:5d:85:ac:c0:89
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+    Signature Algorithm: sha256WithRSAEncryption
+        5f:7c:e0:ae:58:97:b0:36:1e:a7:28:61:9c:0d:2e:cb:34:22:
+        b3:18:7d:d9:0d:2e:2e:0e:0c:79:1f:5e:14:37:c3:cf:7a:41:
+        60:76:a5:0e:ea:c9:eb:f3:5c:7f:0f:39:2e:dc:b8:58:9b:d9:
+        f6:37:f9:53:22:a1:07:57:f9:4e:e3:0e:5b:31:15:7e:88:8d:
+        78:48:18:d5:f9:3a:dd:0b:4a:41:5b:c1:e0:32:8b:3a:ef:ad:
+        36:c8:26:e8:25:52:f7:94:19:99:6e:ff:ec:ac:f3:34:6e:f4:
+        ef:73:e9:6f:2c:8e:c3:96:09:b5:25:68:f9:ce:5c:40:07:47:
+        36:8a
+-----BEGIN CERTIFICATE-----
+MIICfzCCAeigAwIBAgIBEDANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0ExX3RhMzEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0ExX3RhMzAeFw0zNTAxMDEwMTAxMDFaFw0zNTAxMDIwMTAxMDFaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjczRfcDFfdGEzMRkwFwYJKoZIhvcN
+AQkBFgpjczRfcDFfdGEzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQClcmzE
+3N8V9bAv+9Li2fIsXgrFBDSZDwYTmuiGLUQvV2eBoZMOzbVLyhpLMcanc7NwZiED
+as2lv0ptlthQnpXXQoSGgPEVP1yFj93uE2HJLHHBwcvo6U3rztlXmC2TgQ77bQAx
+ndtvwqqxNmUNjYJ75998A3b5uGxufhNdhazAiQIDAQABox0wGzAMBgNVHRMBAf8E
+AjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQsFAAOBgQBffOCuWJewNh6nKGGc
+DS7LNCKzGH3ZDS4uDgx5H14UN8PPekFgdqUO6snr81x/Dzku3LhYm9n2N/lTIqEH
+V/lO4w5bMRV+iI14SBjV+TrdC0pBW8HgMos67602yCboJVL3lBmZbv/srPM0bvTv
+c+lvLI7Dlgm1JWj5zlxAB0c2ig==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/12.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,54 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 18 (0x12)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA2_ta3/emailAddress=pubCA2_ta3
+        Validity
+            Not Before: Aug  4 20:59:27 2010 GMT
+            Not After : Apr 30 20:59:27 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs1_p2_ta3/emailAddress=cs1_p2_ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:d0:1e:f6:58:e2:2b:d0:15:fe:da:5c:5d:11:84:
+                    b9:7c:65:42:51:e2:92:9e:43:c0:71:c2:0b:ba:4b:
+                    07:60:14:08:27:16:f5:2c:16:44:6d:89:0e:cf:6f:
+                    47:2d:ef:12:df:0d:9d:9c:94:cf:4e:f0:00:1c:07:
+                    3b:6c:e5:10:61:97:f3:c0:20:12:6c:00:87:9d:95:
+                    e4:3b:14:de:7d:97:77:59:9a:2c:9a:f6:a9:0c:20:
+                    3f:0b:da:a9:13:32:d3:a9:a7:5f:38:9f:b5:7f:19:
+                    0f:f1:ff:c0:a6:7f:e9:76:24:66:72:29:ce:6d:6a:
+                    a2:c3:3e:34:0a:34:b8:c4:9b
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+    Signature Algorithm: sha256WithRSAEncryption
+        2f:4c:87:b3:14:32:98:dd:06:48:ce:26:54:7d:49:d7:3d:6a:
+        a3:ac:52:bc:55:9e:9f:09:82:1a:ea:cc:c3:a4:a2:83:4e:98:
+        73:cd:29:f5:0b:46:4f:f7:e6:97:cb:96:8f:60:ca:22:b0:dc:
+        37:0e:7b:89:4c:24:13:aa:9a:4e:65:f7:66:f2:3c:99:e3:12:
+        e4:59:db:b9:9f:46:a4:27:19:1b:90:f3:2b:8d:01:88:78:81:
+        34:90:0e:14:a9:80:05:f1:19:28:22:e1:00:f3:e4:a6:e1:28:
+        0d:d0:36:ac:9f:1c:05:9c:17:e3:0f:2b:40:6b:1a:7a:07:60:
+        8c:b5
+-----BEGIN CERTIFICATE-----
+MIICfzCCAeigAwIBAgIBEjANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0EyX3RhMzEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0EyX3RhMzAeFw0xMDA4MDQyMDU5MjdaFw0xMzA0MzAyMDU5MjdaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjczFfcDJfdGEzMRkwFwYJKoZIhvcN
+AQkBFgpjczFfcDJfdGEzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQHvZY
+4ivQFf7aXF0RhLl8ZUJR4pKeQ8Bxwgu6SwdgFAgnFvUsFkRtiQ7Pb0ct7xLfDZ2c
+lM9O8AAcBzts5RBhl/PAIBJsAIedleQ7FN59l3dZmiya9qkMID8L2qkTMtOpp184
+n7V/GQ/x/8Cmf+l2JGZyKc5taqLDPjQKNLjEmwIDAQABox0wGzAMBgNVHRMBAf8E
+AjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQsFAAOBgQAvTIezFDKY3QZIziZU
+fUnXPWqjrFK8VZ6fCYIa6szDpKKDTphzzSn1C0ZP9+aXy5aPYMoisNw3DnuJTCQT
+qppOZfdm8jyZ4xLkWdu5n0akJxkbkPMrjQGIeIE0kA4UqYAF8RkoIuEA8+Sm4SgN
+0DasnxwFnBfjDytAaxp6B2CMtQ==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/14.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,54 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 20 (0x14)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA3_ta3/emailAddress=pubCA3_ta3
+        Validity
+            Not Before: Aug  4 20:59:27 2010 GMT
+            Not After : Apr 30 20:59:27 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs1_p3_ta3/emailAddress=cs1_p3_ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:bc:82:7d:df:49:1f:1f:4c:7e:ee:25:51:96:e4:
+                    49:a8:fb:ee:b0:51:b5:10:e9:cc:f0:36:07:59:61:
+                    37:a8:95:70:5f:53:3e:54:ef:02:46:d9:12:84:20:
+                    8f:65:c4:53:99:e6:cc:d9:de:d0:e5:d2:51:2b:3d:
+                    3d:08:88:a3:35:d3:7e:bf:c9:70:d3:65:81:16:30:
+                    18:0e:7f:22:66:52:05:65:d0:e4:65:11:06:8d:df:
+                    a1:97:df:74:c4:f3:be:d2:6f:ee:12:8d:1a:dd:15:
+                    b8:e4:7e:cd:12:ce:d4:47:4d:d5:e9:d7:c8:3b:e0:
+                    0a:43:7a:4a:cc:11:6a:38:31
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+    Signature Algorithm: sha256WithRSAEncryption
+        33:5c:cd:75:6d:2d:67:ce:9a:bb:c9:86:9d:07:59:66:9c:b2:
+        36:0f:a6:6d:5a:a4:dc:11:0a:b6:0a:80:78:5d:93:8a:c6:6b:
+        e1:81:01:70:31:5b:0c:ad:8e:04:35:4a:6b:c6:54:d5:28:fd:
+        8d:bb:c6:90:b2:66:58:3a:8c:a6:e5:98:dc:e5:ed:5f:ad:55:
+        48:99:68:2a:7f:5a:b4:48:e7:96:29:97:9a:af:d5:b4:be:08:
+        e9:cd:34:7f:15:98:3c:f7:30:f6:a8:ed:4b:4a:57:f5:1c:18:
+        2a:96:36:f6:ec:a0:d4:bc:50:b6:68:0f:cd:ac:44:0c:97:c5:
+        89:59
+-----BEGIN CERTIFICATE-----
+MIICfzCCAeigAwIBAgIBFDANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0EzX3RhMzEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0EzX3RhMzAeFw0xMDA4MDQyMDU5MjdaFw0xMzA0MzAyMDU5MjdaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjczFfcDNfdGEzMRkwFwYJKoZIhvcN
+AQkBFgpjczFfcDNfdGEzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8gn3f
+SR8fTH7uJVGW5Emo++6wUbUQ6czwNgdZYTeolXBfUz5U7wJG2RKEII9lxFOZ5szZ
+3tDl0lErPT0IiKM1036/yXDTZYEWMBgOfyJmUgVl0ORlEQaN36GX33TE877Sb+4S
+jRrdFbjkfs0SztRHTdXp18g74ApDekrMEWo4MQIDAQABox0wGzAMBgNVHRMBAf8E
+AjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQsFAAOBgQAzXM11bS1nzpq7yYad
+B1lmnLI2D6ZtWqTcEQq2CoB4XZOKxmvhgQFwMVsMrY4ENUprxlTVKP2Nu8aQsmZY
+Ooym5Zjc5e1frVVImWgqf1q0SOeWKZear9W0vgjpzTR/FZg89zD2qO1LSlf1HBgq
+ljb27KDUvFC2aA/NrEQMl8WJWQ==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/16.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,54 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 22 (0x16)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA4_ta3/emailAddress=pubCA4_ta3
+        Validity
+            Not Before: Aug  4 20:59:28 2010 GMT
+            Not After : Apr 30 20:59:28 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs1_p4_ta3/emailAddress=cs1_p4_ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:bf:42:c9:e7:65:b4:c1:88:85:cc:9a:49:29:db:
+                    64:05:14:60:b4:c4:ab:44:7d:86:51:9d:c0:ba:c2:
+                    41:c2:80:fc:e7:ea:26:14:f2:73:af:90:98:98:c8:
+                    ed:eb:89:d4:1f:a7:9a:7a:4f:8d:0a:4a:b5:54:de:
+                    3c:1a:5c:cc:18:1d:39:dd:f5:2b:97:a6:1c:b3:75:
+                    4c:da:1f:86:bb:1f:0f:67:b1:a0:e9:1c:f9:21:e0:
+                    2e:98:de:5c:64:66:7f:39:42:78:14:a5:ce:2c:b2:
+                    9b:fc:f2:54:a1:a2:af:cc:73:80:a3:6d:d0:d3:29:
+                    f9:ae:9b:e1:d6:9c:3a:19:89
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+    Signature Algorithm: sha256WithRSAEncryption
+        1b:81:d7:ec:0d:02:2c:b0:29:3c:62:f1:f5:e3:71:50:ac:a2:
+        d5:66:86:8c:98:c2:5a:79:2c:25:cf:a1:55:0f:4f:17:5d:93:
+        c6:89:fc:d6:14:ad:3e:2a:56:4e:ab:2d:1b:5d:37:30:2e:50:
+        78:22:d7:74:46:63:76:a0:23:5c:77:ad:ae:47:7e:db:a0:7e:
+        2c:17:27:df:0a:e8:2e:ff:4d:58:53:99:d2:36:08:78:45:a6:
+        af:eb:e9:fd:48:a1:e1:20:f1:70:ad:e9:77:51:d8:22:e5:e6:
+        f2:a6:06:04:31:eb:fe:3c:f1:75:5f:51:36:a9:b1:fc:8f:6c:
+        d8:4e
+-----BEGIN CERTIFICATE-----
+MIICfzCCAeigAwIBAgIBFjANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0E0X3RhMzEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0E0X3RhMzAeFw0xMDA4MDQyMDU5MjhaFw0xMzA0MzAyMDU5MjhaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjczFfcDRfdGEzMRkwFwYJKoZIhvcN
+AQkBFgpjczFfcDRfdGEzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC/Qsnn
+ZbTBiIXMmkkp22QFFGC0xKtEfYZRncC6wkHCgPzn6iYU8nOvkJiYyO3ridQfp5p6
+T40KSrVU3jwaXMwYHTnd9SuXphyzdUzaH4a7Hw9nsaDpHPkh4C6Y3lxkZn85QngU
+pc4sspv88lShoq/Mc4CjbdDTKfmum+HWnDoZiQIDAQABox0wGzAMBgNVHRMBAf8E
+AjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQsFAAOBgQAbgdfsDQIssCk8YvH1
+43FQrKLVZoaMmMJaeSwlz6FVD08XXZPGifzWFK0+KlZOqy0bXTcwLlB4Itd0RmN2
+oCNcd62uR37boH4sFyffCugu/01YU5nSNgh4Raav6+n9SKHhIPFwrel3Udgi5eby
+pgYEMev+PPF1X1E2qbH8j2zYTg==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/18.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,56 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 24 (0x18)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta4/emailAddress=pubCA1_ta4
+        Validity
+            Not Before: Aug  4 20:59:28 2010 GMT
+            Not After : Apr 30 20:59:28 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs1_ta4/emailAddress=cs1_ta4
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:ac:00:6d:f7:7a:86:bb:cf:c8:06:9a:71:7f:69:
+                    3a:41:2d:5d:d5:66:31:a1:2f:9d:7b:72:df:21:44:
+                    be:03:63:cd:3e:2b:fc:e3:46:8d:df:54:cb:71:27:
+                    26:cf:63:f8:9b:9f:73:5e:45:9f:b9:5e:78:5a:ed:
+                    e6:c0:22:dd:9b:dd:8a:5a:4e:bc:af:dd:70:a5:1c:
+                    12:60:1c:7a:71:7c:65:8f:41:e0:5a:fb:c7:02:9a:
+                    e1:ef:e1:d5:ab:31:fb:08:c8:f9:c9:d8:f1:7e:75:
+                    59:79:27:26:0d:21:43:89:3a:67:ad:13:74:23:fa:
+                    27:0f:b7:1a:68:65:67:b9:03
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 CRL Distribution Points: 
+                URI:http://localhost:12001/file/0/pubCA1_ta4_crl.pem
+
+    Signature Algorithm: sha256WithRSAEncryption
+        26:89:7c:81:2d:20:13:0e:c3:0c:76:39:1f:9a:65:db:66:ac:
+        75:75:cc:a3:23:8d:d7:37:b1:dd:91:5f:80:1a:46:79:6c:9a:
+        9f:c3:36:84:0e:46:6c:26:48:f1:63:67:d5:fd:f9:de:e6:52:
+        8f:a5:f1:3f:f6:06:ad:4d:4d:09:c2:64:21:ef:69:72:5c:bd:
+        f7:be:95:8a:ad:e6:6f:a8:31:83:45:04:08:a1:37:ac:4f:d4:
+        46:08:00:03:55:02:96:f8:f9:d7:db:06:94:fc:6a:06:65:a5:
+        b3:52:b9:8a:cd:01:2c:f4:48:4c:b7:e3:16:23:0c:db:42:9c:
+        e8:62
+-----BEGIN CERTIFICATE-----
+MIICrzCCAhigAwIBAgIBGDANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0ExX3RhNDEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0ExX3RhNDAeFw0xMDA4MDQyMDU5MjhaFw0xMzA0MzAyMDU5MjhaMHAxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRAwDgYDVQQDFAdjczFfdGE0MRYwFAYJKoZIhvcNAQkB
+FgdjczFfdGE0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsAG33eoa7z8gG
+mnF/aTpBLV3VZjGhL517ct8hRL4DY80+K/zjRo3fVMtxJybPY/ibn3NeRZ+5Xnha
+7ebAIt2b3YpaTryv3XClHBJgHHpxfGWPQeBa+8cCmuHv4dWrMfsIyPnJ2PF+dVl5
+JyYNIUOJOmetE3Qj+icPtxpoZWe5AwIDAQABo1MwUTAMBgNVHRMBAf8EAjAAMEEG
+A1UdHwQ6MDgwNqA0oDKGMGh0dHA6Ly9sb2NhbGhvc3Q6MTIwMDEvZmlsZS8wL3B1
+YkNBMV90YTRfY3JsLnBlbTANBgkqhkiG9w0BAQsFAAOBgQAmiXyBLSATDsMMdjkf
+mmXbZqx1dcyjI43XN7HdkV+AGkZ5bJqfwzaEDkZsJkjxY2fV/fne5lKPpfE/9gat
+TU0JwmQh72lyXL33vpWKreZvqDGDRQQIoTesT9RGCAADVQKW+PnX2waU/GoGZaWz
+UrmKzQEs9EhMt+MWIwzbQpzoYg==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/19.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,67 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 25 (0x19)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta4/emailAddress=pubCA1_ta4
+        Validity
+            Not Before: Aug  4 20:59:29 2010 GMT
+            Not After : Apr 30 20:59:29 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs2_ta4/emailAddress=cs2_ta4
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:d3:11:f2:56:c0:36:ef:ad:7f:18:53:a7:29:77:
+                    9f:6a:82:43:cd:a6:65:0c:5e:ca:39:d9:fa:83:b2:
+                    0d:24:e5:10:ae:85:c5:dc:02:aa:a6:38:4f:31:f3:
+                    b6:ab:47:37:9b:f8:99:80:6c:d3:35:36:81:72:f1:
+                    93:0f:6b:dd:ca:d7:5d:a1:6a:30:74:6e:07:9c:47:
+                    c3:35:69:fc:38:e6:b5:3d:bc:65:e6:ad:67:ea:22:
+                    90:06:d3:eb:aa:64:2f:3e:b3:4c:e1:a4:65:14:8e:
+                    b2:96:85:fc:3c:1d:01:a5:4a:16:1a:b2:84:e9:a8:
+                    03:d1:09:be:7b:3c:3b:0e:ed
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                5A:AE:AB:13:F4:60:55:35:31:96:FF:3F:20:AD:22:DF:EE:C7:4E:D3
+            X509v3 Authority Key Identifier: 
+                keyid:EE:8D:78:53:11:FE:07:CB:C8:55:4B:EF:A6:2F:E1:83:72:BB:BA:21
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta4/emailAddress=ta4
+                serial:17
+
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 CRL Distribution Points: 
+                URI:http://localhost:12001/file/0/example_file
+
+    Signature Algorithm: sha256WithRSAEncryption
+        4d:74:90:ac:a2:9c:93:39:0c:41:a7:c1:2b:73:56:97:14:32:
+        8d:64:01:78:82:a1:6f:a6:9c:3d:f5:75:80:3e:e2:b5:6c:cf:
+        c8:f2:21:46:05:e2:30:da:ce:41:88:96:87:ac:7b:a6:42:2a:
+        96:f7:1e:8d:4c:92:43:97:8f:99:08:29:47:ce:95:fb:7a:4e:
+        84:2c:0b:80:4b:c9:bf:a1:dc:0b:63:c6:9c:4f:c4:59:12:39:
+        e5:97:ee:6b:6e:86:33:18:43:da:16:5e:51:24:d0:0d:05:92:
+        7d:12:89:cd:21:fc:4e:52:86:9a:02:f9:5e:51:38:62:55:33:
+        d3:db
+-----BEGIN CERTIFICATE-----
+MIIDYDCCAsmgAwIBAgIBGTANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0ExX3RhNDEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0ExX3RhNDAeFw0xMDA4MDQyMDU5MjlaFw0xMzA0MzAyMDU5MjlaMHAxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRAwDgYDVQQDFAdjczJfdGE0MRYwFAYJKoZIhvcNAQkB
+FgdjczJfdGE0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDTEfJWwDbvrX8Y
+U6cpd59qgkPNpmUMXso52fqDsg0k5RCuhcXcAqqmOE8x87arRzeb+JmAbNM1NoFy
+8ZMPa93K112hajB0bgecR8M1afw45rU9vGXmrWfqIpAG0+uqZC8+s0zhpGUUjrKW
+hfw8HQGlShYasoTpqAPRCb57PDsO7QIDAQABo4IBAjCB/zAdBgNVHQ4EFgQUWq6r
+E/RgVTUxlv8/IK0i3+7HTtMwgZIGA1UdIwSBijCBh4AU7o14UxH+B8vIVUvvpi/h
+g3K7uiGhbKRqMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMw
+EQYDVQQHEwpNZW5sbyBQYXJrMQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTQx
+EjAQBgkqhkiG9w0BCQEWA3RhNIIBFzAMBgNVHRMBAf8EAjAAMDsGA1UdHwQ0MDIw
+MKAuoCyGKmh0dHA6Ly9sb2NhbGhvc3Q6MTIwMDEvZmlsZS8wL2V4YW1wbGVfZmls
+ZTANBgkqhkiG9w0BAQsFAAOBgQBNdJCsopyTOQxBp8Erc1aXFDKNZAF4gqFvppw9
+9XWAPuK1bM/I8iFGBeIw2s5BiJaHrHumQiqW9x6NTJJDl4+ZCClHzpX7ek6ELAuA
+S8m/odwLY8acT8RZEjnll+5rboYzGEPaFl5RJNANBZJ9EonNIfxOUoaaAvleUThi
+VTPT2w==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/1A.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,66 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 26 (0x1a)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta4/emailAddress=pubCA1_ta4
+        Validity
+            Not Before: Aug  4 20:59:29 2010 GMT
+            Not After : Apr 30 20:59:29 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs3_ta4/emailAddress=cs3_ta4
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:b2:66:56:2e:29:80:41:b1:f4:0f:03:7d:94:35:
+                    7d:67:5f:a6:df:49:c8:47:d8:53:03:0b:97:bb:01:
+                    fb:ba:86:6e:5b:f1:f6:b2:50:fd:c6:4a:8f:16:0d:
+                    4c:6b:95:72:55:a1:26:c1:db:8a:f1:16:e5:06:45:
+                    72:78:5c:54:fa:4b:3e:b2:e9:68:a9:68:4f:c8:19:
+                    8d:40:c1:07:3b:82:b5:ea:60:7c:8f:94:9f:27:81:
+                    79:1e:03:f1:ac:90:42:6b:6f:87:1e:ea:b9:a8:c5:
+                    b1:a4:2a:ff:8c:1c:37:aa:7d:eb:7c:70:2a:5f:e6:
+                    56:60:84:46:e5:a2:3b:11:79
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                98:85:12:48:CD:F8:29:DD:17:72:03:5C:40:02:E6:50:F6:24:E7:2D
+            X509v3 Authority Key Identifier: 
+                keyid:EE:8D:78:53:11:FE:07:CB:C8:55:4B:EF:A6:2F:E1:83:72:BB:BA:21
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta4/emailAddress=ta4
+                serial:17
+
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 CRL Distribution Points: 
+                URI:foo://bar/baz
+
+    Signature Algorithm: sha256WithRSAEncryption
+        49:ac:6c:a5:ab:c6:c7:ad:f3:93:47:d4:74:7f:4a:d3:46:b0:
+        71:6f:6e:42:e2:7f:f6:ed:db:38:ed:29:09:e1:e0:a0:a7:4c:
+        ec:17:56:a8:71:71:20:2a:da:f0:19:4d:e2:13:3c:6e:db:6a:
+        16:3a:46:63:15:7b:3c:a2:70:f1:6c:14:35:5b:51:80:1c:7e:
+        2c:93:23:ac:31:46:ea:7a:cf:8a:80:b9:45:95:67:ea:b7:c1:
+        cf:b7:0d:99:7b:72:37:29:4d:b3:a0:31:94:e4:55:79:9d:f2:
+        fa:18:c3:f5:fe:77:93:91:17:f1:ce:b7:ae:39:00:b1:5b:98:
+        ab:81
+-----BEGIN CERTIFICATE-----
+MIIDQjCCAqugAwIBAgIBGjANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0ExX3RhNDEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0ExX3RhNDAeFw0xMDA4MDQyMDU5MjlaFw0xMzA0MzAyMDU5MjlaMHAxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRAwDgYDVQQDFAdjczNfdGE0MRYwFAYJKoZIhvcNAQkB
+FgdjczNfdGE0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyZlYuKYBBsfQP
+A32UNX1nX6bfSchH2FMDC5e7Afu6hm5b8fayUP3GSo8WDUxrlXJVoSbB24rxFuUG
+RXJ4XFT6Sz6y6WipaE/IGY1AwQc7grXqYHyPlJ8ngXkeA/GskEJrb4ce6rmoxbGk
+Kv+MHDeqfet8cCpf5lZghEblojsReQIDAQABo4HlMIHiMB0GA1UdDgQWBBSYhRJI
+zfgp3RdyA1xAAuZQ9iTnLTCBkgYDVR0jBIGKMIGHgBTujXhTEf4Hy8hVS++mL+GD
+cru6IaFspGowaDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEzAR
+BgNVBAcTCk1lbmxvIFBhcmsxDTALBgNVBAoTBHBrZzUxDDAKBgNVBAMTA3RhNDES
+MBAGCSqGSIb3DQEJARYDdGE0ggEXMAwGA1UdEwEB/wQCMAAwHgYDVR0fBBcwFTAT
+oBGgD4YNZm9vOi8vYmFyL2JhejANBgkqhkiG9w0BAQsFAAOBgQBJrGylq8bHrfOT
+R9R0f0rTRrBxb25C4n/27ds47SkJ4eCgp0zsF1aocXEgKtrwGU3iEzxu22oWOkZj
+FXs8onDxbBQ1W1GAHH4skyOsMUbqes+KgLlFlWfqt8HPtw2Ze3I3KU2zoDGU5FV5
+nfL6GMP1/neTkRfxzreuOQCxW5irgQ==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/1C.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,54 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 28 (0x1c)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta5/emailAddress=pubCA1_ta5
+        Validity
+            Not Before: Aug  4 20:59:29 2010 GMT
+            Not After : Apr 30 20:59:29 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs1_ta5/emailAddress=cs1_ta5
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:a7:58:5a:64:49:1e:65:e8:63:d7:6c:d2:b4:65:
+                    73:47:16:10:1b:a9:45:7e:22:fe:87:7b:30:58:2e:
+                    81:7f:d0:69:be:49:06:c5:44:2b:8d:32:0c:91:8f:
+                    48:d4:d9:e4:51:25:52:56:bc:40:92:a8:05:e7:65:
+                    82:c4:79:49:ac:42:fc:d4:41:71:9c:cb:7a:f0:5f:
+                    35:d7:08:11:03:3b:d3:4b:c1:cb:37:7a:cd:58:64:
+                    ec:1b:83:25:3e:3a:f3:99:23:e0:13:c5:85:9a:1a:
+                    d4:79:53:d2:32:4c:c9:50:3b:19:66:6f:22:fc:c8:
+                    5a:6b:ef:97:d9:77:01:3a:a3
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+    Signature Algorithm: sha256WithRSAEncryption
+        38:eb:26:f5:12:ed:5c:37:ad:86:d2:0f:b8:7e:a2:87:88:35:
+        b2:c3:50:92:41:65:48:b3:fe:fd:a6:81:a5:bc:07:70:d6:54:
+        3a:e5:dd:a9:c6:0a:fe:5d:5f:2b:97:0b:4c:5d:d0:59:9d:76:
+        95:9a:7c:d8:fa:4a:59:6c:16:27:b6:91:b2:98:8d:fe:15:23:
+        18:f0:79:0b:9c:f3:35:bb:a7:e1:31:b3:03:83:e9:3a:b1:f6:
+        1f:c2:f9:15:85:c6:0f:3d:b4:78:a4:20:e4:46:96:43:85:7c:
+        9e:ad:e0:8e:78:47:3d:f9:7b:2e:14:90:45:39:68:d4:34:fc:
+        f3:c2
+-----BEGIN CERTIFICATE-----
+MIICeTCCAeKgAwIBAgIBHDANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0ExX3RhNTEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0ExX3RhNTAeFw0xMDA4MDQyMDU5MjlaFw0xMzA0MzAyMDU5MjlaMHAxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRAwDgYDVQQDFAdjczFfdGE1MRYwFAYJKoZIhvcNAQkB
+FgdjczFfdGE1MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnWFpkSR5l6GPX
+bNK0ZXNHFhAbqUV+Iv6HezBYLoF/0Gm+SQbFRCuNMgyRj0jU2eRRJVJWvECSqAXn
+ZYLEeUmsQvzUQXGcy3rwXzXXCBEDO9NLwcs3es1YZOwbgyU+OvOZI+ATxYWaGtR5
+U9IyTMlQOxlmbyL8yFpr75fZdwE6owIDAQABox0wGzAMBgNVHRMBAf8EAjAAMAsG
+A1UdDwQEAwIHgDANBgkqhkiG9w0BAQsFAAOBgQA46yb1Eu1cN62G0g+4fqKHiDWy
+w1CSQWVIs/79poGlvAdw1lQ65d2pxgr+XV8rlwtMXdBZnXaVmnzY+kpZbBYntpGy
+mI3+FSMY8HkLnPM1u6fhMbMDg+k6sfYfwvkVhcYPPbR4pCDkRpZDhXyereCOeEc9
++XsuFJBFOWjUNPzzwg==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/cs1_p1_ta3_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,54 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 13 (0xd)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta3/emailAddress=pubCA1_ta3
+        Validity
+            Not Before: Aug  4 20:59:25 2010 GMT
+            Not After : Apr 30 20:59:25 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs1_p1_ta3/emailAddress=cs1_p1_ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:dd:8e:8a:e1:5f:20:65:74:0d:91:f3:d6:bd:76:
+                    67:58:99:ae:d7:99:bc:78:1f:d0:bb:d9:97:95:41:
+                    3b:42:4b:cc:cc:36:d8:27:00:2a:c3:27:92:4c:2d:
+                    5f:62:81:0c:b2:6d:1b:93:ca:a4:1c:18:09:8c:26:
+                    22:bf:80:a4:fe:48:37:87:64:63:32:95:41:8f:f6:
+                    35:98:93:f0:61:f2:4b:eb:b0:34:36:67:85:a1:9d:
+                    21:75:de:ab:9f:32:ae:3a:93:64:48:7f:ef:5a:fa:
+                    44:e2:1b:9f:9d:10:3c:c3:9c:90:dd:e1:fe:33:31:
+                    4a:22:cb:82:ab:84:2a:1e:af
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+    Signature Algorithm: sha256WithRSAEncryption
+        3c:c2:d6:d7:6b:2a:e4:79:6d:b3:c8:48:64:b6:54:0c:30:d0:
+        3b:cd:4e:b8:f8:cd:0a:94:53:e5:10:b9:9e:93:f3:5a:a5:5e:
+        8c:4f:a6:d9:6c:98:ac:b6:e9:87:5e:85:ca:80:7f:34:5f:8a:
+        97:7a:f3:fc:8e:8d:de:6c:58:02:dc:ee:46:96:46:38:60:13:
+        7d:3a:5e:b8:32:e9:15:33:3f:0f:f2:21:2c:ea:ef:cf:0b:ff:
+        b8:07:58:2a:61:15:2c:fe:69:86:02:78:76:60:ce:51:30:8a:
+        26:ed:aa:9e:ee:b0:64:81:2f:0f:5c:a5:cd:47:cd:59:0b:3b:
+        aa:12
+-----BEGIN CERTIFICATE-----
+MIICfzCCAeigAwIBAgIBDTANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0ExX3RhMzEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0ExX3RhMzAeFw0xMDA4MDQyMDU5MjVaFw0xMzA0MzAyMDU5MjVaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjczFfcDFfdGEzMRkwFwYJKoZIhvcN
+AQkBFgpjczFfcDFfdGEzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdjorh
+XyBldA2R89a9dmdYma7Xmbx4H9C72ZeVQTtCS8zMNtgnACrDJ5JMLV9igQyybRuT
+yqQcGAmMJiK/gKT+SDeHZGMylUGP9jWYk/Bh8kvrsDQ2Z4WhnSF13qufMq46k2RI
+f+9a+kTiG5+dEDzDnJDd4f4zMUoiy4KrhCoerwIDAQABox0wGzAMBgNVHRMBAf8E
+AjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQsFAAOBgQA8wtbXayrkeW2zyEhk
+tlQMMNA7zU64+M0KlFPlELmek/NapV6MT6bZbJistumHXoXKgH80X4qXevP8jo3e
+bFgC3O5GlkY4YBN9Ol64MukVMz8P8iEs6u/PC/+4B1gqYRUs/mmGAnh2YM5RMIom
+7aqe7rBkgS8PXKXNR81ZCzuqEg==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/cs1_p2_ta3_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,54 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 18 (0x12)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA2_ta3/emailAddress=pubCA2_ta3
+        Validity
+            Not Before: Aug  4 20:59:27 2010 GMT
+            Not After : Apr 30 20:59:27 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs1_p2_ta3/emailAddress=cs1_p2_ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:d0:1e:f6:58:e2:2b:d0:15:fe:da:5c:5d:11:84:
+                    b9:7c:65:42:51:e2:92:9e:43:c0:71:c2:0b:ba:4b:
+                    07:60:14:08:27:16:f5:2c:16:44:6d:89:0e:cf:6f:
+                    47:2d:ef:12:df:0d:9d:9c:94:cf:4e:f0:00:1c:07:
+                    3b:6c:e5:10:61:97:f3:c0:20:12:6c:00:87:9d:95:
+                    e4:3b:14:de:7d:97:77:59:9a:2c:9a:f6:a9:0c:20:
+                    3f:0b:da:a9:13:32:d3:a9:a7:5f:38:9f:b5:7f:19:
+                    0f:f1:ff:c0:a6:7f:e9:76:24:66:72:29:ce:6d:6a:
+                    a2:c3:3e:34:0a:34:b8:c4:9b
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+    Signature Algorithm: sha256WithRSAEncryption
+        2f:4c:87:b3:14:32:98:dd:06:48:ce:26:54:7d:49:d7:3d:6a:
+        a3:ac:52:bc:55:9e:9f:09:82:1a:ea:cc:c3:a4:a2:83:4e:98:
+        73:cd:29:f5:0b:46:4f:f7:e6:97:cb:96:8f:60:ca:22:b0:dc:
+        37:0e:7b:89:4c:24:13:aa:9a:4e:65:f7:66:f2:3c:99:e3:12:
+        e4:59:db:b9:9f:46:a4:27:19:1b:90:f3:2b:8d:01:88:78:81:
+        34:90:0e:14:a9:80:05:f1:19:28:22:e1:00:f3:e4:a6:e1:28:
+        0d:d0:36:ac:9f:1c:05:9c:17:e3:0f:2b:40:6b:1a:7a:07:60:
+        8c:b5
+-----BEGIN CERTIFICATE-----
+MIICfzCCAeigAwIBAgIBEjANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0EyX3RhMzEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0EyX3RhMzAeFw0xMDA4MDQyMDU5MjdaFw0xMzA0MzAyMDU5MjdaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjczFfcDJfdGEzMRkwFwYJKoZIhvcN
+AQkBFgpjczFfcDJfdGEzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQHvZY
+4ivQFf7aXF0RhLl8ZUJR4pKeQ8Bxwgu6SwdgFAgnFvUsFkRtiQ7Pb0ct7xLfDZ2c
+lM9O8AAcBzts5RBhl/PAIBJsAIedleQ7FN59l3dZmiya9qkMID8L2qkTMtOpp184
+n7V/GQ/x/8Cmf+l2JGZyKc5taqLDPjQKNLjEmwIDAQABox0wGzAMBgNVHRMBAf8E
+AjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQsFAAOBgQAvTIezFDKY3QZIziZU
+fUnXPWqjrFK8VZ6fCYIa6szDpKKDTphzzSn1C0ZP9+aXy5aPYMoisNw3DnuJTCQT
+qppOZfdm8jyZ4xLkWdu5n0akJxkbkPMrjQGIeIE0kA4UqYAF8RkoIuEA8+Sm4SgN
+0DasnxwFnBfjDytAaxp6B2CMtQ==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/cs1_p3_ta3_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,54 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 20 (0x14)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA3_ta3/emailAddress=pubCA3_ta3
+        Validity
+            Not Before: Aug  4 20:59:27 2010 GMT
+            Not After : Apr 30 20:59:27 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs1_p3_ta3/emailAddress=cs1_p3_ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:bc:82:7d:df:49:1f:1f:4c:7e:ee:25:51:96:e4:
+                    49:a8:fb:ee:b0:51:b5:10:e9:cc:f0:36:07:59:61:
+                    37:a8:95:70:5f:53:3e:54:ef:02:46:d9:12:84:20:
+                    8f:65:c4:53:99:e6:cc:d9:de:d0:e5:d2:51:2b:3d:
+                    3d:08:88:a3:35:d3:7e:bf:c9:70:d3:65:81:16:30:
+                    18:0e:7f:22:66:52:05:65:d0:e4:65:11:06:8d:df:
+                    a1:97:df:74:c4:f3:be:d2:6f:ee:12:8d:1a:dd:15:
+                    b8:e4:7e:cd:12:ce:d4:47:4d:d5:e9:d7:c8:3b:e0:
+                    0a:43:7a:4a:cc:11:6a:38:31
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+    Signature Algorithm: sha256WithRSAEncryption
+        33:5c:cd:75:6d:2d:67:ce:9a:bb:c9:86:9d:07:59:66:9c:b2:
+        36:0f:a6:6d:5a:a4:dc:11:0a:b6:0a:80:78:5d:93:8a:c6:6b:
+        e1:81:01:70:31:5b:0c:ad:8e:04:35:4a:6b:c6:54:d5:28:fd:
+        8d:bb:c6:90:b2:66:58:3a:8c:a6:e5:98:dc:e5:ed:5f:ad:55:
+        48:99:68:2a:7f:5a:b4:48:e7:96:29:97:9a:af:d5:b4:be:08:
+        e9:cd:34:7f:15:98:3c:f7:30:f6:a8:ed:4b:4a:57:f5:1c:18:
+        2a:96:36:f6:ec:a0:d4:bc:50:b6:68:0f:cd:ac:44:0c:97:c5:
+        89:59
+-----BEGIN CERTIFICATE-----
+MIICfzCCAeigAwIBAgIBFDANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0EzX3RhMzEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0EzX3RhMzAeFw0xMDA4MDQyMDU5MjdaFw0xMzA0MzAyMDU5MjdaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjczFfcDNfdGEzMRkwFwYJKoZIhvcN
+AQkBFgpjczFfcDNfdGEzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8gn3f
+SR8fTH7uJVGW5Emo++6wUbUQ6czwNgdZYTeolXBfUz5U7wJG2RKEII9lxFOZ5szZ
+3tDl0lErPT0IiKM1036/yXDTZYEWMBgOfyJmUgVl0ORlEQaN36GX33TE877Sb+4S
+jRrdFbjkfs0SztRHTdXp18g74ApDekrMEWo4MQIDAQABox0wGzAMBgNVHRMBAf8E
+AjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQsFAAOBgQAzXM11bS1nzpq7yYad
+B1lmnLI2D6ZtWqTcEQq2CoB4XZOKxmvhgQFwMVsMrY4ENUprxlTVKP2Nu8aQsmZY
+Ooym5Zjc5e1frVVImWgqf1q0SOeWKZear9W0vgjpzTR/FZg89zD2qO1LSlf1HBgq
+ljb27KDUvFC2aA/NrEQMl8WJWQ==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/cs1_p4_ta3_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,54 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 22 (0x16)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA4_ta3/emailAddress=pubCA4_ta3
+        Validity
+            Not Before: Aug  4 20:59:28 2010 GMT
+            Not After : Apr 30 20:59:28 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs1_p4_ta3/emailAddress=cs1_p4_ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:bf:42:c9:e7:65:b4:c1:88:85:cc:9a:49:29:db:
+                    64:05:14:60:b4:c4:ab:44:7d:86:51:9d:c0:ba:c2:
+                    41:c2:80:fc:e7:ea:26:14:f2:73:af:90:98:98:c8:
+                    ed:eb:89:d4:1f:a7:9a:7a:4f:8d:0a:4a:b5:54:de:
+                    3c:1a:5c:cc:18:1d:39:dd:f5:2b:97:a6:1c:b3:75:
+                    4c:da:1f:86:bb:1f:0f:67:b1:a0:e9:1c:f9:21:e0:
+                    2e:98:de:5c:64:66:7f:39:42:78:14:a5:ce:2c:b2:
+                    9b:fc:f2:54:a1:a2:af:cc:73:80:a3:6d:d0:d3:29:
+                    f9:ae:9b:e1:d6:9c:3a:19:89
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+    Signature Algorithm: sha256WithRSAEncryption
+        1b:81:d7:ec:0d:02:2c:b0:29:3c:62:f1:f5:e3:71:50:ac:a2:
+        d5:66:86:8c:98:c2:5a:79:2c:25:cf:a1:55:0f:4f:17:5d:93:
+        c6:89:fc:d6:14:ad:3e:2a:56:4e:ab:2d:1b:5d:37:30:2e:50:
+        78:22:d7:74:46:63:76:a0:23:5c:77:ad:ae:47:7e:db:a0:7e:
+        2c:17:27:df:0a:e8:2e:ff:4d:58:53:99:d2:36:08:78:45:a6:
+        af:eb:e9:fd:48:a1:e1:20:f1:70:ad:e9:77:51:d8:22:e5:e6:
+        f2:a6:06:04:31:eb:fe:3c:f1:75:5f:51:36:a9:b1:fc:8f:6c:
+        d8:4e
+-----BEGIN CERTIFICATE-----
+MIICfzCCAeigAwIBAgIBFjANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0E0X3RhMzEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0E0X3RhMzAeFw0xMDA4MDQyMDU5MjhaFw0xMzA0MzAyMDU5MjhaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjczFfcDRfdGEzMRkwFwYJKoZIhvcN
+AQkBFgpjczFfcDRfdGEzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC/Qsnn
+ZbTBiIXMmkkp22QFFGC0xKtEfYZRncC6wkHCgPzn6iYU8nOvkJiYyO3ridQfp5p6
+T40KSrVU3jwaXMwYHTnd9SuXphyzdUzaH4a7Hw9nsaDpHPkh4C6Y3lxkZn85QngU
+pc4sspv88lShoq/Mc4CjbdDTKfmum+HWnDoZiQIDAQABox0wGzAMBgNVHRMBAf8E
+AjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQsFAAOBgQAbgdfsDQIssCk8YvH1
+43FQrKLVZoaMmMJaeSwlz6FVD08XXZPGifzWFK0+KlZOqy0bXTcwLlB4Itd0RmN2
+oCNcd62uR37boH4sFyffCugu/01YU5nSNgh4Raav6+n9SKHhIPFwrel3Udgi5eby
+pgYEMev+PPF1X1E2qbH8j2zYTg==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/cs1_pubCA1_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,54 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 6 (0x6)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ch2_pubCA1/emailAddress=ch2_pubCA1
+        Validity
+            Not Before: Aug  4 20:59:24 2010 GMT
+            Not After : Apr 30 20:59:24 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs1_pubCA1/emailAddress=cs1_pubCA1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:97:a7:b6:9a:40:63:12:2f:3c:4b:3f:75:d2:53:
+                    5b:c9:c9:6e:7c:fc:f6:8e:35:7f:7a:5a:b2:fa:00:
+                    eb:dd:f0:f2:87:2a:c9:9b:4d:7e:2d:3c:f1:0e:4e:
+                    ff:b4:b1:91:88:2f:c3:ab:ae:65:39:1e:da:e8:7e:
+                    50:b5:94:48:a6:5c:b0:bb:42:aa:70:e6:50:9c:41:
+                    2c:67:38:6c:e0:5d:9a:7d:b4:95:36:54:ea:e8:48:
+                    24:31:1c:30:39:24:2c:2a:1f:de:c2:c8:bf:e8:82:
+                    35:4a:9b:52:8e:15:e8:34:df:0c:78:be:e5:c6:85:
+                    c6:79:88:75:c0:04:e4:b8:77
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+    Signature Algorithm: sha256WithRSAEncryption
+        61:86:7f:54:cd:2f:e0:7f:2a:9a:20:55:23:af:00:79:13:25:
+        2e:29:4e:c6:40:d5:66:60:ea:34:b8:9a:cc:d9:39:04:63:d7:
+        f8:ae:a3:3d:73:54:34:8d:67:5a:92:b1:1a:f8:f0:38:f3:64:
+        2e:45:32:bd:29:a1:e3:32:d6:c7:73:77:70:c0:f0:e6:d4:00:
+        62:3b:e2:23:12:bb:f4:f7:d7:0c:15:74:2a:b0:cb:90:00:f3:
+        ba:ad:3c:15:35:4b:ef:c3:08:34:4e:02:e7:6c:bd:2c:e6:45:
+        43:fa:c5:1d:14:3c:6b:33:01:1d:22:b2:12:2e:0e:e7:82:53:
+        49:9b
+-----BEGIN CERTIFICATE-----
+MIICfzCCAeigAwIBAgIBBjANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKY2gyX3B1YkNBMTEZMBcGCSqGSIb3DQEJARYKY2gy
+X3B1YkNBMTAeFw0xMDA4MDQyMDU5MjRaFw0xMzA0MzAyMDU5MjRaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjczFfcHViQ0ExMRkwFwYJKoZIhvcN
+AQkBFgpjczFfcHViQ0ExMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCXp7aa
+QGMSLzxLP3XSU1vJyW58/PaONX96WrL6AOvd8PKHKsmbTX4tPPEOTv+0sZGIL8Or
+rmU5HtroflC1lEimXLC7Qqpw5lCcQSxnOGzgXZp9tJU2VOroSCQxHDA5JCwqH97C
+yL/ogjVKm1KOFeg03wx4vuXGhcZ5iHXABOS4dwIDAQABox0wGzAMBgNVHRMBAf8E
+AjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQsFAAOBgQBhhn9UzS/gfyqaIFUj
+rwB5EyUuKU7GQNVmYOo0uJrM2TkEY9f4rqM9c1Q0jWdakrEa+PA482QuRTK9KaHj
+MtbHc3dwwPDm1ABiO+IjErv099cMFXQqsMuQAPO6rTwVNUvvwwg0TgLnbL0s5kVD
++sUdFDxrMwEdIrISLg7nglNJmw==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/cs1_ta2_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,53 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 11 (0xb)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta2/emailAddress=ta2
+        Validity
+            Not Before: Aug  4 20:59:25 2010 GMT
+            Not After : Apr 30 20:59:25 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs1_ta2/emailAddress=cs1_ta2
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:b7:0f:a6:ed:f2:e7:d2:c1:de:09:a9:5b:7d:ba:
+                    41:14:76:aa:26:fc:f6:a5:0b:d5:42:a5:e1:f0:5b:
+                    2a:15:f0:60:b7:df:06:13:02:06:03:e3:df:31:b9:
+                    4f:60:1c:ed:04:55:28:11:bd:8b:7b:9d:98:6a:2c:
+                    18:e8:45:85:a5:8b:ce:4c:87:3e:91:46:dd:76:91:
+                    ca:d1:0d:36:02:1b:23:18:4c:44:01:a4:8e:30:01:
+                    fe:09:a8:46:28:e3:2e:e5:5f:45:66:f9:a5:81:2a:
+                    f3:97:0d:c8:ed:22:cf:59:82:4b:cc:c6:eb:14:35:
+                    48:48:df:a8:58:a4:3c:80:63
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+    Signature Algorithm: sha256WithRSAEncryption
+        79:48:fb:8f:11:f5:8b:94:10:b2:09:f5:ee:de:34:e9:61:b7:
+        00:53:0b:82:99:dd:34:13:cf:de:73:54:12:af:62:24:a8:9b:
+        10:1e:04:f6:39:ac:10:20:80:70:d5:ee:29:40:00:91:ae:e5:
+        62:cf:1c:22:19:b2:bf:3a:b5:b1:b1:89:29:d7:c2:50:c6:5c:
+        1b:d8:e5:02:f1:c1:a9:f1:bc:b7:6c:37:65:2b:25:18:31:10:
+        56:73:b0:71:30:6e:2a:f5:82:31:81:75:81:05:0b:11:5e:ed:
+        28:85:0a:cc:17:1e:a0:c8:37:01:a6:75:71:9a:89:89:c9:24:
+        1e:5b
+-----BEGIN CERTIFICATE-----
+MIICazCCAdSgAwIBAgIBCzANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEMMAoGA1UEAxMDdGEyMRIwEAYJKoZIhvcNAQkBFgN0YTIwHhcNMTAw
+ODA0MjA1OTI1WhcNMTMwNDMwMjA1OTI1WjBwMQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UEChMEcGtn
+NTEQMA4GA1UEAxQHY3MxX3RhMjEWMBQGCSqGSIb3DQEJARYHY3MxX3RhMjCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtw+m7fLn0sHeCalbfbpBFHaqJvz2pQvV
+QqXh8FsqFfBgt98GEwIGA+PfMblPYBztBFUoEb2Le52YaiwY6EWFpYvOTIc+kUbd
+dpHK0Q02AhsjGExEAaSOMAH+CahGKOMu5V9FZvmlgSrzlw3I7SLPWYJLzMbrFDVI
+SN+oWKQ8gGMCAwEAAaMdMBswDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCB4AwDQYJ
+KoZIhvcNAQELBQADgYEAeUj7jxH1i5QQsgn17t406WG3AFMLgpndNBPP3nNUEq9i
+JKibEB4E9jmsECCAcNXuKUAAka7lYs8cIhmyvzq1sbGJKdfCUMZcG9jlAvHBqfG8
+t2w3ZSslGDEQVnOwcTBuKvWCMYF1gQULEV7tKIUKzBceoMg3AaZ1cZqJickkHls=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/cs1_ta4_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,56 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 24 (0x18)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta4/emailAddress=pubCA1_ta4
+        Validity
+            Not Before: Aug  4 20:59:28 2010 GMT
+            Not After : Apr 30 20:59:28 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs1_ta4/emailAddress=cs1_ta4
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:ac:00:6d:f7:7a:86:bb:cf:c8:06:9a:71:7f:69:
+                    3a:41:2d:5d:d5:66:31:a1:2f:9d:7b:72:df:21:44:
+                    be:03:63:cd:3e:2b:fc:e3:46:8d:df:54:cb:71:27:
+                    26:cf:63:f8:9b:9f:73:5e:45:9f:b9:5e:78:5a:ed:
+                    e6:c0:22:dd:9b:dd:8a:5a:4e:bc:af:dd:70:a5:1c:
+                    12:60:1c:7a:71:7c:65:8f:41:e0:5a:fb:c7:02:9a:
+                    e1:ef:e1:d5:ab:31:fb:08:c8:f9:c9:d8:f1:7e:75:
+                    59:79:27:26:0d:21:43:89:3a:67:ad:13:74:23:fa:
+                    27:0f:b7:1a:68:65:67:b9:03
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 CRL Distribution Points: 
+                URI:http://localhost:12001/file/0/pubCA1_ta4_crl.pem
+
+    Signature Algorithm: sha256WithRSAEncryption
+        26:89:7c:81:2d:20:13:0e:c3:0c:76:39:1f:9a:65:db:66:ac:
+        75:75:cc:a3:23:8d:d7:37:b1:dd:91:5f:80:1a:46:79:6c:9a:
+        9f:c3:36:84:0e:46:6c:26:48:f1:63:67:d5:fd:f9:de:e6:52:
+        8f:a5:f1:3f:f6:06:ad:4d:4d:09:c2:64:21:ef:69:72:5c:bd:
+        f7:be:95:8a:ad:e6:6f:a8:31:83:45:04:08:a1:37:ac:4f:d4:
+        46:08:00:03:55:02:96:f8:f9:d7:db:06:94:fc:6a:06:65:a5:
+        b3:52:b9:8a:cd:01:2c:f4:48:4c:b7:e3:16:23:0c:db:42:9c:
+        e8:62
+-----BEGIN CERTIFICATE-----
+MIICrzCCAhigAwIBAgIBGDANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0ExX3RhNDEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0ExX3RhNDAeFw0xMDA4MDQyMDU5MjhaFw0xMzA0MzAyMDU5MjhaMHAxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRAwDgYDVQQDFAdjczFfdGE0MRYwFAYJKoZIhvcNAQkB
+FgdjczFfdGE0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsAG33eoa7z8gG
+mnF/aTpBLV3VZjGhL517ct8hRL4DY80+K/zjRo3fVMtxJybPY/ibn3NeRZ+5Xnha
+7ebAIt2b3YpaTryv3XClHBJgHHpxfGWPQeBa+8cCmuHv4dWrMfsIyPnJ2PF+dVl5
+JyYNIUOJOmetE3Qj+icPtxpoZWe5AwIDAQABo1MwUTAMBgNVHRMBAf8EAjAAMEEG
+A1UdHwQ6MDgwNqA0oDKGMGh0dHA6Ly9sb2NhbGhvc3Q6MTIwMDEvZmlsZS8wL3B1
+YkNBMV90YTRfY3JsLnBlbTANBgkqhkiG9w0BAQsFAAOBgQAmiXyBLSATDsMMdjkf
+mmXbZqx1dcyjI43XN7HdkV+AGkZ5bJqfwzaEDkZsJkjxY2fV/fne5lKPpfE/9gat
+TU0JwmQh72lyXL33vpWKreZvqDGDRQQIoTesT9RGCAADVQKW+PnX2waU/GoGZaWz
+UrmKzQEs9EhMt+MWIwzbQpzoYg==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/cs1_ta5_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,54 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 28 (0x1c)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta5/emailAddress=pubCA1_ta5
+        Validity
+            Not Before: Aug  4 20:59:29 2010 GMT
+            Not After : Apr 30 20:59:29 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs1_ta5/emailAddress=cs1_ta5
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:a7:58:5a:64:49:1e:65:e8:63:d7:6c:d2:b4:65:
+                    73:47:16:10:1b:a9:45:7e:22:fe:87:7b:30:58:2e:
+                    81:7f:d0:69:be:49:06:c5:44:2b:8d:32:0c:91:8f:
+                    48:d4:d9:e4:51:25:52:56:bc:40:92:a8:05:e7:65:
+                    82:c4:79:49:ac:42:fc:d4:41:71:9c:cb:7a:f0:5f:
+                    35:d7:08:11:03:3b:d3:4b:c1:cb:37:7a:cd:58:64:
+                    ec:1b:83:25:3e:3a:f3:99:23:e0:13:c5:85:9a:1a:
+                    d4:79:53:d2:32:4c:c9:50:3b:19:66:6f:22:fc:c8:
+                    5a:6b:ef:97:d9:77:01:3a:a3
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+    Signature Algorithm: sha256WithRSAEncryption
+        38:eb:26:f5:12:ed:5c:37:ad:86:d2:0f:b8:7e:a2:87:88:35:
+        b2:c3:50:92:41:65:48:b3:fe:fd:a6:81:a5:bc:07:70:d6:54:
+        3a:e5:dd:a9:c6:0a:fe:5d:5f:2b:97:0b:4c:5d:d0:59:9d:76:
+        95:9a:7c:d8:fa:4a:59:6c:16:27:b6:91:b2:98:8d:fe:15:23:
+        18:f0:79:0b:9c:f3:35:bb:a7:e1:31:b3:03:83:e9:3a:b1:f6:
+        1f:c2:f9:15:85:c6:0f:3d:b4:78:a4:20:e4:46:96:43:85:7c:
+        9e:ad:e0:8e:78:47:3d:f9:7b:2e:14:90:45:39:68:d4:34:fc:
+        f3:c2
+-----BEGIN CERTIFICATE-----
+MIICeTCCAeKgAwIBAgIBHDANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0ExX3RhNTEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0ExX3RhNTAeFw0xMDA4MDQyMDU5MjlaFw0xMzA0MzAyMDU5MjlaMHAxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRAwDgYDVQQDFAdjczFfdGE1MRYwFAYJKoZIhvcNAQkB
+FgdjczFfdGE1MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnWFpkSR5l6GPX
+bNK0ZXNHFhAbqUV+Iv6HezBYLoF/0Gm+SQbFRCuNMgyRj0jU2eRRJVJWvECSqAXn
+ZYLEeUmsQvzUQXGcy3rwXzXXCBEDO9NLwcs3es1YZOwbgyU+OvOZI+ATxYWaGtR5
+U9IyTMlQOxlmbyL8yFpr75fZdwE6owIDAQABox0wGzAMBgNVHRMBAf8EAjAAMAsG
+A1UdDwQEAwIHgDANBgkqhkiG9w0BAQsFAAOBgQA46yb1Eu1cN62G0g+4fqKHiDWy
+w1CSQWVIs/79poGlvAdw1lQ65d2pxgr+XV8rlwtMXdBZnXaVmnzY+kpZbBYntpGy
+mI3+FSMY8HkLnPM1u6fhMbMDg+k6sfYfwvkVhcYPPbR4pCDkRpZDhXyereCOeEc9
++XsuFJBFOWjUNPzzwg==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/cs2_p1_ta3_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,55 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 14 (0xe)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta3/emailAddress=pubCA1_ta3
+        Validity
+            Not Before: Aug  4 20:59:26 2010 GMT
+            Not After : Apr 30 20:59:26 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs2_p1_ta3/emailAddress=cs2_p1_ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:c4:33:d5:18:cf:f2:82:d5:e6:c0:68:5a:3a:2a:
+                    50:30:fc:d6:df:61:cc:c1:35:16:cd:22:bf:72:42:
+                    2a:08:aa:93:f8:52:18:e9:e4:45:f3:d1:0a:a2:38:
+                    c6:44:73:e1:27:84:98:88:2f:f8:b2:b1:e2:46:39:
+                    bd:1f:cf:7a:bc:51:7f:31:e4:f5:b8:56:f3:54:4c:
+                    a5:57:ae:70:cc:f6:a4:46:8b:2c:7e:d3:6f:9b:c2:
+                    bb:e6:a4:f2:2a:15:e1:48:54:2c:63:fd:b3:eb:9e:
+                    6d:3a:bd:cc:3d:ce:3d:16:52:c1:6b:2a:82:8c:ca:
+                    60:50:6d:d6:aa:88:e7:c5:29
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Issuer Alternative Name: critical
+                <EMPTY>
+
+    Signature Algorithm: sha256WithRSAEncryption
+        04:c7:86:2b:af:5e:8c:eb:fc:5f:b4:ab:40:f2:57:b4:2c:db:
+        bc:14:6c:9c:49:5c:79:c9:55:a2:6b:ff:2a:d0:98:d7:66:83:
+        cc:48:58:f1:e8:a8:14:17:80:bc:18:bd:cf:d4:f9:02:a1:44:
+        6d:7c:91:f9:3c:97:03:28:2c:9e:c6:14:a9:8d:3a:bd:c7:c4:
+        ef:93:df:62:b5:41:2b:63:ed:16:a6:de:f2:f7:ab:54:b9:04:
+        b6:8f:ba:25:45:76:89:51:b2:c3:bc:67:db:78:93:3d:ae:77:
+        b2:0c:26:14:be:9e:89:ed:bb:f6:df:a4:b4:61:b1:18:bf:b8:
+        e6:38
+-----BEGIN CERTIFICATE-----
+MIICgDCCAemgAwIBAgIBDjANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0ExX3RhMzEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0ExX3RhMzAeFw0xMDA4MDQyMDU5MjZaFw0xMzA0MzAyMDU5MjZaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjczJfcDFfdGEzMRkwFwYJKoZIhvcN
+AQkBFgpjczJfcDFfdGEzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEM9UY
+z/KC1ebAaFo6KlAw/NbfYczBNRbNIr9yQioIqpP4Uhjp5EXz0QqiOMZEc+EnhJiI
+L/iyseJGOb0fz3q8UX8x5PW4VvNUTKVXrnDM9qRGiyx+02+bwrvmpPIqFeFIVCxj
+/bPrnm06vcw9zj0WUsFrKoKMymBQbdaqiOfFKQIDAQABox4wHDAMBgNVHRMBAf8E
+AjAAMAwGA1UdEgEB/wQCMAAwDQYJKoZIhvcNAQELBQADgYEABMeGK69ejOv8X7Sr
+QPJXtCzbvBRsnElceclVomv/KtCY12aDzEhY8eioFBeAvBi9z9T5AqFEbXyR+TyX
+AygsnsYUqY06vcfE75PfYrVBK2PtFqbe8verVLkEto+6JUV2iVGyw7xn23iTPa53
+sgwmFL6eie279t+ktGGxGL+45jg=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/cs2_pubCA1_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,56 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 7 (0x7)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ch2_pubCA1/emailAddress=ch2_pubCA1
+        Validity
+            Not Before: Aug  4 20:59:24 2010 GMT
+            Not After : Apr 30 20:59:24 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs2_pubCA1/emailAddress=cs2_pubCA1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:bc:d4:1e:7a:76:36:24:10:2f:84:b3:ed:24:8f:
+                    0b:85:8a:17:39:2f:15:26:0a:80:e2:60:aa:c0:00:
+                    af:d5:ba:9c:ef:b0:3a:09:31:e7:97:37:82:ea:32:
+                    a0:c5:75:c3:0e:0f:6a:77:ef:66:77:2f:6a:a2:60:
+                    5b:b7:86:39:df:12:94:4e:61:79:de:dd:d2:fc:d1:
+                    a0:ba:fe:6a:24:09:3b:4f:1e:35:19:e2:15:25:8b:
+                    7c:03:19:66:3d:10:45:91:9c:83:9a:71:c9:b2:eb:
+                    df:a9:64:c7:2d:5a:93:23:d3:5d:ec:64:03:64:f4:
+                    34:b9:ee:40:1d:df:0c:c5:3d
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 CRL Distribution Points: 
+                URI:http://localhost:12001/file/0/pubCA1_ta1_crl.pem
+
+    Signature Algorithm: sha256WithRSAEncryption
+        39:29:a1:18:73:e2:98:bd:03:ed:99:eb:dc:f3:a3:da:cb:3e:
+        b3:5e:4c:f5:27:2f:c0:9d:7b:d1:3b:97:dc:cc:00:ca:f3:81:
+        48:65:d5:a8:07:42:25:8e:9e:66:38:eb:ca:68:f3:f0:15:95:
+        21:7b:c9:ec:9b:b1:af:dc:63:95:a2:cd:8c:dc:88:f5:7d:37:
+        2f:20:02:ea:b9:c5:e3:64:c2:4a:2d:94:54:10:4e:b9:07:8a:
+        46:99:7c:26:40:82:e5:65:30:df:66:02:6c:17:d8:6e:95:d4:
+        ff:09:25:15:0b:68:7b:ab:84:35:c9:3f:ec:3f:92:76:f2:59:
+        c2:50
+-----BEGIN CERTIFICATE-----
+MIICtTCCAh6gAwIBAgIBBzANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKY2gyX3B1YkNBMTEZMBcGCSqGSIb3DQEJARYKY2gy
+X3B1YkNBMTAeFw0xMDA4MDQyMDU5MjRaFw0xMzA0MzAyMDU5MjRaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjczJfcHViQ0ExMRkwFwYJKoZIhvcN
+AQkBFgpjczJfcHViQ0ExMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC81B56
+djYkEC+Es+0kjwuFihc5LxUmCoDiYKrAAK/VupzvsDoJMeeXN4LqMqDFdcMOD2p3
+72Z3L2qiYFu3hjnfEpROYXne3dL80aC6/mokCTtPHjUZ4hUli3wDGWY9EEWRnIOa
+ccmy69+pZMctWpMj013sZANk9DS57kAd3wzFPQIDAQABo1MwUTAMBgNVHRMBAf8E
+AjAAMEEGA1UdHwQ6MDgwNqA0oDKGMGh0dHA6Ly9sb2NhbGhvc3Q6MTIwMDEvZmls
+ZS8wL3B1YkNBMV90YTFfY3JsLnBlbTANBgkqhkiG9w0BAQsFAAOBgQA5KaEYc+KY
+vQPtmevc86Payz6zXkz1Jy/AnXvRO5fczADK84FIZdWoB0Iljp5mOOvKaPPwFZUh
+e8nsm7Gv3GOVos2M3Ij1fTcvIALqucXjZMJKLZRUEE65B4pGmXwmQILlZTDfZgJs
+F9huldT/CSUVC2h7q4Q1yT/sP5J28lnCUA==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/cs2_ta4_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,67 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 25 (0x19)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta4/emailAddress=pubCA1_ta4
+        Validity
+            Not Before: Aug  4 20:59:29 2010 GMT
+            Not After : Apr 30 20:59:29 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs2_ta4/emailAddress=cs2_ta4
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:d3:11:f2:56:c0:36:ef:ad:7f:18:53:a7:29:77:
+                    9f:6a:82:43:cd:a6:65:0c:5e:ca:39:d9:fa:83:b2:
+                    0d:24:e5:10:ae:85:c5:dc:02:aa:a6:38:4f:31:f3:
+                    b6:ab:47:37:9b:f8:99:80:6c:d3:35:36:81:72:f1:
+                    93:0f:6b:dd:ca:d7:5d:a1:6a:30:74:6e:07:9c:47:
+                    c3:35:69:fc:38:e6:b5:3d:bc:65:e6:ad:67:ea:22:
+                    90:06:d3:eb:aa:64:2f:3e:b3:4c:e1:a4:65:14:8e:
+                    b2:96:85:fc:3c:1d:01:a5:4a:16:1a:b2:84:e9:a8:
+                    03:d1:09:be:7b:3c:3b:0e:ed
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                5A:AE:AB:13:F4:60:55:35:31:96:FF:3F:20:AD:22:DF:EE:C7:4E:D3
+            X509v3 Authority Key Identifier: 
+                keyid:EE:8D:78:53:11:FE:07:CB:C8:55:4B:EF:A6:2F:E1:83:72:BB:BA:21
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta4/emailAddress=ta4
+                serial:17
+
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 CRL Distribution Points: 
+                URI:http://localhost:12001/file/0/example_file
+
+    Signature Algorithm: sha256WithRSAEncryption
+        4d:74:90:ac:a2:9c:93:39:0c:41:a7:c1:2b:73:56:97:14:32:
+        8d:64:01:78:82:a1:6f:a6:9c:3d:f5:75:80:3e:e2:b5:6c:cf:
+        c8:f2:21:46:05:e2:30:da:ce:41:88:96:87:ac:7b:a6:42:2a:
+        96:f7:1e:8d:4c:92:43:97:8f:99:08:29:47:ce:95:fb:7a:4e:
+        84:2c:0b:80:4b:c9:bf:a1:dc:0b:63:c6:9c:4f:c4:59:12:39:
+        e5:97:ee:6b:6e:86:33:18:43:da:16:5e:51:24:d0:0d:05:92:
+        7d:12:89:cd:21:fc:4e:52:86:9a:02:f9:5e:51:38:62:55:33:
+        d3:db
+-----BEGIN CERTIFICATE-----
+MIIDYDCCAsmgAwIBAgIBGTANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0ExX3RhNDEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0ExX3RhNDAeFw0xMDA4MDQyMDU5MjlaFw0xMzA0MzAyMDU5MjlaMHAxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRAwDgYDVQQDFAdjczJfdGE0MRYwFAYJKoZIhvcNAQkB
+FgdjczJfdGE0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDTEfJWwDbvrX8Y
+U6cpd59qgkPNpmUMXso52fqDsg0k5RCuhcXcAqqmOE8x87arRzeb+JmAbNM1NoFy
+8ZMPa93K112hajB0bgecR8M1afw45rU9vGXmrWfqIpAG0+uqZC8+s0zhpGUUjrKW
+hfw8HQGlShYasoTpqAPRCb57PDsO7QIDAQABo4IBAjCB/zAdBgNVHQ4EFgQUWq6r
+E/RgVTUxlv8/IK0i3+7HTtMwgZIGA1UdIwSBijCBh4AU7o14UxH+B8vIVUvvpi/h
+g3K7uiGhbKRqMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMw
+EQYDVQQHEwpNZW5sbyBQYXJrMQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTQx
+EjAQBgkqhkiG9w0BCQEWA3RhNIIBFzAMBgNVHRMBAf8EAjAAMDsGA1UdHwQ0MDIw
+MKAuoCyGKmh0dHA6Ly9sb2NhbGhvc3Q6MTIwMDEvZmlsZS8wL2V4YW1wbGVfZmls
+ZTANBgkqhkiG9w0BAQsFAAOBgQBNdJCsopyTOQxBp8Erc1aXFDKNZAF4gqFvppw9
+9XWAPuK1bM/I8iFGBeIw2s5BiJaHrHumQiqW9x6NTJJDl4+ZCClHzpX7ek6ELAuA
+S8m/odwLY8acT8RZEjnll+5rboYzGEPaFl5RJNANBZJ9EonNIfxOUoaaAvleUThi
+VTPT2w==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/cs3_p1_ta3_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,54 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 15 (0xf)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta3/emailAddress=pubCA1_ta3
+        Validity
+            Not Before: Jan  1 01:01:01 2009 GMT
+            Not After : Jan  2 01:01:01 2009 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs3_p1_ta3/emailAddress=cs3_p1_ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:ce:9e:aa:9a:44:62:e4:9d:f2:cd:d1:ef:39:cc:
+                    cb:b8:e9:1a:06:cf:7e:e4:e1:99:52:e0:5a:17:a9:
+                    78:b3:e7:25:c0:97:f8:72:d4:75:50:c5:d9:84:84:
+                    90:cc:53:5e:46:c0:66:d8:0a:76:0c:cf:f7:ff:f8:
+                    fd:e9:f4:60:88:49:74:97:3d:34:f0:90:da:97:5d:
+                    40:1e:78:cb:bf:84:1b:c2:7e:70:cb:b6:79:26:7d:
+                    62:a1:63:60:0b:9f:b3:5a:5f:13:a8:1c:5e:f5:39:
+                    0c:14:d4:67:58:16:09:3b:cf:5c:4a:4a:e6:17:80:
+                    90:69:b5:6d:8d:c8:27:88:9d
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+    Signature Algorithm: sha256WithRSAEncryption
+        41:c7:40:05:62:dd:88:6f:07:66:78:9b:56:0d:55:77:9e:b7:
+        d1:08:f6:b1:59:cd:85:72:b3:19:fd:0f:c7:4f:a9:54:52:6a:
+        4b:f0:c2:d1:35:6c:1c:cd:71:ee:6f:61:c3:a9:a2:f9:13:68:
+        6a:56:f9:95:c6:da:82:61:9d:de:dd:4b:e1:42:2f:db:80:62:
+        49:31:45:60:c8:d6:3d:1b:49:82:6f:df:1c:a4:ca:01:9a:6f:
+        bc:ff:9e:a8:ec:42:f8:22:f9:70:b3:3a:e6:e2:3e:d2:18:58:
+        89:95:d8:01:fe:b1:25:5e:bc:a2:70:1c:59:5d:e5:af:b1:02:
+        ac:d3
+-----BEGIN CERTIFICATE-----
+MIICfzCCAeigAwIBAgIBDzANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0ExX3RhMzEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0ExX3RhMzAeFw0wOTAxMDEwMTAxMDFaFw0wOTAxMDIwMTAxMDFaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjczNfcDFfdGEzMRkwFwYJKoZIhvcN
+AQkBFgpjczNfcDFfdGEzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOnqqa
+RGLknfLN0e85zMu46RoGz37k4ZlS4FoXqXiz5yXAl/hy1HVQxdmEhJDMU15GwGbY
+CnYMz/f/+P3p9GCISXSXPTTwkNqXXUAeeMu/hBvCfnDLtnkmfWKhY2ALn7NaXxOo
+HF71OQwU1GdYFgk7z1xKSuYXgJBptW2NyCeInQIDAQABox0wGzAMBgNVHRMBAf8E
+AjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQsFAAOBgQBBx0AFYt2IbwdmeJtW
+DVV3nrfRCPaxWc2FcrMZ/Q/HT6lUUmpL8MLRNWwczXHub2HDqaL5E2hqVvmVxtqC
+YZ3e3UvhQi/bgGJJMUVgyNY9G0mCb98cpMoBmm+8/56o7EL4Ivlwszrm4j7SGFiJ
+ldgB/rElXryicBxZXeWvsQKs0w==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/cs3_pubCA1_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,56 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 8 (0x8)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ch2_pubCA1/emailAddress=ch2_pubCA1
+        Validity
+            Not Before: Aug  4 20:59:24 2010 GMT
+            Not After : Apr 30 20:59:24 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs3_pubCA1/emailAddress=cs3_pubCA1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:ae:1e:e7:bd:54:fe:74:88:e0:34:0d:32:b2:1b:
+                    ea:3e:63:fd:7b:1b:13:cc:84:29:e1:f8:7d:c4:9c:
+                    65:aa:3a:2b:fd:c9:7c:03:57:03:b2:12:75:b9:c9:
+                    5e:02:a4:8e:6d:c7:54:c1:cd:e1:30:28:5f:a8:64:
+                    c9:c2:02:e2:3b:af:5e:b3:ec:2c:1c:5c:48:50:07:
+                    87:e4:19:80:ef:b4:78:6f:f2:6f:dd:64:61:97:ce:
+                    a7:29:0a:07:3c:6f:2e:44:fe:38:70:5b:c6:44:bb:
+                    cf:f5:3f:b3:20:3b:3b:81:fa:77:25:ab:1f:4f:f6:
+                    db:28:fd:7f:ba:2f:57:18:47
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 CRL Distribution Points: 
+                URI:http://localhost:12001/file/0/ch1_pubCA1_crl.pem
+
+    Signature Algorithm: sha256WithRSAEncryption
+        22:d6:f3:a1:9f:65:9a:2d:d1:3f:50:ea:ba:52:99:1e:1f:95:
+        38:e4:e0:cb:7e:fc:7f:5a:82:75:a4:fa:23:64:7b:4f:63:b1:
+        b5:30:34:38:8e:d1:54:13:a6:1e:7b:3b:f0:3e:94:54:1e:a4:
+        5c:19:3c:38:18:d7:ee:b0:31:ea:ac:d1:b2:18:4b:a7:19:93:
+        45:8f:a2:b6:cf:0b:39:73:b6:80:2e:3d:48:de:18:af:98:4e:
+        cc:15:a2:a4:98:a0:d1:03:36:05:b1:e7:81:94:3b:cd:da:b2:
+        fc:2b:ff:9f:e5:fe:9c:b8:2b:5c:1a:75:00:58:54:a3:f1:4e:
+        cf:53
+-----BEGIN CERTIFICATE-----
+MIICtTCCAh6gAwIBAgIBCDANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKY2gyX3B1YkNBMTEZMBcGCSqGSIb3DQEJARYKY2gy
+X3B1YkNBMTAeFw0xMDA4MDQyMDU5MjRaFw0xMzA0MzAyMDU5MjRaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjczNfcHViQ0ExMRkwFwYJKoZIhvcN
+AQkBFgpjczNfcHViQ0ExMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCuHue9
+VP50iOA0DTKyG+o+Y/17GxPMhCnh+H3EnGWqOiv9yXwDVwOyEnW5yV4CpI5tx1TB
+zeEwKF+oZMnCAuI7r16z7CwcXEhQB4fkGYDvtHhv8m/dZGGXzqcpCgc8by5E/jhw
+W8ZEu8/1P7MgOzuB+nclqx9P9tso/X+6L1cYRwIDAQABo1MwUTAMBgNVHRMBAf8E
+AjAAMEEGA1UdHwQ6MDgwNqA0oDKGMGh0dHA6Ly9sb2NhbGhvc3Q6MTIwMDEvZmls
+ZS8wL2NoMV9wdWJDQTFfY3JsLnBlbTANBgkqhkiG9w0BAQsFAAOBgQAi1vOhn2Wa
+LdE/UOq6UpkeH5U45ODLfvx/WoJ1pPojZHtPY7G1MDQ4jtFUE6YeezvwPpRUHqRc
+GTw4GNfusDHqrNGyGEunGZNFj6K2zws5c7aALj1I3hivmE7MFaKkmKDRAzYFseeB
+lDvN2rL8K/+f5f6cuCtcGnUAWFSj8U7PUw==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/cs3_ta4_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,66 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 26 (0x1a)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta4/emailAddress=pubCA1_ta4
+        Validity
+            Not Before: Aug  4 20:59:29 2010 GMT
+            Not After : Apr 30 20:59:29 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs3_ta4/emailAddress=cs3_ta4
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:b2:66:56:2e:29:80:41:b1:f4:0f:03:7d:94:35:
+                    7d:67:5f:a6:df:49:c8:47:d8:53:03:0b:97:bb:01:
+                    fb:ba:86:6e:5b:f1:f6:b2:50:fd:c6:4a:8f:16:0d:
+                    4c:6b:95:72:55:a1:26:c1:db:8a:f1:16:e5:06:45:
+                    72:78:5c:54:fa:4b:3e:b2:e9:68:a9:68:4f:c8:19:
+                    8d:40:c1:07:3b:82:b5:ea:60:7c:8f:94:9f:27:81:
+                    79:1e:03:f1:ac:90:42:6b:6f:87:1e:ea:b9:a8:c5:
+                    b1:a4:2a:ff:8c:1c:37:aa:7d:eb:7c:70:2a:5f:e6:
+                    56:60:84:46:e5:a2:3b:11:79
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                98:85:12:48:CD:F8:29:DD:17:72:03:5C:40:02:E6:50:F6:24:E7:2D
+            X509v3 Authority Key Identifier: 
+                keyid:EE:8D:78:53:11:FE:07:CB:C8:55:4B:EF:A6:2F:E1:83:72:BB:BA:21
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta4/emailAddress=ta4
+                serial:17
+
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 CRL Distribution Points: 
+                URI:foo://bar/baz
+
+    Signature Algorithm: sha256WithRSAEncryption
+        49:ac:6c:a5:ab:c6:c7:ad:f3:93:47:d4:74:7f:4a:d3:46:b0:
+        71:6f:6e:42:e2:7f:f6:ed:db:38:ed:29:09:e1:e0:a0:a7:4c:
+        ec:17:56:a8:71:71:20:2a:da:f0:19:4d:e2:13:3c:6e:db:6a:
+        16:3a:46:63:15:7b:3c:a2:70:f1:6c:14:35:5b:51:80:1c:7e:
+        2c:93:23:ac:31:46:ea:7a:cf:8a:80:b9:45:95:67:ea:b7:c1:
+        cf:b7:0d:99:7b:72:37:29:4d:b3:a0:31:94:e4:55:79:9d:f2:
+        fa:18:c3:f5:fe:77:93:91:17:f1:ce:b7:ae:39:00:b1:5b:98:
+        ab:81
+-----BEGIN CERTIFICATE-----
+MIIDQjCCAqugAwIBAgIBGjANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0ExX3RhNDEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0ExX3RhNDAeFw0xMDA4MDQyMDU5MjlaFw0xMzA0MzAyMDU5MjlaMHAxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRAwDgYDVQQDFAdjczNfdGE0MRYwFAYJKoZIhvcNAQkB
+FgdjczNfdGE0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyZlYuKYBBsfQP
+A32UNX1nX6bfSchH2FMDC5e7Afu6hm5b8fayUP3GSo8WDUxrlXJVoSbB24rxFuUG
+RXJ4XFT6Sz6y6WipaE/IGY1AwQc7grXqYHyPlJ8ngXkeA/GskEJrb4ce6rmoxbGk
+Kv+MHDeqfet8cCpf5lZghEblojsReQIDAQABo4HlMIHiMB0GA1UdDgQWBBSYhRJI
+zfgp3RdyA1xAAuZQ9iTnLTCBkgYDVR0jBIGKMIGHgBTujXhTEf4Hy8hVS++mL+GD
+cru6IaFspGowaDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEzAR
+BgNVBAcTCk1lbmxvIFBhcmsxDTALBgNVBAoTBHBrZzUxDDAKBgNVBAMTA3RhNDES
+MBAGCSqGSIb3DQEJARYDdGE0ggEXMAwGA1UdEwEB/wQCMAAwHgYDVR0fBBcwFTAT
+oBGgD4YNZm9vOi8vYmFyL2JhejANBgkqhkiG9w0BAQsFAAOBgQBJrGylq8bHrfOT
+R9R0f0rTRrBxb25C4n/27ds47SkJ4eCgp0zsF1aocXEgKtrwGU3iEzxu22oWOkZj
+FXs8onDxbBQ1W1GAHH4skyOsMUbqes+KgLlFlWfqt8HPtw2Ze3I3KU2zoDGU5FV5
+nfL6GMP1/neTkRfxzreuOQCxW5irgQ==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/cs4_p1_ta3_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,54 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 16 (0x10)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta3/emailAddress=pubCA1_ta3
+        Validity
+            Not Before: Jan  1 01:01:01 2035 GMT
+            Not After : Jan  2 01:01:01 2035 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs4_p1_ta3/emailAddress=cs4_p1_ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:a5:72:6c:c4:dc:df:15:f5:b0:2f:fb:d2:e2:d9:
+                    f2:2c:5e:0a:c5:04:34:99:0f:06:13:9a:e8:86:2d:
+                    44:2f:57:67:81:a1:93:0e:cd:b5:4b:ca:1a:4b:31:
+                    c6:a7:73:b3:70:66:21:03:6a:cd:a5:bf:4a:6d:96:
+                    d8:50:9e:95:d7:42:84:86:80:f1:15:3f:5c:85:8f:
+                    dd:ee:13:61:c9:2c:71:c1:c1:cb:e8:e9:4d:eb:ce:
+                    d9:57:98:2d:93:81:0e:fb:6d:00:31:9d:db:6f:c2:
+                    aa:b1:36:65:0d:8d:82:7b:e7:df:7c:03:76:f9:b8:
+                    6c:6e:7e:13:5d:85:ac:c0:89
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+    Signature Algorithm: sha256WithRSAEncryption
+        5f:7c:e0:ae:58:97:b0:36:1e:a7:28:61:9c:0d:2e:cb:34:22:
+        b3:18:7d:d9:0d:2e:2e:0e:0c:79:1f:5e:14:37:c3:cf:7a:41:
+        60:76:a5:0e:ea:c9:eb:f3:5c:7f:0f:39:2e:dc:b8:58:9b:d9:
+        f6:37:f9:53:22:a1:07:57:f9:4e:e3:0e:5b:31:15:7e:88:8d:
+        78:48:18:d5:f9:3a:dd:0b:4a:41:5b:c1:e0:32:8b:3a:ef:ad:
+        36:c8:26:e8:25:52:f7:94:19:99:6e:ff:ec:ac:f3:34:6e:f4:
+        ef:73:e9:6f:2c:8e:c3:96:09:b5:25:68:f9:ce:5c:40:07:47:
+        36:8a
+-----BEGIN CERTIFICATE-----
+MIICfzCCAeigAwIBAgIBEDANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0ExX3RhMzEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0ExX3RhMzAeFw0zNTAxMDEwMTAxMDFaFw0zNTAxMDIwMTAxMDFaMHYxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MRMwEQYDVQQDFApjczRfcDFfdGEzMRkwFwYJKoZIhvcN
+AQkBFgpjczRfcDFfdGEzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQClcmzE
+3N8V9bAv+9Li2fIsXgrFBDSZDwYTmuiGLUQvV2eBoZMOzbVLyhpLMcanc7NwZiED
+as2lv0ptlthQnpXXQoSGgPEVP1yFj93uE2HJLHHBwcvo6U3rztlXmC2TgQ77bQAx
+ndtvwqqxNmUNjYJ75998A3b5uGxufhNdhazAiQIDAQABox0wGzAMBgNVHRMBAf8E
+AjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQsFAAOBgQBffOCuWJewNh6nKGGc
+DS7LNCKzGH3ZDS4uDgx5H14UN8PPekFgdqUO6snr81x/Dzku3LhYm9n2N/lTIqEH
+V/lO4w5bMRV+iI14SBjV+TrdC0pBW8HgMos67602yCboJVL3lBmZbv/srPM0bvTv
+c+lvLI7Dlgm1JWj5zlxAB0c2ig==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/code_signing_certs/cs4_pubCA1_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,54 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 10 (0xa)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ch2.2_pubCA1/emailAddress=ch2.2_pubCA1
+        Validity
+            Not Before: Aug  4 20:59:25 2010 GMT
+            Not After : Apr 30 20:59:25 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=cs4_pubCA1/emailAddress=cs4_pubCA1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:b7:e6:67:c1:7f:08:9e:27:00:00:ce:8e:e4:5b:
+                    f5:65:d0:f2:4e:ac:d4:07:b8:21:a2:5a:9b:bd:e3:
+                    48:24:ff:f1:ec:05:49:c2:34:5a:ca:f5:9b:91:2b:
+                    3c:6a:31:ea:3b:25:53:c9:09:3b:2b:24:32:8b:8c:
+                    4c:30:95:78:e9:7c:f0:d7:bc:f8:4e:24:8b:c5:dd:
+                    b4:50:5a:a8:68:78:15:ee:52:73:6e:5a:9a:f9:dd:
+                    7c:39:90:f1:ef:bf:e5:a5:18:dc:d4:d8:a1:8f:2e:
+                    6a:9c:17:dc:20:93:59:e6:c4:3d:bb:f2:a8:0e:ea:
+                    1a:be:a9:54:7f:a2:7b:48:73
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Key Usage: 
+                Digital Signature
+    Signature Algorithm: sha256WithRSAEncryption
+        6a:34:f8:4a:4b:80:50:1e:e8:bd:17:75:d4:c5:e5:30:b7:63:
+        2f:18:18:e8:24:38:ec:a3:e9:a9:39:f0:2c:4c:83:22:b6:ed:
+        38:9e:08:d4:3e:3d:b6:5e:2f:2d:cd:84:43:60:92:f0:1e:6c:
+        06:6a:86:f3:d9:bb:c7:1c:77:aa:21:b0:0d:34:c6:86:b2:7c:
+        cc:66:12:89:16:eb:39:a6:2f:2b:4b:0e:95:87:4f:28:e3:62:
+        73:c2:99:68:26:ee:5f:e4:64:99:d1:a7:b7:25:66:a8:19:f3:
+        36:c5:b8:1e:7e:ed:10:af:6e:38:a9:9a:03:55:3f:2f:4e:2a:
+        af:9a
+-----BEGIN CERTIFICATE-----
+MIICgzCCAeygAwIBAgIBCjANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEVMBMGA1UEAxQMY2gyLjJfcHViQ0ExMRswGQYJKoZIhvcNAQkBFgxj
+aDIuMl9wdWJDQTEwHhcNMTAwODA0MjA1OTI1WhcNMTMwNDMwMjA1OTI1WjB2MQsw
+CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8g
+UGFyazENMAsGA1UEChMEcGtnNTETMBEGA1UEAxQKY3M0X3B1YkNBMTEZMBcGCSqG
+SIb3DQEJARYKY3M0X3B1YkNBMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
+t+ZnwX8InicAAM6O5Fv1ZdDyTqzUB7gholqbveNIJP/x7AVJwjRayvWbkSs8ajHq
+OyVTyQk7KyQyi4xMMJV46Xzw17z4TiSLxd20UFqoaHgV7lJzblqa+d18OZDx77/l
+pRjc1Nihjy5qnBfcIJNZ5sQ9u/KoDuoavqlUf6J7SHMCAwEAAaMdMBswDAYDVR0T
+AQH/BAIwADALBgNVHQ8EBAMCB4AwDQYJKoZIhvcNAQELBQADgYEAajT4SkuAUB7o
+vRd11MXlMLdjLxgY6CQ47KPpqTnwLEyDIrbtOJ4I1D49tl4vLc2EQ2CS8B5sBmqG
+89m7xxx3qiGwDTTGhrJ8zGYSiRbrOaYvK0sOlYdPKONic8KZaCbuX+RkmdGntyVm
+qBnzNsW4Hn7tEK9uOKmaA1U/L04qr5o=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/crl/ch1_pubCA1_crl.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,30 @@
+Certificate Revocation List (CRL):
+        Version 1 (0x0)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: /C=US/ST=California/L=Menlo Park/O=pkg5/CN=ch1_pubCA1/emailAddress=ch1_pubCA1
+        Last Update: Aug  4 20:59:24 2010 GMT
+        Next Update: Apr 30 20:59:24 2013 GMT
+Revoked Certificates:
+    Serial Number: 07
+        Revocation Date: Aug  4 20:59:24 2010 GMT
+    Serial Number: 08
+        Revocation Date: Aug  4 20:59:24 2010 GMT
+    Signature Algorithm: sha256WithRSAEncryption
+        65:24:c6:61:0a:72:59:69:de:5e:a4:c8:a5:c8:35:06:30:39:
+        da:b3:ad:a9:cb:1b:f4:9b:ad:45:64:63:b2:ff:2b:bb:e7:65:
+        55:aa:84:0b:e4:bd:fd:a8:51:50:a6:c3:14:11:34:1c:85:8a:
+        d9:b2:20:a0:4c:f5:01:fd:cd:b0:5e:59:a6:b2:7b:a9:14:4e:
+        ad:bc:95:5b:68:ab:d1:ec:89:1a:07:48:a7:d8:f1:ba:b6:38:
+        e6:60:dc:41:6e:16:9c:9d:83:c6:b9:72:3e:c3:7c:b6:de:b7:
+        cc:5c:b2:bf:28:ea:64:d4:de:e8:a6:84:ec:fa:15:92:90:0f:
+        92:44
+-----BEGIN X509 CRL-----
+MIIBZTCBzzANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzETMBEGA1UECBMK
+Q2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UEChMEcGtnNTET
+MBEGA1UEAxQKY2gxX3B1YkNBMTEZMBcGCSqGSIb3DQEJARYKY2gxX3B1YkNBMRcN
+MTAwODA0MjA1OTI0WhcNMTMwNDMwMjA1OTI0WjAoMBICAQcXDTEwMDgwNDIwNTky
+NFowEgIBCBcNMTAwODA0MjA1OTI0WjANBgkqhkiG9w0BAQsFAAOBgQBlJMZhCnJZ
+ad5epMilyDUGMDnas62pyxv0m61FZGOy/yu752VVqoQL5L39qFFQpsMUETQchYrZ
+siCgTPUB/c2wXlmmsnupFE6tvJVbaKvR7IkaB0in2PG6tjjmYNxBbhacnYPGuXI+
+w3y23rfMXLK/KOpk1N7opoTs+hWSkA+SRA==
+-----END X509 CRL-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/crl/pubCA1_ta1_crl.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,28 @@
+Certificate Revocation List (CRL):
+        Version 1 (0x0)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: /C=US/ST=California/L=Menlo Park/O=pkg5/CN=pubCA1_ta1/emailAddress=pubCA1_ta1
+        Last Update: Aug  4 20:59:24 2010 GMT
+        Next Update: Apr 30 20:59:24 2013 GMT
+Revoked Certificates:
+    Serial Number: 07
+        Revocation Date: Aug  4 20:59:24 2010 GMT
+    Signature Algorithm: sha256WithRSAEncryption
+        81:6e:ef:a2:08:9b:98:1a:56:15:c9:12:20:84:a6:43:50:f6:
+        bd:1f:88:0d:54:cd:00:65:d4:92:1a:0f:b0:2b:23:5b:b6:94:
+        08:5d:fd:86:73:ae:d6:27:6e:05:b6:15:59:e9:1e:d3:39:b2:
+        91:29:97:d7:fd:c4:73:b4:5e:85:4c:e5:85:88:d6:0e:34:5d:
+        19:50:de:ec:24:9c:46:7e:a4:2f:81:d0:79:71:a0:bb:d8:c2:
+        4c:95:16:00:b5:8f:36:17:b2:61:57:8c:d5:a9:be:98:1b:05:
+        44:4d:66:ff:de:d6:fd:94:60:81:3c:ad:b7:1b:70:91:6d:2c:
+        82:7f
+-----BEGIN X509 CRL-----
+MIIBUTCBuzANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzETMBEGA1UECBMK
+Q2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UEChMEcGtnNTET
+MBEGA1UEAxQKcHViQ0ExX3RhMTEZMBcGCSqGSIb3DQEJARYKcHViQ0ExX3RhMRcN
+MTAwODA0MjA1OTI0WhcNMTMwNDMwMjA1OTI0WjAUMBICAQcXDTEwMDgwNDIwNTky
+NFowDQYJKoZIhvcNAQELBQADgYEAgW7vogibmBpWFckSIISmQ1D2vR+IDVTNAGXU
+khoPsCsjW7aUCF39hnOu1iduBbYVWeke0zmykSmX1/3Ec7RehUzlhYjWDjRdGVDe
+7CScRn6kL4HQeXGgu9jCTJUWALWPNheyYVeM1am+mBsFRE1m/97W/ZRggTyttxtw
+kW0sgn8=
+-----END X509 CRL-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/crl/pubCA1_ta4_crl.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,32 @@
+Certificate Revocation List (CRL):
+        Version 1 (0x0)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: /C=US/ST=California/L=Menlo Park/O=pkg5/CN=pubCA1_ta4/emailAddress=pubCA1_ta4
+        Last Update: Aug  4 20:59:28 2010 GMT
+        Next Update: Apr 30 20:59:28 2013 GMT
+Revoked Certificates:
+    Serial Number: 07
+        Revocation Date: Aug  4 20:59:24 2010 GMT
+    Serial Number: 08
+        Revocation Date: Aug  4 20:59:24 2010 GMT
+    Serial Number: 18
+        Revocation Date: Aug  4 20:59:28 2010 GMT
+    Signature Algorithm: sha256WithRSAEncryption
+        45:47:01:04:a3:e9:cf:1c:cc:43:e6:00:23:34:57:eb:9e:f4:
+        7c:93:88:70:61:dd:6b:b8:7c:8c:97:19:3e:08:f2:f2:64:81:
+        f9:de:62:60:aa:8d:81:f2:c5:f2:6e:42:d4:7e:6b:e0:2c:6c:
+        c1:38:05:0a:84:c5:e2:68:28:b4:82:d1:76:35:0a:43:95:9e:
+        3f:16:48:6d:e1:27:c8:9a:22:fa:e2:63:13:bd:7c:15:4f:e0:
+        d0:39:be:dc:19:97:9a:cf:08:38:17:f0:2c:9f:bf:a4:cf:be:
+        ad:4c:1e:aa:96:96:d8:08:3f:61:ee:c0:b1:78:c2:57:dc:40:
+        66:31
+-----BEGIN X509 CRL-----
+MIIBeTCB4zANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzETMBEGA1UECBMK
+Q2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UEChMEcGtnNTET
+MBEGA1UEAxQKcHViQ0ExX3RhNDEZMBcGCSqGSIb3DQEJARYKcHViQ0ExX3RhNBcN
+MTAwODA0MjA1OTI4WhcNMTMwNDMwMjA1OTI4WjA8MBICAQcXDTEwMDgwNDIwNTky
+NFowEgIBCBcNMTAwODA0MjA1OTI0WjASAgEYFw0xMDA4MDQyMDU5MjhaMA0GCSqG
+SIb3DQEBCwUAA4GBAEVHAQSj6c8czEPmACM0V+ue9HyTiHBh3Wu4fIyXGT4I8vJk
+gfneYmCqjYHyxfJuQtR+a+AsbME4BQqExeJoKLSC0XY1CkOVnj8WSG3hJ8iaIvri
+YxO9fBVP4NA5vtwZl5rPCDgX8Cyfv6TPvq1MHqqWltgIP2HuwLF4wlfcQGYx
+-----END X509 CRL-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/crl/ta5_crl.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,35 @@
+Certificate Revocation List (CRL):
+        Version 1 (0x0)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: /C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta5/emailAddress=ta5
+        Last Update: Aug  4 20:59:29 2010 GMT
+        Next Update: Apr 30 20:59:29 2013 GMT
+Revoked Certificates:
+    Serial Number: 07
+        Revocation Date: Aug  4 20:59:24 2010 GMT
+    Serial Number: 08
+        Revocation Date: Aug  4 20:59:24 2010 GMT
+    Serial Number: 18
+        Revocation Date: Aug  4 20:59:28 2010 GMT
+    Serial Number: 1B
+        Revocation Date: Aug  4 20:59:29 2010 GMT
+    Signature Algorithm: sha256WithRSAEncryption
+        8e:92:e0:14:21:89:5b:01:ae:c8:d7:88:ce:fd:18:2b:e3:25:
+        31:9c:2a:a7:41:3c:d1:e1:d7:de:73:95:3b:7f:01:04:0d:46:
+        6f:e1:9a:da:57:63:25:cc:d6:d9:d3:4b:ed:43:fd:6c:a0:96:
+        a1:e9:5a:e0:b2:c4:2b:fd:ae:0a:8d:2b:08:1e:0e:d7:fe:8d:
+        f5:bf:e0:fe:7b:4d:c8:2d:ac:51:8c:0a:cb:b0:77:51:c3:09:
+        ed:4a:75:5b:c7:77:bb:31:9e:62:3f:33:af:95:82:94:83:7c:
+        36:de:b0:e8:7a:b1:e3:7d:86:c0:7f:d8:84:74:73:7c:4b:36:
+        f7:07
+-----BEGIN X509 CRL-----
+MIIBfzCB6TANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJVUzETMBEGA1UECBMK
+Q2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UEChMEcGtnNTEM
+MAoGA1UEAxMDdGE1MRIwEAYJKoZIhvcNAQkBFgN0YTUXDTEwMDgwNDIwNTkyOVoX
+DTEzMDQzMDIwNTkyOVowUDASAgEHFw0xMDA4MDQyMDU5MjRaMBICAQgXDTEwMDgw
+NDIwNTkyNFowEgIBGBcNMTAwODA0MjA1OTI4WjASAgEbFw0xMDA4MDQyMDU5Mjla
+MA0GCSqGSIb3DQEBCwUAA4GBAI6S4BQhiVsBrsjXiM79GCvjJTGcKqdBPNHh195z
+lTt/AQQNRm/hmtpXYyXM1tnTS+1D/WyglqHpWuCyxCv9rgqNKwgeDtf+jfW/4P57
+TcgtrFGMCsuwd1HDCe1KdVvHd7sxnmI/M6+VgpSDfDbesOh6seN9hsB/2IR0c3xL
+NvcH
+-----END X509 CRL-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/index	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,28 @@
+V	130430205923Z		01	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=i1_ta1/emailAddress=i1_ta1
+V	130430205923Z		02	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=i2_ta1/emailAddress=i2_ta1
+V	130430205923Z		03	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=pubCA1_ta1/emailAddress=pubCA1_ta1
+V	130430205923Z		04	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ch1_pubCA1/emailAddress=ch1_pubCA1
+V	130430205923Z		05	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ch2_pubCA1/emailAddress=ch2_pubCA1
+V	130430205924Z		06	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=cs1_pubCA1/emailAddress=cs1_pubCA1
+R	130430205924Z	100804205924Z	07	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=cs2_pubCA1/emailAddress=cs2_pubCA1
+R	130430205924Z	100804205924Z	08	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=cs3_pubCA1/emailAddress=cs3_pubCA1
+V	130430205924Z		09	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ch2.2_pubCA1/emailAddress=ch2.2_pubCA1
+V	130430205925Z		0A	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=cs4_pubCA1/emailAddress=cs4_pubCA1
+V	130430205925Z		0B	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=cs1_ta2/emailAddress=cs1_ta2
+V	130430205925Z		0C	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=pubCA1_ta3/emailAddress=pubCA1_ta3
+V	130430205925Z		0D	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=cs1_p1_ta3/emailAddress=cs1_p1_ta3
+V	130430205926Z		0E	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=cs2_p1_ta3/emailAddress=cs2_p1_ta3
+V	090102010101Z		0F	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=cs3_p1_ta3/emailAddress=cs3_p1_ta3
+V	350102010101Z		10	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=cs4_p1_ta3/emailAddress=cs4_p1_ta3
+V	130430205927Z		11	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=pubCA2_ta3/emailAddress=pubCA2_ta3
+V	130430205927Z		12	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=cs1_p2_ta3/emailAddress=cs1_p2_ta3
+V	090102010101Z		13	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=pubCA3_ta3/emailAddress=pubCA3_ta3
+V	130430205927Z		14	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=cs1_p3_ta3/emailAddress=cs1_p3_ta3
+V	350102010101Z		15	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=pubCA4_ta3/emailAddress=pubCA4_ta3
+V	130430205928Z		16	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=cs1_p4_ta3/emailAddress=cs1_p4_ta3
+V	130430205928Z		17	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=pubCA1_ta4/emailAddress=pubCA1_ta4
+R	130430205928Z	100804205928Z	18	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=cs1_ta4/emailAddress=cs1_ta4
+V	130430205929Z		19	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=cs2_ta4/emailAddress=cs2_ta4
+V	130430205929Z		1A	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=cs3_ta4/emailAddress=cs3_ta4
+R	130430205929Z	100804205929Z	1B	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=pubCA1_ta5/emailAddress=pubCA1_ta5
+V	130430205929Z		1C	unknown	/C=US/ST=California/L=Menlo Park/O=pkg5/CN=cs1_ta5/emailAddress=cs1_ta5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/index.attr	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,1 @@
+unique_subject = no
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/inter_certs/01.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,62 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta1/emailAddress=ta1
+        Validity
+            Not Before: Aug  4 20:59:23 2010 GMT
+            Not After : Apr 30 20:59:23 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=i1_ta1/emailAddress=i1_ta1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:c6:a6:ce:f9:00:3f:47:3e:3c:72:b0:a7:d8:29:
+                    ec:13:8a:8b:95:d9:c1:93:c2:af:50:f9:21:56:36:
+                    40:5c:8b:08:99:bd:56:5d:91:56:46:5c:e8:ad:44:
+                    ca:8b:b5:29:03:58:a4:e4:19:b3:31:9e:b7:39:ee:
+                    5e:2b:45:a0:36:5c:0c:63:f7:e4:ce:ff:27:e2:bd:
+                    72:3d:fe:a5:36:b8:c6:87:04:8a:78:94:40:56:3f:
+                    8b:da:32:82:99:6c:19:63:ea:a3:c2:21:a2:b9:99:
+                    86:d6:b0:70:38:2e:4f:5b:37:00:ac:c5:8e:73:9f:
+                    3d:cb:ae:0c:6e:b8:d4:1e:31
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                56:66:FB:5E:DF:02:EF:B8:8E:E1:8A:AF:6D:9B:6A:CD:F6:BF:8B:6C
+            X509v3 Authority Key Identifier: 
+                keyid:BB:C9:C7:62:4B:87:B7:6A:32:3F:A5:51:7B:C1:3A:8E:3F:06:5C:F7
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta1/emailAddress=ta1
+                serial:CB:CF:1D:CD:F3:A6:CD:09
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        a2:a3:72:b1:14:ad:a0:f9:c7:4c:76:bb:6d:1e:eb:0d:f9:75:
+        2e:d4:56:30:ac:78:24:9a:1b:9e:78:28:9f:24:da:56:17:9f:
+        fc:e6:18:3d:ce:2a:4e:3a:7d:fe:71:c9:dd:a3:57:ed:7d:ca:
+        f4:6f:f8:e8:fe:7f:b0:db:c3:1b:c8:d2:1b:e1:93:13:df:9f:
+        5c:a7:56:1e:60:91:2d:bd:51:f7:70:80:50:57:c5:78:f0:7f:
+        67:a8:57:08:06:59:0d:04:54:6d:7d:d2:4f:27:d4:c1:dc:73:
+        03:52:e4:69:e6:e9:c4:3a:6d:64:db:21:47:8e:7d:c8:3e:9d:
+        48:3b
+-----BEGIN CERTIFICATE-----
+MIIDHTCCAoagAwIBAgIBATANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEMMAoGA1UEAxMDdGExMRIwEAYJKoZIhvcNAQkBFgN0YTEwHhcNMTAw
+ODA0MjA1OTIzWhcNMTMwNDMwMjA1OTIzWjBuMQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UEChMEcGtn
+NTEPMA0GA1UEAxQGaTFfdGExMRUwEwYJKoZIhvcNAQkBFgZpMV90YTEwgZ8wDQYJ
+KoZIhvcNAQEBBQADgY0AMIGJAoGBAMamzvkAP0c+PHKwp9gp7BOKi5XZwZPCr1D5
+IVY2QFyLCJm9Vl2RVkZc6K1Eyou1KQNYpOQZszGetznuXitFoDZcDGP35M7/J+K9
+cj3+pTa4xocEiniUQFY/i9oygplsGWPqo8IhormZhtawcDguT1s3AKzFjnOfPcuu
+DG641B4xAgMBAAGjgdAwgc0wHQYDVR0OBBYEFFZm+17fAu+4juGKr22bas32v4ts
+MIGaBgNVHSMEgZIwgY+AFLvJx2JLh7dqMj+lUXvBOo4/Blz3oWykajBoMQswCQYD
+VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFy
+azENMAsGA1UEChMEcGtnNTEMMAoGA1UEAxMDdGExMRIwEAYJKoZIhvcNAQkBFgN0
+YTGCCQDLzx3N86bNCTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4GB
+AKKjcrEUraD5x0x2u20e6w35dS7UVjCseCSaG554KJ8k2lYXn/zmGD3OKk46ff5x
+yd2jV+19yvRv+Oj+f7DbwxvI0hvhkxPfn1ynVh5gkS29UfdwgFBXxXjwf2eoVwgG
+WQ0EVG190k8n1MHccwNS5Gnm6cQ6bWTbIUeOfcg+nUg7
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/inter_certs/02.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,62 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 2 (0x2)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=i1_ta1/emailAddress=i1_ta1
+        Validity
+            Not Before: Aug  4 20:59:23 2010 GMT
+            Not After : Apr 30 20:59:23 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=i2_ta1/emailAddress=i2_ta1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:b9:6b:ec:dd:7f:06:e2:ac:a5:56:89:fa:1b:8b:
+                    07:da:76:d6:a9:62:c0:b2:cf:ff:c1:eb:95:b1:e7:
+                    74:42:ee:af:28:92:3e:86:3a:24:89:f2:60:cd:f3:
+                    29:dd:ad:18:3f:ff:d7:cc:88:5a:36:fd:2d:16:46:
+                    67:6a:08:86:10:2e:fc:cf:3e:cd:bd:c6:30:f2:8c:
+                    c8:63:d2:70:17:1e:c0:b4:27:5c:68:ff:83:1c:4c:
+                    a6:18:2f:43:4e:44:4c:de:44:52:bf:da:da:b4:1b:
+                    ee:85:d8:d7:0a:14:09:42:e9:f4:87:83:f3:85:a6:
+                    81:64:57:b2:12:de:a7:03:27
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                E3:6D:6B:62:16:42:41:2B:9C:3B:68:01:F3:EF:16:3C:31:83:05:41
+            X509v3 Authority Key Identifier: 
+                keyid:56:66:FB:5E:DF:02:EF:B8:8E:E1:8A:AF:6D:9B:6A:CD:F6:BF:8B:6C
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta1/emailAddress=ta1
+                serial:01
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        b6:ba:e6:a5:25:c6:2f:d8:b0:ff:68:f5:0f:4b:f3:1e:10:25:
+        68:72:8f:bc:f2:ce:17:ee:81:66:db:18:46:08:7f:07:d3:82:
+        63:99:c4:19:87:cc:d8:cd:cc:e5:fd:6c:c7:c7:39:32:be:f5:
+        94:9f:21:a5:39:df:91:d7:0a:57:6b:e5:41:87:eb:c4:ca:a9:
+        08:05:85:a2:03:89:13:a7:b2:88:ff:91:94:5d:13:6b:97:32:
+        e8:e3:2c:80:42:b2:c9:78:52:9d:23:c9:e8:11:4a:79:9b:d0:
+        9d:d2:10:3d:2e:21:e3:f6:a7:f6:e5:4c:55:a8:f9:0a:bc:13:
+        d7:d5
+-----BEGIN CERTIFICATE-----
+MIIDGzCCAoSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBuMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEPMA0GA1UEAxQGaTFfdGExMRUwEwYJKoZIhvcNAQkBFgZpMV90YTEw
+HhcNMTAwODA0MjA1OTIzWhcNMTMwNDMwMjA1OTIzWjBuMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEPMA0GA1UEAxQGaTJfdGExMRUwEwYJKoZIhvcNAQkBFgZpMl90YTEw
+gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALlr7N1/BuKspVaJ+huLB9p21qli
+wLLP/8HrlbHndELuryiSPoY6JInyYM3zKd2tGD//18yIWjb9LRZGZ2oIhhAu/M8+
+zb3GMPKMyGPScBcewLQnXGj/gxxMphgvQ05ETN5EUr/a2rQb7oXY1woUCULp9IeD
+84WmgWRXshLepwMnAgMBAAGjgcgwgcUwHQYDVR0OBBYEFONta2IWQkErnDtoAfPv
+FjwxgwVBMIGSBgNVHSMEgYowgYeAFFZm+17fAu+4juGKr22bas32v4tsoWykajBo
+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVu
+bG8gUGFyazENMAsGA1UEChMEcGtnNTEMMAoGA1UEAxMDdGExMRIwEAYJKoZIhvcN
+AQkBFgN0YTGCAQEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQC2
+uualJcYv2LD/aPUPS/MeECVoco+88s4X7oFm2xhGCH8H04JjmcQZh8zYzczl/WzH
+xzkyvvWUnyGlOd+R1wpXa+VBh+vEyqkIBYWiA4kTp7KI/5GUXRNrlzLo4yyAQrLJ
+eFKdI8noEUp5m9Cd0hA9LiHj9qf25UxVqPkKvBPX1Q==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/inter_certs/i1_ta1_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,62 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta1/emailAddress=ta1
+        Validity
+            Not Before: Aug  4 20:59:23 2010 GMT
+            Not After : Apr 30 20:59:23 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=i1_ta1/emailAddress=i1_ta1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:c6:a6:ce:f9:00:3f:47:3e:3c:72:b0:a7:d8:29:
+                    ec:13:8a:8b:95:d9:c1:93:c2:af:50:f9:21:56:36:
+                    40:5c:8b:08:99:bd:56:5d:91:56:46:5c:e8:ad:44:
+                    ca:8b:b5:29:03:58:a4:e4:19:b3:31:9e:b7:39:ee:
+                    5e:2b:45:a0:36:5c:0c:63:f7:e4:ce:ff:27:e2:bd:
+                    72:3d:fe:a5:36:b8:c6:87:04:8a:78:94:40:56:3f:
+                    8b:da:32:82:99:6c:19:63:ea:a3:c2:21:a2:b9:99:
+                    86:d6:b0:70:38:2e:4f:5b:37:00:ac:c5:8e:73:9f:
+                    3d:cb:ae:0c:6e:b8:d4:1e:31
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                56:66:FB:5E:DF:02:EF:B8:8E:E1:8A:AF:6D:9B:6A:CD:F6:BF:8B:6C
+            X509v3 Authority Key Identifier: 
+                keyid:BB:C9:C7:62:4B:87:B7:6A:32:3F:A5:51:7B:C1:3A:8E:3F:06:5C:F7
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta1/emailAddress=ta1
+                serial:CB:CF:1D:CD:F3:A6:CD:09
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        a2:a3:72:b1:14:ad:a0:f9:c7:4c:76:bb:6d:1e:eb:0d:f9:75:
+        2e:d4:56:30:ac:78:24:9a:1b:9e:78:28:9f:24:da:56:17:9f:
+        fc:e6:18:3d:ce:2a:4e:3a:7d:fe:71:c9:dd:a3:57:ed:7d:ca:
+        f4:6f:f8:e8:fe:7f:b0:db:c3:1b:c8:d2:1b:e1:93:13:df:9f:
+        5c:a7:56:1e:60:91:2d:bd:51:f7:70:80:50:57:c5:78:f0:7f:
+        67:a8:57:08:06:59:0d:04:54:6d:7d:d2:4f:27:d4:c1:dc:73:
+        03:52:e4:69:e6:e9:c4:3a:6d:64:db:21:47:8e:7d:c8:3e:9d:
+        48:3b
+-----BEGIN CERTIFICATE-----
+MIIDHTCCAoagAwIBAgIBATANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEMMAoGA1UEAxMDdGExMRIwEAYJKoZIhvcNAQkBFgN0YTEwHhcNMTAw
+ODA0MjA1OTIzWhcNMTMwNDMwMjA1OTIzWjBuMQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UEChMEcGtn
+NTEPMA0GA1UEAxQGaTFfdGExMRUwEwYJKoZIhvcNAQkBFgZpMV90YTEwgZ8wDQYJ
+KoZIhvcNAQEBBQADgY0AMIGJAoGBAMamzvkAP0c+PHKwp9gp7BOKi5XZwZPCr1D5
+IVY2QFyLCJm9Vl2RVkZc6K1Eyou1KQNYpOQZszGetznuXitFoDZcDGP35M7/J+K9
+cj3+pTa4xocEiniUQFY/i9oygplsGWPqo8IhormZhtawcDguT1s3AKzFjnOfPcuu
+DG641B4xAgMBAAGjgdAwgc0wHQYDVR0OBBYEFFZm+17fAu+4juGKr22bas32v4ts
+MIGaBgNVHSMEgZIwgY+AFLvJx2JLh7dqMj+lUXvBOo4/Blz3oWykajBoMQswCQYD
+VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFy
+azENMAsGA1UEChMEcGtnNTEMMAoGA1UEAxMDdGExMRIwEAYJKoZIhvcNAQkBFgN0
+YTGCCQDLzx3N86bNCTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4GB
+AKKjcrEUraD5x0x2u20e6w35dS7UVjCseCSaG554KJ8k2lYXn/zmGD3OKk46ff5x
+yd2jV+19yvRv+Oj+f7DbwxvI0hvhkxPfn1ynVh5gkS29UfdwgFBXxXjwf2eoVwgG
+WQ0EVG190k8n1MHccwNS5Gnm6cQ6bWTbIUeOfcg+nUg7
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/inter_certs/i2_ta1_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,62 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 2 (0x2)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=i1_ta1/emailAddress=i1_ta1
+        Validity
+            Not Before: Aug  4 20:59:23 2010 GMT
+            Not After : Apr 30 20:59:23 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=i2_ta1/emailAddress=i2_ta1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:b9:6b:ec:dd:7f:06:e2:ac:a5:56:89:fa:1b:8b:
+                    07:da:76:d6:a9:62:c0:b2:cf:ff:c1:eb:95:b1:e7:
+                    74:42:ee:af:28:92:3e:86:3a:24:89:f2:60:cd:f3:
+                    29:dd:ad:18:3f:ff:d7:cc:88:5a:36:fd:2d:16:46:
+                    67:6a:08:86:10:2e:fc:cf:3e:cd:bd:c6:30:f2:8c:
+                    c8:63:d2:70:17:1e:c0:b4:27:5c:68:ff:83:1c:4c:
+                    a6:18:2f:43:4e:44:4c:de:44:52:bf:da:da:b4:1b:
+                    ee:85:d8:d7:0a:14:09:42:e9:f4:87:83:f3:85:a6:
+                    81:64:57:b2:12:de:a7:03:27
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                E3:6D:6B:62:16:42:41:2B:9C:3B:68:01:F3:EF:16:3C:31:83:05:41
+            X509v3 Authority Key Identifier: 
+                keyid:56:66:FB:5E:DF:02:EF:B8:8E:E1:8A:AF:6D:9B:6A:CD:F6:BF:8B:6C
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta1/emailAddress=ta1
+                serial:01
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        b6:ba:e6:a5:25:c6:2f:d8:b0:ff:68:f5:0f:4b:f3:1e:10:25:
+        68:72:8f:bc:f2:ce:17:ee:81:66:db:18:46:08:7f:07:d3:82:
+        63:99:c4:19:87:cc:d8:cd:cc:e5:fd:6c:c7:c7:39:32:be:f5:
+        94:9f:21:a5:39:df:91:d7:0a:57:6b:e5:41:87:eb:c4:ca:a9:
+        08:05:85:a2:03:89:13:a7:b2:88:ff:91:94:5d:13:6b:97:32:
+        e8:e3:2c:80:42:b2:c9:78:52:9d:23:c9:e8:11:4a:79:9b:d0:
+        9d:d2:10:3d:2e:21:e3:f6:a7:f6:e5:4c:55:a8:f9:0a:bc:13:
+        d7:d5
+-----BEGIN CERTIFICATE-----
+MIIDGzCCAoSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBuMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEPMA0GA1UEAxQGaTFfdGExMRUwEwYJKoZIhvcNAQkBFgZpMV90YTEw
+HhcNMTAwODA0MjA1OTIzWhcNMTMwNDMwMjA1OTIzWjBuMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEPMA0GA1UEAxQGaTJfdGExMRUwEwYJKoZIhvcNAQkBFgZpMl90YTEw
+gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALlr7N1/BuKspVaJ+huLB9p21qli
+wLLP/8HrlbHndELuryiSPoY6JInyYM3zKd2tGD//18yIWjb9LRZGZ2oIhhAu/M8+
+zb3GMPKMyGPScBcewLQnXGj/gxxMphgvQ05ETN5EUr/a2rQb7oXY1woUCULp9IeD
+84WmgWRXshLepwMnAgMBAAGjgcgwgcUwHQYDVR0OBBYEFONta2IWQkErnDtoAfPv
+FjwxgwVBMIGSBgNVHSMEgYowgYeAFFZm+17fAu+4juGKr22bas32v4tsoWykajBo
+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVu
+bG8gUGFyazENMAsGA1UEChMEcGtnNTEMMAoGA1UEAxMDdGExMRIwEAYJKoZIhvcN
+AQkBFgN0YTGCAQEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQC2
+uualJcYv2LD/aPUPS/MeECVoco+88s4X7oFm2xhGCH8H04JjmcQZh8zYzczl/WzH
+xzkyvvWUnyGlOd+R1wpXa+VBh+vEyqkIBYWiA4kTp7KI/5GUXRNrlzLo4yyAQrLJ
+eFKdI8noEUp5m9Cd0hA9LiHj9qf25UxVqPkKvBPX1Q==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/ch1_pubCA1_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXwIBAAKBgQDfSUyM3SXhTYEIAWXkN9vUh77xyvPC5YKw0skJpD1BKslAxVWq
+C49BQoI8LkcjI4jlVX4/ca7J+di/ueBLdG2CryDwjANL+9lAmb+UkPkANr6nlw2v
+b+PmQwwipyuS3SSPeC7dWm0Fd7YW0YoHT6GvccN6tNNULvWa07FAf+A1cQIDAQAB
+AoGBAMgUwJnBWT5I2wS3a/xS6ZPKiBnWyROt4axdVXRkTddlZa26poaXkSjjVhxj
+Q6+DGhqWv2hOkFfAoK88+nXiwHUbvQrz+6z0qne+Cn0qjYUI/1TxnjGYP6bsiSJT
+3a+7MiNxi/6D87fZ+MDRFTwGzgpglJOzIHkBv9JT/l3po6ChAkEA8sno0QQpqbnh
+TVuD06ULkFxZdJQdINJENNBIP1Ru7oEQz4Ad9M+IRWK0rgUsNT+iPUYCmf6y+qwC
+ymMf0/r2bQJBAOtvt8TfM/coHXaPoFG7AnUs6eT6idCuQ4DNgjSTaI9dKz362cvx
+U5oo7gSy8gzDteeJcDmAWQpmgQL/q6/s6JUCQQCrOhLkNldbyChJcl1Kin/ZVAgS
+29KfLyvDQ5FweI+zzXqZnPWDjknBBZf/ks5Wz4YQSKvVB3gaqe1d5wKvcbMRAkEA
+g4H4tUgz36eRpYsecuixu7/luhhT6LOeUxD33ORF8GaLY+h9xZQ8LY0VPpyx5X1g
+Wz+C5yuREOUmxQUI4pDDbQJBANa1DNHklL9sFrVLX/d0vPuH9mBYc8Tzm+xINqzN
+I1jWCd8HWh/5WHsShRWSkYV/da2j6ME99g4lpvnMKC2dIg4=
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/ch2.2_pubCA1_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXgIBAAKBgQC4T9hGOM9N+GhkEEoviyzWX4kyRJCJJXb/VGVZ0nWG0JTPLfCU
+GCMy/c70a6DHDvmqGPkL/ueFqv+K4QRT+aQ0dUUHb/GABsrDDzu0RZf+CfUXGGwF
+6TRoud5ho6zhIg9pcm+pqGTLiaM9MgIlZF9JHg9QRxTyCr+McldE+S6eaQIDAQAB
+AoGAbu63uEQ3GbG6eweG7yiwOvLTa6ry52jiP3l3auGOFS9zcWMwGqKQhP9YUap5
+4XV09VkEhKDOjphGKDuY1EY7+sOvSpO1jwUUqS1kHPVhIQHzf5f95v0kSY5lk4s8
+ZD1Tv1lthd2Mc426Zw1n1OnhYU6Ip8Cycp2vesUlmn15eNUCQQDzeLBo+J/tlu5n
+CkjoTGC+XuL21LVysa0ENZRcxZ1E5h6T+NKLo7FBiio5X7dqk23niKgGN3DtT89j
+HR3uQ00LAkEAwcvU/8RwAtpReSoNCOyVqZXX2JTPLKOeysBNft+9c0hgGnIyr7t+
+nduVEm7lgujg6xX+nuRMIsb0kJdEgcji2wJBAOnHaRxiHq4zzpaB+Z+UNxCUa7o2
+ZEPM9ySjjeHGnkwZ6iKLOR97/ifAUurkTWm4Rj+bqDrP4U7841V4D9VIKiECQQCd
+vavCA8Koj8uBNBkoCmpHfxAR2g5H52Z44c4yVyt9iouu+wUGxTZqhzDvsBRgWe25
+bE20R18xb3/hsT6x5THBAkEAvq8eB9U75Kecf4iJt6/1iyhbRa/yMqFP7CeXFq/W
+HyhjL6AL4d+nKhNPfwrz/sOLR7MZTm8ieytFdLNZ2luImw==
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/ch2_pubCA1_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCxF5QDmRIJHvI/duNjEXU8QUbKPyydL+MvOZBjodAx4bfrlPPF
+fCtK2pvSKClock7IUwyEm2uhfWNJO2XmvhGlukFedA0WrpUmAnnKON8T6feXUs3T
+hUnsz3XNVBPwFQ1l7urleztjPl+pS1bTEB2bR+0vRlRTGbAuY80S9EBKawIDAQAB
+AoGABrTv5Br99d54KjMkdXIJ0JhgR/SQiftwTS+O6lcMfXcg8gkYGliTgyg4UoM2
+3j/GAAw1IyiHsPwAsJtRRqXYITB4Swurdi17HdkamgigtZT9COp9U0SfcbCWgLWx
+1noCIaSh/8keBgTxnrnYf/y+0enrjxodYG6Cxyk5eelud0ECQQDm8lgs53o3Oh1g
+Udp71PGLscO22YjjVMXTtP9aaQ2xzkguGGSVoHOX+Izfqiy8HlJkMIeGi3r/DnXx
+SSapfCqRAkEAxE2haINHysSDw1JQXAJGFjcwsWIPbyNT80aMxM1Q+PJp//uC2Ddj
+sFd3p17lvEtWA/jI/qb0/t1e61UvcopLOwJAQqehYVxxvqzMO7eEKodcK6hjx0tj
+odEew6qSpKJ7bF0QIhWyOik0E6GN7yPrg2Pw/a+v/doV5rVivwAQ44vNsQJBAIEC
+wASO2tzg//ObImMFv4gUJ3U8jAYvgpnMkPE6OnAR6SYp5pkw9dxL78BYtsVkAZjE
+pVvu3+6sEBi7uF4fk0cCQC3DKv42iBPOrDsj4XEFTV3MKTSp9ybigshGerkrpC57
+OOrl3JcfQ9EmtVPNJPeGRXHvzuFyD/szmIx4bToh9rg=
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/cs1_p1_ta3_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDdjorhXyBldA2R89a9dmdYma7Xmbx4H9C72ZeVQTtCS8zMNtgn
+ACrDJ5JMLV9igQyybRuTyqQcGAmMJiK/gKT+SDeHZGMylUGP9jWYk/Bh8kvrsDQ2
+Z4WhnSF13qufMq46k2RIf+9a+kTiG5+dEDzDnJDd4f4zMUoiy4KrhCoerwIDAQAB
+AoGBAIMROlONJOsfto9rQtQeYZDmiap+BiLCH4ehd60SQ+46TVNZ9pFL5gBBPqjW
+BqGNWmeLaE8MB/2esrc4MEI95lx1oSEVgSQEgFxqCnwQ+8FfZiQr6i/Q7636kI5G
+LcjQ0B5GDdNyI6kbxdtTc0JQak1NWn/S7fjacsEikOj44rLRAkEA8zc2ql427tuy
+5JPD9CmLqGZbRpeQ/nSN3uKp0QPcQCTHc1rRddXTSJI+Vcj8c0lBGN0KJBLPCwVg
+Kd8gAq4C0wJBAOkz4WHGYEhhmuq7+lgfJNFQrngffmsreFURiMbUp9g2BQm+k5q9
+GwnGqoaTzl/UUaQZKbDcKoCMSYXaWm7uszUCQBQbWm+XPl9c1ltDRA3paVxQqfca
+DKicpiXpAzT+ZrT+1WZZ+bsOJFt5i6G37fbx9WnCzFXTID6/AQY1JgZSsHUCQAuu
+mKTAPkSB9zO5FPJjJQIDS6oi0b9mnxGL3lEvh/Txx9DUJirDPF6CADrbnqP4S9qv
+lAITFWH5JRm6dXtHI90CQQDVGdX31C3nFHZafk5O7GUwKQNOGaifcfIQ04ZIwMBO
+HsryI2bRJByldLW2YKtn2RzkHWE6Lp04iG3289qhIeIG
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/cs1_p2_ta3_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXwIBAAKBgQDQHvZY4ivQFf7aXF0RhLl8ZUJR4pKeQ8Bxwgu6SwdgFAgnFvUs
+FkRtiQ7Pb0ct7xLfDZ2clM9O8AAcBzts5RBhl/PAIBJsAIedleQ7FN59l3dZmiya
+9qkMID8L2qkTMtOpp184n7V/GQ/x/8Cmf+l2JGZyKc5taqLDPjQKNLjEmwIDAQAB
+AoGBAM4rzgkxTQvfrk9tLnl7TTDxMujhljOYlJ1dCLctOoowbf8jXA+no3QLUZOm
+/hGAA+bZmyiRtmjRkpoxg+oVZcovEsszBHpeqasq1akYtQ+M004On0qn1e2fmeZu
+ecXrhkTKdNqeRR69ENfQmAcs5snYKkmwCEIDDbGnp1wKU4oJAkEA6vBeKkJi4dNQ
+Iw//89wIXMIN9x7u7R13iUQBpJwdPYi0loOPRgXXQBwub/dGcdMorGGjcL7ukLBC
+G7aqUyD77wJBAOLHJXMbYSVYKf1rQtgdwVYP8M6hrCawyTh6Obp0zjjYhr31gy0n
+SEnywUPZs2CtGdBgP9SUcik/sD7zgxIrhhUCQQDI5qb/aCl6huLeOM5cz+luuJqM
+ma0iorIXdUoaY00103LpyrJ35IK+1dp38HIS38jGL/A9d2g13iOJ41gfIfONAkEA
+xe0IC3m3BO/43fxyv8rgheutwbqrVK1xQgCzR8BQiJ66oyqXjZ4+YoQkF8L24wbR
+g+Otci0JomS6v4arO/2OrQJBAMO3XU/aXerYDt+JUcvAeFQCCEI+D9S1jkeXWkuT
+jizIChu1nWAPeY1tCPhwi8CETo5y9oWKzKg4+5RTpEbh0Mw=
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/cs1_p3_ta3_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQC8gn3fSR8fTH7uJVGW5Emo++6wUbUQ6czwNgdZYTeolXBfUz5U
+7wJG2RKEII9lxFOZ5szZ3tDl0lErPT0IiKM1036/yXDTZYEWMBgOfyJmUgVl0ORl
+EQaN36GX33TE877Sb+4SjRrdFbjkfs0SztRHTdXp18g74ApDekrMEWo4MQIDAQAB
+AoGALfEPhC9p6lLWTGvD6qZQXWKo1UfUfP6993zzZZEP44IoFNNQyZpGT8XvgUv+
+JqsmRMe+/QoUly4eog8WpNHIFJb55TBJLAsW48QM4EExbVuCcbRauDOPfN7uvJd4
+WjPs3vBxJ0mq4WLkEiZVaG1lVgBAEkHBumnrxhdXjaj3LcECQQDmCeXLBbFojoaT
+zq8mc9Ii3i2FEjuLB++1yQ0Gzvcza2UKUXd0MIFkcA2Mb5mcMXxFderWrlSkD2rf
+AL8ezwwFAkEA0cjFkjkvIHuWS48fIw6kY7p3VnTvJQ/banotRW5R4c6rTuofL/YK
+sL+PCdZYQ2ew+k0bYG+uwc+iYcEXQuzfPQJBANA+pYfk33WHkMy9jlGBB/oIp6yP
+lNeHl7k5CFHhimdCEXYFyd2lC32g8qLvZF/BbH51AOLXbkgWrOi0BFAfnwECQAr9
+MmRDfJV+A9R3bdEfTjsvJFsyCujtGLhOKBrv+XgTpGOg3ftcLxktH6gLQ1pcjye9
+bEaz8vqSDtaCD97gm50CQQCR6h+MwbT/tjwknYe9TaN0KHxU4hfL+9Qsvw1tseXq
+9U50DKB8bxFXJE+h3v4cLWy8ofwSxh0D4J0D+NCGyQaZ
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/cs1_p4_ta3_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQC/QsnnZbTBiIXMmkkp22QFFGC0xKtEfYZRncC6wkHCgPzn6iYU
+8nOvkJiYyO3ridQfp5p6T40KSrVU3jwaXMwYHTnd9SuXphyzdUzaH4a7Hw9nsaDp
+HPkh4C6Y3lxkZn85QngUpc4sspv88lShoq/Mc4CjbdDTKfmum+HWnDoZiQIDAQAB
+AoGAbQe18aOZF3qsS6bobmQS8JJdTq+Ossyb9Yrog46ZzjeZ9NsWOnq8WCkl1HM2
+rj80HZd+CJuw210bYfYObTjZXylrsE95Ss1+qljx8vbWU5IiKimBGWhrKbM8/ulU
+adedJHyctX4h1CXGfmrtz7j6nTD48E79PsAlJqgYAwxeMwECQQDjEc1SD4pkEdZv
+aRjoGKiDmyR0fZEk2Ypfhc58zAcdZMA4oT7NYAmWBDIedjn+fF3mFIqdTRyfOsVC
+wMWwUgd1AkEA16EJUx6AxI3TGobPvOcmLJKoPkRS+GvGN+zACDAVEAt6ucv3if2G
+f9mnn+1aHBJjnnvEHwfXAxlsme7i2CnbRQJATuHNURei/PaRZuy8wUxnpiiMNoe0
+l3eXMW37eLEsO5LXkBS8C360ddAJVTm/FeBAgoBaUyEJs2soQfNT+dfVTQJAVp4T
+ttXr+AjYojFBRaq8xO7ssoaTpcL1TwXFZgSakWVrGTN77mxvGPB/y1h2+AvTBJjH
+AYgOsOoHnBY//YFi2QJANJzFg7k4lWU+UkqJpnWp/O+uqy7RgPenrr2kqrbSW88B
+dLdWm/xPvq+vhXa/pNmEX/Gh3HjIZZzQyeTlXzTVQA==
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/cs1_pubCA1_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQCXp7aaQGMSLzxLP3XSU1vJyW58/PaONX96WrL6AOvd8PKHKsmb
+TX4tPPEOTv+0sZGIL8OrrmU5HtroflC1lEimXLC7Qqpw5lCcQSxnOGzgXZp9tJU2
+VOroSCQxHDA5JCwqH97CyL/ogjVKm1KOFeg03wx4vuXGhcZ5iHXABOS4dwIDAQAB
+AoGAT8DaTbpon2qJ2cSw0IAX+EFfQonBm73UoWLLVqBfaiNJV/4PcgXJwj6XQoAX
+B06Oi0EbNNEM2II6eyPai/NEVLGQozV9HgMmbPT1uBjgxBuCibdKOzvmcfShLcdG
+sjYBs8wV1AfYkKsY9M+sctgUiRDo4rkCHEssF3F/iA9jvvkCQQDGlisuEPCYPhKG
+wnucMn7LZl8r3g6UWE4URTLFcrzYAfJxOB+WPfN4kPE0o486k9D4L+W/gfdOrTym
+WaTxHQD9AkEAw4ALHxe7vY2rE4U1ssmRQ1wftXu8eJ8oDR59r33ih2UhCU9w/rs1
+AEzyWac6x9Bd8uUiQF6m++kq9JzZHmdDgwJAG4adHZmDf9a6wqsabyAgqxjZgD8b
+TjyfNfgRfYTV4CsE6+SXnD+iC8grZtx08e2jPYOGGPFu0hz5FyW90x3uEQJAfyiS
+k0e5mkJCKvEzCzYmIN0T1tRDs2U6BMZ3U6UaqZwyj763LUiQ4cAqxfuKtRqncOxu
+idXG4QU5Jl+6rRbXhwJAN64+IlP5rCS8ZdTxwlMz5nik0NEHagMX72jgEbwtiAPt
+QTY3X5Ag/F3+d3Br2QN+FaemC+FuqBYXqpqvLQhjnw==
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/cs1_ta2_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXwIBAAKBgQC3D6bt8ufSwd4JqVt9ukEUdqom/PalC9VCpeHwWyoV8GC33wYT
+AgYD498xuU9gHO0EVSgRvYt7nZhqLBjoRYWli85Mhz6RRt12kcrRDTYCGyMYTEQB
+pI4wAf4JqEYo4y7lX0Vm+aWBKvOXDcjtIs9ZgkvMxusUNUhI36hYpDyAYwIDAQAB
+AoGBAKdoY/MFCWXerwxM2YNv+iYZot9GxNQIrz1k7+tbo3AuxHRCO47UceXK1Qjm
++6TcrxAgRCV9Hnqsk3681wZK1b0T0TUaEEiUuUVVtKAHBD/yHw64AI/eKmjMQhSm
+aw9WT35E3HeWjX4VIwXZjUGO5wFg1SK/f61FPrDwWCtnZ7hpAkEA2784BgNbNZXV
+fWBRXxiSKXngGacJdhMJAz/fXGeBho7t0FiKYMxsDKp1912mYteB3uZCmo2VuACQ
+IS4PN3sEfQJBANVDC/cNjip0ztXh4dxSfAJbqNKJ774MELMZuU5jCQBBevnf5V7Z
+njP+Hl09L+Wisb8+hIcslB7JoMkQ7KNjDl8CQQCMc4u7TCnf9gSePhHEVlAVcnBp
+9Pl3HnOEQC7jQMTo3DHkGLNZa08kSU9c696NDnFTppircBNhp/p3Opk/PMGBAkEA
+pvkHtTb3yGYMS4m/vTEXxwDc/XriKnpn2NKbM7R2p6ydDGcwv0LDixG71GTDy5fG
+c2YPfYZ5smFLciG+JW65IQJBANDtzr9Z8Wk8bV72jftgiND6i7oGO9jejZneKXVu
+y8/iwthkJHKjBh33WrLHUJG+NHms7zoSfstyZK3PmqGxyq4=
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/cs1_ta4_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCsAG33eoa7z8gGmnF/aTpBLV3VZjGhL517ct8hRL4DY80+K/zj
+Ro3fVMtxJybPY/ibn3NeRZ+5Xnha7ebAIt2b3YpaTryv3XClHBJgHHpxfGWPQeBa
++8cCmuHv4dWrMfsIyPnJ2PF+dVl5JyYNIUOJOmetE3Qj+icPtxpoZWe5AwIDAQAB
+AoGAOvI6vaGkIyFmb7zmQMATUtr1WXkYcSEcW35WsdQZOpgtcq0okctQO8WXo0PD
+rTeZr9vJcflyb9jMbn0xo49PWtdN+TP+NYL2buqclJL+nd2AVzKpH6ufRM5OeezZ
+RkCZKmq913umwjFV4SgeJ7QJWmDzZfaE5RsQDOlz4rQio4ECQQDe9KUbcJj9sO7i
+4wBSrVBwkU5HclaitqL0ohMuoJAL/qiI7uC0St04JZPctndoEzLDlLmfJhWRFpeb
+hsLLHY/TAkEAxX5+4LDgYMZ7ztMDg7xADCswqunRmGdQIU+WuUfDdAvXyzuIPigu
+hzKujrH4Fhf2yRj+MTTNcSqjrTwQA7qkEQJAJmbM6WUDdO68tqeSrqrbaAgfC39O
+HMiIWMpxs15EcUxziuJaIbOjVsBiL2neNzbXT4iWUCsnG85gXpFfi8yTsQJBAIFB
+BLDxkihEPwtht08kiZZtPfDeDrr8AsmKWU7x1M3CYn00fTqQ+cKqPOxPNdrf3DhJ
+DzQNJtgF3BGo2aJXKMECQHJxFZkCXz4x3/fNwWG6f9ZbcUczXsOt/+/WQWxKNi4s
+VBLQ/7c5Jaw16kt4hH4f4RSbAnuCuxDiEOhs42Kcl4k=
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/cs1_ta5_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCnWFpkSR5l6GPXbNK0ZXNHFhAbqUV+Iv6HezBYLoF/0Gm+SQbF
+RCuNMgyRj0jU2eRRJVJWvECSqAXnZYLEeUmsQvzUQXGcy3rwXzXXCBEDO9NLwcs3
+es1YZOwbgyU+OvOZI+ATxYWaGtR5U9IyTMlQOxlmbyL8yFpr75fZdwE6owIDAQAB
+AoGBAKMUDPKR9tekwjdbS3KVMuPhck0ihiBIBfcNa61jlLtz5LiU/c4bgr2UOn9X
+PMiAlmklj7oKtnq01xwK5oaFE+8A8eUslLDV97PVHBmuzs/4ipSMYlB+ZiNNuS2k
+nhklGLFeeFbtydhoE+VXAu8xVO6o0bX8VHxdA/1kcOX5d+nBAkEA3cTUSjav2ZFB
+glF8Q3XssJexpkA22LvWyXdL9LgC+Y+RoJ3q1nKL/14TbJ5tC6PoauRrJyBJzmPn
+w/zqBKL6kwJBAMEs+e9qExorxCb1mHIMBoE/7TrSLhPO2RAbSjS6WItCD3PkNKE+
+j7kUTIrbFHu5aVRYnOphcE+Soi72jKuj+bECQFW4YyZchRRf5SZuQM4Cov6PZAeT
+AqA72wX8qsto5R15tRyUbdV+aUbIIlH12siJDqliqVhyTpUMYOWMuRgZtykCQDm4
+NJ3itf514VA6xegdy7vG3B1dO8NTZOw5Gz0SCO7jODbKkycyyELm29AJkd8+EUjQ
+iWJG5wX/rFIX/QQ0JKECQAvgKwZPF9LRWadgMPCxWJJmWCsTW8e17pGwI3i31QjH
+thT7ljDNnx3+Lo1vVjIjX9yZXuhloJsSZkXfY9VQ2us=
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/cs2_p1_ta3_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDEM9UYz/KC1ebAaFo6KlAw/NbfYczBNRbNIr9yQioIqpP4Uhjp
+5EXz0QqiOMZEc+EnhJiIL/iyseJGOb0fz3q8UX8x5PW4VvNUTKVXrnDM9qRGiyx+
+02+bwrvmpPIqFeFIVCxj/bPrnm06vcw9zj0WUsFrKoKMymBQbdaqiOfFKQIDAQAB
+AoGAWwpaFTtYolEy05EYXOkJcNHBusGcywIhZGp9Pz1oV8EfDBi8Krubofkb4A5M
+IbNLhJTIWlk4I2LbRg7ArSQPJMagfAbpuKcpJdsj1e+YPEvkTQBYWPaNr9G2fnHq
+/kWlKwZ13XpMG23PGmeMliqqCml+Z4DGHJ6TFhTxIC558wECQQDueVykLoTbvl77
+AQwmKirXPuxHQvDqzX1l6NmgQJvtFo1y1DkSlD4CbdpK+hNihUdnVj6yPPmVOwT8
+AX+6o+9ZAkEA0p8sypq4+JLY5Xgsl21oqIqjWO4J5wdAsoloCIl7kP+GGco4FVHW
+K1tAiajrI2/W+K3SP+Os7Ze+gWnGLUoaUQJBAMpRunAsa1lHFKvdQqJqafg9kRYQ
+S/bZKcc5GtFjnyYxWQYP2O/TRxymeGnd6m5OZrrcJ8ruAk1CSkNHPkdpZ9kCQQCD
+Dg5l5w5Phbg2WKeOdcKYlON9M2iv+4BTV1KHdVyQ5Z5Ar+Zjxa84/SfUQGpHe5DM
+3gOkQ3vXvwMILZPlnGVxAkB5hqYYqQOkh2uStr7cFC3GSgWWRLGRPy0KyvMBpqpL
+xSFAStuunpykRkXWcqAjSdJjCiDEcmPZUHkvCQk3RH+4
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/cs2_pubCA1_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQC81B56djYkEC+Es+0kjwuFihc5LxUmCoDiYKrAAK/VupzvsDoJ
+MeeXN4LqMqDFdcMOD2p372Z3L2qiYFu3hjnfEpROYXne3dL80aC6/mokCTtPHjUZ
+4hUli3wDGWY9EEWRnIOaccmy69+pZMctWpMj013sZANk9DS57kAd3wzFPQIDAQAB
+AoGAFzSiQj6AzNHIZTCPdiy2J8UesYJdwP0NdcSXd10ePs/eNX6cw0CEy4qg5hMu
+utWMERBH71FWcFM9cZMR8m3mcpNlFLVwUyC9MzWam9XCZ0Cyms/z9RjEhMpTRUx1
+zNLltnIcApf10h45atqMlXE19bE6+RDcpiXHzJgNdeIkpakCQQDvFfWs1aJY5I2J
+xN6KT7WgKUjSujnCqV6dZv0yLbDBifz9q4vIHxqVOfQG8Gxi6jdyBd9EM2QzLoXd
+zJrpwXNzAkEAyi/11hxNxtgPMxOxuOEfKoVr3QhqHLMeH1j+B2qZ47nSSjd0cNIi
+OOkvvdlMAOWKkgSjB5nfPQ2Ai3WMQIuYjwJBAJS/btgXGiiAGecrCuG2ceOxi9M/
+dYw839bCKqk7cAsZlMMmJZNedqV9JuviTSzFV7WjHaNK7f5B5Zt3HrJsXy0CQCyv
+/wDszo/1bx6V6sD3GOFYDegTlQh02mKJU9Qlzo+ToZP/v7+z4hZ8C65FWdQU59Sw
+K6xhaQLgehnYyD/32qcCQQCzqGsYRAalVuKVR8HBq3k52WLWK/6eSj/pjW1Rei7n
+C2txZgvI87OGV0KjSOq1XRROgOTH40CYlB7RsKzAU7J9
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/cs2_ta4_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQDTEfJWwDbvrX8YU6cpd59qgkPNpmUMXso52fqDsg0k5RCuhcXc
+AqqmOE8x87arRzeb+JmAbNM1NoFy8ZMPa93K112hajB0bgecR8M1afw45rU9vGXm
+rWfqIpAG0+uqZC8+s0zhpGUUjrKWhfw8HQGlShYasoTpqAPRCb57PDsO7QIDAQAB
+AoGAQh3ADL6fNsrhIgyqM0oebK2rcZLq2kojDKYkW/Z9OY5rgE+1H+rR68l9vUb7
+dIGVgM0JwHnWWzfcqtXTXCRMz/gLWeWr7K0Jt4X1iDXEKJ97lCYyrQcJ5Eu28S6+
+M5A+lEBicNK5/q7rcu/mYiFnVU07pnVDsoeOjS5N8AeQXX0CQQD/SodcXmPmSWQv
+804oVT3Znr50Bo7PEssvJFcncHfEyD7tVpORXOerodD75C2MJX916ptOK0vrr6wA
+4Q+GPFFbAkEA06f72djec1ZCxYIjJZ1fsJgarRvNUOjNBtvRuKKGWrChFnktQDN9
+2CcIXNklAJlscLVfIftehW8bwjUeht2LVwJAa5cZXRBawd8EXkEIG29xVZnVYkix
+PwwInaGPKYv4rfJGsvfd0VF6QZc84CvWFk5nXWa2dUdCA95Rez1esZASKQJBAKTi
+tbnVUB7L8YKKSjUwb25UYFvBT+abJbYVI0FSI5adCTFHv2/HbV8psUMbys63txnq
+wazodY8/qoFV/m0UREsCQC2i+6Y3b+RDvWFmdwuuu2+LFNePB3c2X+YC82awEOa7
+EZXiK6Q+a9dTAGPeakDJHKpZdWg042clIWhkvEn8lg4=
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/cs3_p1_ta3_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXgIBAAKBgQDOnqqaRGLknfLN0e85zMu46RoGz37k4ZlS4FoXqXiz5yXAl/hy
+1HVQxdmEhJDMU15GwGbYCnYMz/f/+P3p9GCISXSXPTTwkNqXXUAeeMu/hBvCfnDL
+tnkmfWKhY2ALn7NaXxOoHF71OQwU1GdYFgk7z1xKSuYXgJBptW2NyCeInQIDAQAB
+AoGAFhGsdz3GslSMkp9RxgKx39ZGCWQwUZInJksAVHathcmyppeU2e8HeNEpIpZm
+QOzGrRfv5DN52HR+MMEPneWUSckQVPr7PFwhKGQPDwRK0M354nFB+7bfUru0n0a8
+R9BeiY1uCHahaaRSWydbaT/+UEvH+Oz45ypx7L/Krot2hQECQQD2IMEPFNUNd9Wf
+udsLswDJLmNjguQ1LR2x2FJvEl//mXPC+60FDzUAVitTqsOxnrTWlGFhj7BlBWp6
+lhZDhcLFAkEA1ug96/8SLJU00pwYAMc5SeV07uG6IA1dh6/w6oS6FXuMpS21SduX
+DUOJLylk3wT+jpFRw4dnRxihi1HSk14r+QJBAJO/U8Um30IndoBchCaAvO8Hvrfk
+wfM98v5oeguc/y2jQz9/7vwDhfB+yaF+99xvBeVtywtSwzPRTXrrD9BWwnUCQQCV
+q9tsYBH9QNEwGQxShm2svITK1iS1q/lGxc9I1bVvvsM+Su4miSvTTgTd9rtM44KS
+Mj06qzPPfSUNDahVgFGpAkEApfekCGNhaW+SMIciQrOEsaP/Pgy6UVboPkFABWX4
+UIinIlogtzlFzo0ijrqt2yjluq62Ytr8rOTRFfoJNJEz/w==
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/cs3_pubCA1_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXwIBAAKBgQCuHue9VP50iOA0DTKyG+o+Y/17GxPMhCnh+H3EnGWqOiv9yXwD
+VwOyEnW5yV4CpI5tx1TBzeEwKF+oZMnCAuI7r16z7CwcXEhQB4fkGYDvtHhv8m/d
+ZGGXzqcpCgc8by5E/jhwW8ZEu8/1P7MgOzuB+nclqx9P9tso/X+6L1cYRwIDAQAB
+AoGBAIySqukyK1SOBORBG4KsAstoEodG7w8YTHABHBiVY4aw/D8iYZqYr4UeXikm
+J13e2JZMbWMiAgHNNp1O8YxOo7HS6KHmbG/ywj8eyN51zbBKjNO/oYbGh+ItQytP
+vqni54Solj2KsQax9Ke7QF82HKSN7hvTm65486/1wjjXw1oBAkEA2gsVa+YfQeHw
+63OYOL8rhD4dDZxi7829NqnWf+izpg9hOjpTv2yvoX76PaToKX+ISJuS43w/8uTT
+x+Ei5tF0gQJBAMxucvNH2EbufuwLLMELlxzW+vBpqRP2CoH6W8lAOxLBH6A2jlP+
+Yaf39wz4cadUK0Qq+QbAYgX74gdw3XghiMcCQQCOadDbAZoG2QEXeA/DeLF+lWc6
+fZttT263ZmSwdJfp7X+unWwXynBIRfxCCRSODjtAWUSuinfmOKlOkvDN256BAkEA
+t6DueECssOpB790J0k2K60jgF1uRmHCFd8Ne9yNO7MW0lsDqj+AL8Ej4DRqNXHRq
+eMzw63ObmSxsF6r2BJZ6uQJBAJttK1t1MoB/DbrN5KekckC/fNuQFSXLm5xmJMMs
+tTF1vwqOVBVKHu/LWylmuo8J5KSElE3wrZaoeDXNbOH7ul4=
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/cs3_ta4_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCyZlYuKYBBsfQPA32UNX1nX6bfSchH2FMDC5e7Afu6hm5b8fay
+UP3GSo8WDUxrlXJVoSbB24rxFuUGRXJ4XFT6Sz6y6WipaE/IGY1AwQc7grXqYHyP
+lJ8ngXkeA/GskEJrb4ce6rmoxbGkKv+MHDeqfet8cCpf5lZghEblojsReQIDAQAB
+AoGAbkoeFUPK6tJdE7sQs8Ot126m93vhuajfCQ7tqss7GMFrEKSx4uN3QFNvyi5G
+hGxL1uxdzZMwfoOs6wecERTj4yDMdk0d6aI0FgPJJVEzfLg2d8FzAKrC27myzpCh
+LO1MrfRhftzDZxWnVghsEj7vA5qdIDnR6yXKl/AI7kFkiAECQQDWcolRC7Hx3quc
+332KLjZ4MR4nWov+h4rk34XLvi/qAofqXrsxXTgFuWB2TMHoAN321LP1f8oqBlUT
+XtIntJW5AkEA1Pewn73mc9pgP1GhyYhiM+wxmPrGg2R6vbfYi5taYzZ91ham6cwG
+pKIh/e3WmDCdtcPxQLMYmyRpMNtZS8A5wQJBAIfDBy/p6YOoZpjv3DhovU8mOWLM
+rig7gzEWWUv9YbQSWh2ET5oW2+qzy1/ZhEDum5cyXaOkfUZRr/aNZxp/9vECQAW8
+SfhzX9J87hymcSoBT0vAr7FEB7agLSIQ4ncYDv4fCJKMd6BSS1eBulKhZichIA42
+IbgxWpdLCr4zGhuNKMECQFwhLWM/W+nfwQCe/n9VO03xvjPXKxoJx9dmuWW3w6el
+NS2WYbGMgXSZNTlQ6Hcu4Ui44rS2qtfZktxAvhnhrV0=
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/cs4_p1_ta3_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQClcmzE3N8V9bAv+9Li2fIsXgrFBDSZDwYTmuiGLUQvV2eBoZMO
+zbVLyhpLMcanc7NwZiEDas2lv0ptlthQnpXXQoSGgPEVP1yFj93uE2HJLHHBwcvo
+6U3rztlXmC2TgQ77bQAxndtvwqqxNmUNjYJ75998A3b5uGxufhNdhazAiQIDAQAB
+AoGAS4hR4A52SrBAH6f4P1kBFwBYKlohKT+SpqCyR4+i8XoV5zi8yqVff5plJq8y
+4oAQC+CUcdrwyBrs/9s+JpBAF6oSY6wNv+pAXkVj7zh24mjZAPBqV6gdsLZ9gWVS
+YSPC4df0BisRvCCQxvYxzx+f8jINVIXGDdEuz6RSLDbKC4ECQQDb7N5/fnXJnZD2
+TIlgjdE/jMOl0QUfcjdrynl5FY3b26LCYfaGlzXJ7LGP/tceo0gatbw0fr7x36qo
+zzeaPj7bAkEAwJXlWXYUcIqWXVBTwQNhEM0Wq6B3wTAYbITxiW58jrb+oatjnt19
+t3fXnbMaoWU11nnqW3lLR0NhYFbmDF7hawJAY0GSYaQncOkGJcMBNWyMBcx3+HxP
+fZPE44csL7PEpHeKC4S/CJtyEUIcGUsAt7klr7hZyq9xaiRyF2H+TETPhQJAEWG2
+CIQCxkGL3rIwTPxcF2MbR7Q8+r+3hJvfHPNO5KaZhsfsPttozFVRrZcLsUNsP4ZT
+Y5wn8i+fq01MiBNMLwJBAJYLdA89YS7tAAcsuAm8g3JofzmRS8Ty/FEBUa8bce2w
+fJOfBvS+8fX9Zn7ZRmgeP24Po07gJGTPDr6D1H3z9kc=
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/cs4_pubCA1_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQC35mfBfwieJwAAzo7kW/Vl0PJOrNQHuCGiWpu940gk//HsBUnC
+NFrK9ZuRKzxqMeo7JVPJCTsrJDKLjEwwlXjpfPDXvPhOJIvF3bRQWqhoeBXuUnNu
+Wpr53Xw5kPHvv+WlGNzU2KGPLmqcF9wgk1nmxD278qgO6hq+qVR/ontIcwIDAQAB
+AoGAQhLzto8pDoHeu2t75cqwmht/5Aqux/M9inLZwFk4I6seRfoEbVWYRZIHihop
+w9IZYZTgzLuXWcHQs1j+Svp5jXXWM/XIoPiN5EjvQfrIS1f8RtQ+RxAQ3lBgio7Q
+h9rTuNHmGAdy1A2q90PZ7xC0ST1E/tH7YMsAQO06D7AJUpkCQQDzbdhitOztfDMQ
+qhYIoCXZrrTUXmAZXslUFYEtSRCJU9EnkYm1L0nkd8X8ZwK6BjYHJJjsWl1HmqLf
+4zvOuyGvAkEAwWWUlH9XPlt7jEJqIm6mcPaBy7IFPQG3bqhzy3adZt36dHFFDiDQ
+KSinIcLRm8F0FBTc+jY5VVeckeMmFKUKfQJAOP5O201g63lYu14XKo3UTtMIo3A1
+L7txh65BQEkLBhwJrCn3A+S+eC9Su3WivcsWezWmWDAQBuO9no2lQxGtIQJAOGYP
+Nl8MajrzhKu5l+D82OSKZYS80lW10Kd/XU5yCJWjfGGr6brX+ajJVKcjyXBZEaIj
+7zPw9FpgZor/h/W5YQJBAIK/WuyWkvVrxD2ydEcBMPcHAHDnv/bSIIsv7L8vYODi
+nUnAblJlP4X7CJ8nO9OzChAeqWeFRyCDhV/7V3jV1lk=
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/i1_ta1_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQDGps75AD9HPjxysKfYKewTiouV2cGTwq9Q+SFWNkBciwiZvVZd
+kVZGXOitRMqLtSkDWKTkGbMxnrc57l4rRaA2XAxj9+TO/yfivXI9/qU2uMaHBIp4
+lEBWP4vaMoKZbBlj6qPCIaK5mYbWsHA4Lk9bNwCsxY5znz3LrgxuuNQeMQIDAQAB
+AoGATd6xn1YDeA/jbinlgYzdZ8OVeAZGJX/ZbWpbMQpPLHerxWg85KzGHwrogpNG
+uoEnNJKZAHk6jybiOClCbL/8TuGl1xuBVdscrtOzT+fZW1IVsxEa84LQ+hM/j+OI
+derkbPGuzyftCX7xrEnLKt7uIgliz5nozfK1EKV3ujgSRmECQQDvUDzVnNwO27XX
+mgYBerSCroGxPnCyaiB82qhC/vBeRUZ5TX35hmmcp9WkNF4RsOso1RNxlJX2tmYa
+c559Z+VdAkEA1IDBDy8K/Vim8eacru2w1T5+eK90gKxodcQoMunyPkFAweqJXbNE
+fQdjyTcAnY45nI+tXtBabLBrRW2RjfKa5QJALzNGLGOZy5xuCy4nzRbkj3nXvpuw
+IqBn8/g0g7JAunczZS1xkUt/fRRlQNPLUfXxC8aq5RYHVfe3v7PaKKXbSQJASNr/
+1bnWNbfgPM1I6Lx7RRERAUV+VuNFSSMAeTw2Hlv23MURZXuhvo/7CTB/WIU7gU7N
+LNWYOu1dScdgAN+tdQJAbQsyLT15GILt7PMyIf4pxREpOKttra1ArB61bmTmsyJ/
+fnPYpu92oOSE6q6uzR3xDaYMCuV8eTLxQJ2DH9qRnw==
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/i2_ta1_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQC5a+zdfwbirKVWifobiwfadtapYsCyz//B65Wx53RC7q8okj6G
+OiSJ8mDN8yndrRg//9fMiFo2/S0WRmdqCIYQLvzPPs29xjDyjMhj0nAXHsC0J1xo
+/4McTKYYL0NOREzeRFK/2tq0G+6F2NcKFAlC6fSHg/OFpoFkV7IS3qcDJwIDAQAB
+AoGAKYCjsuw00VXNaDJX/gQ/jMGeyKkm8p8l4vTlO73Pww+DuzQItKic9xd+XXq4
++zo8PE76sXgvoTFH/z1g9lXUE7dWh/zgTf08velDswfgm8vZGctfDNYyOR7BaLhz
+CAqLCJ6FvVQipKXzInCuHDINIt/35uPCq0ZoofpyG1O+B1kCQQDuBmAqkolg0SXc
+8eQ52jAcwlQuYlz/axFE/9W8yKlBtCSihf5ebk3qA+Jjsk8PXE3fI5Yo8KhDkI0i
+ok5AQ7KzAkEAx2yYGdzzNEUGpOKNbNuTVgaVXeK10bk4280muALhyN1lHvCxDHQQ
+dighuXCqVODOxMk/wTdpVLOl4x/CAOoXvQJADXPey4ksqoQnl600MPDb90Qkbdqx
+Vt4+Q6AR/HF633PG/kiEb+HcFXXSvb++KCgXXp0sR3QSjn8E+wghVBB/cQJAEeqv
+v6MaNpf9ANNZ4W3YzuHIiabUrwL1GMpVsDKSFnnNm/oD7hp/YB466W4132pTKVrr
+X3CbBgEd5kn0JCDkAQJBAJv063BGCCCZWY5nCWwFaHvQ06G2mCMIpxGh+N+LHLGR
+c5B5TGhJsT1Rwnij+NQ93jAyaqc3IxJnHw1eCXk3F84=
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/pubCA1_ta1_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCqsDTR8hZv99UzjUVmLL4B7GjJMcruf5P81hcT4Lr7KeFwOxIV
+OrJClosl0fNZZFj6rY0mO89LiOEyby7jadNKTX7I+Vx6QKkUug4+p/HZf6c/3i2W
+g1LXH+v/6QhmNdg4ihW3Dl6l4k3jdLYeFAV4Z+37gsxVxQPfZI8J0DvF0wIDAQAB
+AoGAdq9jawCMfXq0ss3ujadaz3eVPSD0XHY1br9m+JlxKqfqa+GHJ1/TB94qDzg3
+n9bY0CXRWd6Iu5sIC8unrNWu5n7ZrWjfgHIwpLAyK1inXYc+JH/65KFsuwBHwwer
+oeXEkZQCA2NnwW8z8P3nkurGL6AgWZn1dqXl+DA5oc5u50ECQQDStkPvGXCNtI6V
+EHauC4lF4YKV/Z2EeUmyb6WKlXtNmA2IhK7gUIQsNHtSPXfRGy5asNW+t2vxFyJz
+4RrVJcrRAkEAz1/FH8LsejLgOciJ86j0m7mbRYRKlezopIkE7StT4i5OqgtpeJW3
+bgE6GpSwRS22BdLW0Ae99PncTvfrOlCnYwJASkK0NHr5wOdGbOCNgw9LxNYSSLxG
+HF8Gix1v8SR3fUQ+WMOyQhn+SvoAEF7bcFWtA4dY/Ur1ftVRbheCdmZIUQJAFaZP
+9CLrgU5yblXrYQ7Qirlz5mwLRV+4YgUUCJavaTugZsxONJKc1dU29bN0O6SsDiuW
+1Z0ZTcwQHgZv/mSRNQJBAMUp7XvzH71CBnTrQ5ZX7akV5bAIBFSGwMtDgYZT0DVA
+KSTa6BQ3waXBnSb8hct4//TVIqlj/CadjsTQjCS4h48=
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/pubCA1_ta3_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQC97+FeoTL/7ptkGqPw4mNkq31gXjJgNvVnVNDgE27viMH/DmTS
+9MwH/RgDkPtzt5HJnpeysAqun4jcKf0sGQlD72h8q96R3lHL4jX8lv4T6Tzqlzwq
+75KaMXfkoiRAAW6gWe9+cdm+Wj/tfrbVezhtTBb4/ez7b4xB+/3cDFQc2wIDAQAB
+AoGBALgWqklMVaDGg6dHRsPut8TXjWH8ijjEq58mDnhPfYL9+oCZU9E+4A2SGVdD
+iuMB9XQDmSXgB8pt53jz3WSDM30QG/M30Y/hhauUqvGU7QbxK49sr+iJ+d1gq4PO
+Z8w0SkFkGe+HkKHhFR3iiPZ3t8FXS4fZspqh5V6Z/4UjwR1BAkEA4Z4rYqSoNvSx
+juY19uY/LuWV+eoMnIqB0s50+ossEUr7h0+1PLmLC8mF7towOCohPL0DdeKTQp6U
+84j/1mr9OwJBANeDq1PjITLqDssdKZkEeVksP5RXBsSMEdSazeUwwWGYFZCM3oin
+JAuA19bU9rxMVMLbZTOnESfOUHCN6nwZ5OECQEATwPSqGRBKnKceINN3fxhdoiOx
+YlWPTOHHOxfxMNnUdu1uKOYPODtnx78Xfrxk0r3CXNo9OF+iVGF6VlbaWgMCQH9g
+rE+ti/66xjmYp/Bv64UgGQgFE9Pxccx2HsGauoGDUSOZjyG3oB9IbMnmH1sVxndR
+ExSfZw1e7L5JstDcwSECQHMaTx3u9gaH4o2VQaujeQscxqaVV1NEg4VwnnYvKEPI
+JAfF6Z6kR9ncW5NUlvG4I/RN9EbOE3ndDB1nSGdODkI=
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/pubCA1_ta4_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQC09LGfSZeSGKn6lDf5RV8xxC32Gf6arE272n2ZDOHwsg+buMW6
+WPg+Un2DF8J6+a72JnWfF5qKC6AsONT8rAJ/Gy7Jktp5IRBbfFY83n5kUnNCXBtE
+lIsW3qvrs22KQRHHfgaT+qabAB3s1M0HaUZLfmB/S5P2jcUH/gtEqDzbpQIDAQAB
+AoGAN5qBAfsxEfl2McNdt8DzUW2A2gB+1bRgZnrq4R6uRrHQTf9m8q3oCe57Fs80
+OWmDs6t5tRshp42O+Ee2WrXYRgYjkGpD9p0/95+xdMeu4zQgEEAw+MhD4q0PjniP
+sH92Qy0fN16DO26GZMHmGGCZ5W/ckfHPUObX0btoYFmW+vkCQQDYoqIxj1EGxFrl
+Fq1AwE2saeF3NAqidPwODw04UuUQgmpqOVRp1Yw8jwj8lcBSZz7MDlmad+5bLwDv
+GGOknWnLAkEA1dZV70JzRIuNeQE2xKv5k07b66AM9DAnKMG9mvwFR6lJ3TxSbyWY
+Vt7O/iN368xwNh8sZirR8IYavzDD9EziTwJBAMcQIpQByoW6Vn+d59PRIU6l+I0t
+n/wKHTbZ897mpSAXhqtXRM7/cJ6RHMPk41WVE6o0IXgEbl0Rgv0xXxZ7oyMCQHJ+
+SpDK0ZD3743EmqB/PCglZxcoIQd16OGnqm+bVPBjsgrky3Z7eK+6qLXmI8V7NvGj
+i1BAyRuxkgygfasGp30CQQC0MhnOI5fBf+lCGoxvlSnV7+cojciT3Rd+RH+qjVQ1
+ljhJ2PKo9kxFo2KfRqcJnLpZCVjzm0CZ1twsc3EjqvKC
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/pubCA1_ta5_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDx60GfC/WMZh+MXeCaptM8pq9mNuJci8Sn//tv8GUzsqLyihyU
+rd6W13p1eOFfqMlRCP843y7PN7Ko5IJgVdVAvKCzlKRZUa3YJmTO1VQQWnhS8fi8
+1tynQFeCTy8JFt5biEKqZz4fi7duqR5qEqg1nyiFIyk6IA7NiT5zQOjWGwIDAQAB
+AoGAVLVv0OU7IeJQgbINh5mKtd4X5M6rDITUY48618NxbFzMueiqgVUwb9kbxC6D
+nB9Z/soLtDpSBbUXFhSNonXrqYUantKTYaISJKMAnV0RnmqdGM7JfKH6ocLQPz2+
+eXgq/orO+LtM63Ot5IQSbI5zmGikA8tmsAWyQvjFwvEv4AECQQD6NXZW8kLAWVw7
+rL8phCU4XwoOsu9cBGzNySogGiMd4+F6e6gP2mYIlg32Z9vZW8yXYR7BFirNaBNT
+y1EDyawBAkEA94SsyMKBx5f3xsioILwcnfoCvggkAlO/I5ihHqQwuwl7/0IVXrBx
+4uAjJD6xMry89oFWaisHVMSHIGyfPQuyGwJBANgzHAdzHFTColz6HtBL3DGChdk/
+qm5TcIS8v0av7woj37CLayQPrjzbFEOHaMO/e+COThnAAsoslQ7Bz0Y7nAECQQCn
+ufZEDNpY4Hf88lhL5m0V+CcHkwijsxBhFLqJwwVqmSC3dpZ4leR2sx/dHcaB9Tev
+azGdvA65uHtA05qMiXJlAkAgwV3LXDraq/KgUOQVFrr37gwJXxIINpuCe9ljt9+I
+Wey574+RFcaVIYlKI+7Ql6h6eGlxHCPSaSis9sdEvvMK
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/pubCA2_ta3_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCRJ7eTnV3lnuldeOId/3MO16dOo7/j/zMIyankb7yluTMyKY/a
+0WNRDDvahDK7dChw0wc7PawvfcKeSk58NDfmHXaqRKBWyYODE35nkZmvXVo2XaYg
+I0r1qAgSXklSS67T5rRj+C4dgF+9H1h1NJLOvmo7+CX9ZEm2/msD3AyeTwIDAQAB
+AoGAT1BmbNBWGDvmw95jn4SPeBK6JqwvFAPD/Q9EN8AeUmeJ4+T159j17blDkzkd
+B3SHDG8iymn+hcyv5RIxJIjb6ZyRdHL8lSJG66KrU9kdoDZxn+OhlocHJ5BJZ/o0
+8nmrZLuutY4JN97pzk+jIKD4aBffC6LFiJDpDSIhmfabd+ECQQDBeUb7NklAKPms
+mlCgcwF9FjR2fGh0vIViuc/3bCQpU+WPNlDqBIP0b6TNxQ3nmBCpPF9SO1mcBVYK
+5XJIJHjpAkEAwBDh8mB8oz8STh7ZccqFacDaN8qUYGECtion5YyUTRA1XW4Urg/v
+pXYn1etNw6viGLsrX1lhS350oXZMTdLadwJAZDOBdZ259kbCeIg7db3aaYRUi4EH
+QF5a3rTJZqVVXSocXD2PToQkKzafLgr+lpGFH4ErBRXD5TBGTcJjm8V38QJBAKBO
+dwgCGIV4oyKpBPzA+FGoMXrXjrhSwByjWuFxUGZx3Ni6hHAzxOXplJ4r46Ap2nCh
+6DWROG/2gAoz3sQl9UkCQChPoIdCI+wx9EfHnELXMzzEIuqAS1DmJ+CXKTsmzpLg
+UoKNATRkMIM6elwJ2VQvXdMkcO4iApiBD3mL4GgAoEM=
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/pubCA3_ta3_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQCVo4W1cfMvsqrCM/9McEDhBkTofA94dyEdpornDOdlEvXMmc9K
+AL1e6k3Ho4WTDExKF0RJ2bkGRbSZ0JUIqvbEB3VGpyY65QFkJnTHWHPpcE+XFU4w
+vVWOy0MzNor5zFfm7iobqg5nUcVSYatDW/LXLCBcwXKkOruwoju0buO53wIDAQAB
+AoGBAIDK4K995zi7h7tk86x/xWeodLDA7rPZnRgfGtiow5S8D/FMxRxFrLg/5Dgb
+J0GcSSFQC0eg7F5Yqovk+hEezQo1EVX6I/goqoatJhquys0pObPzC5hLnJSmSpm0
+HA9y6afbE33nLGaOQYx4JTSMLdVrQsGQbLTy3lzxJSkDM54RAkEAxHMNHL3Nwsc0
+rjGAiqsw+fQWejlKTGLJRAyw8fwIris9JoUnzqjGYhCP6NLQzcteksbqvHcktBpC
+Fa5qo5CBaQJBAML/2dhsi7zy5N0gTK+msQc6zn7mZKeGD6HpVSgwi1NCmmQmqCcb
+HiKq9TaXGY3+XRrNnLiKSPP6e0NxEB44sAcCQG2VeEUGI9d5ZAuflYLFCCcGX9uC
+Rc3idT8+jR4PZ5AwkoYAVTpUr4VYk85eexexUGo0CBFlrNXCqAaMKvRe0bECQCUV
+IKleowhQrKM8lDjHG11DmqdZSwTsoqZoyA/3g1dXECNBkrK1Hnr7RdyWyX5ORAhn
+14jki1ESbkR6CNWmdBsCQQCrRaq+vNQgAl/JVf4GT97pW2G/3DJxKqfrSQWNiQit
+hDZ9S5xhIFNsDsB3AxAoPKk5qk71wMc9WC0G4kd/E9Iy
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/pubCA4_ta3_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQCyinoiF6O+/zVz8RM04sEC4x6m2LzCKaad4ZYLKzhC2/Sf+AXA
+2YGrNzXaJBvllWvF2ujBFMPHPqQgziV1XxPUlE18aUKC7wnJsRHdoNnidkf9aOfs
+EQL3ppLaULid6JCd9+LWzTV+HPYxcTn+Gl1JzFDHNP3L4YU65KYVmn9rxQIDAQAB
+AoGAdaD6en+sqGeoJe0MxGko1OgiB7cAFcQvPBGmM1GUTahw8PwNflNPNSi42DG2
+F3psePyTILK3kgvZQqvOzheIDgprhtqwDcaKe/voNJ/toa0dOwebP02VuaM7TFnc
+P01f24icN3hvtc8aJ8qehXYKBeq5WhugA2+lSjXv0MUP0TkCQQDf+iepx5BTP5t8
+eDdqbGyFF4EE/ZXYRZgK/k7OXYLqqTqTXwxrsXhgxeJ1j7lmg1NQfkKPhYhdDBGF
+Y9oNP8TDAkEAzBFMe1PcgH3J8dbSK0SNp0wpTxdeIDw40J1z5K2O7bwT7h2BABul
+1eWWL2MrAM/rYVkWoopIDJj6KJf8FUdk1wJAMlq9PBBfxDeSr2Mfok+J/koQeZzB
+aYQL8LzH3uFrI3K0dplx42xc0fTrOt77Ia74tioMsNOmmrSx47lVNpFVnQJBAIsS
+3wTNymDnWVGwDdvfBIsXpK96RXPClxXVuL4IangqzYpiISBpt0NnDEuPUidjjA70
+IDD1/NRZDWPM8MevuFECQQC+acVEnV2XNb7K4eeXeG/A9ay6nKemNF1iSFeuiPHq
+XWOs1du2hPSSsLxWGJiAXn0UgZou3Uo8ZVcUoUkRxnHU
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/ta1_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQCnZGdT8prJzqlKkhZXYcOvnQ6fYYKtz3+qWfL6Bj2irU/bkD5I
+PgDU65bCGbPgavIhYYOS3YZQ/8Y/3iKcHHTLCQbneMKM+JguteTC9L+3kkavx9Zs
+WQfZjAaWG+8Q3D74iwidvYE8DaPpVV8bBDm5f/TP1vmiMTqDliGSpxPETQIDAQAB
+AoGAGY3tbFZsJQTkuVqmCH8HVcb/VXuYbJpx3frPajYLsMsOlvFlYLf+foLcyBMO
+b+NDxa7SXFhvSexSQqvR0s1RUvJ9vBrP/14EC9ObTvlafakt2KfizQSuF/LYh2Q8
+T34YnF7TX7F23d8bi2OmRdBRD4+v81LtkpH/qNgTNda4tiECQQDSry1gxKWtkr7J
+qcncDuhWBs6rppVEQ9EqXUsQjv9a/U7O7Ta0sxMuz8zHpbj+xro6UnH5Uzav7jIa
+WDEmMb3pAkEAy2VztwOAowfYr4i3utMsOkq7h4N2K4kW3YrWmmPJFSxp6LzYL2bu
+qQINrrb3QaIu3uN10YzLXZ+o6/wzA2OgxQJAfKbGi2VtvPeAyCIb24Y6coOOjcJ+
+uCgDvjP6cK6aaMRMd2OkJV96Lw0lVM45WQxNLKqQ4noYdhjRLgMV+Uoe2QJAWJi5
+fdetudYaIeP4vA1uL3oME6xE1hPh/OCUOC4NEgcFnxZbSNKaVM4LLbaPH2zI49fK
+o1uj3gVE7H4vrmNATQJAF5DiwcQmoF0EPY1WgAcd1tgcOwnJrC4zbfEnxOtEG2uZ
+GHVI1XLbEJTdwQUdSCBG9XT40+2hrG0Y17zoFyLpyg==
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/ta2_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQC+PpzYhIJeS5+cDmSMn9CE2OTvXg7Cg5Tg729akT7FuRvPpYzY
+OX8R01Eft3x5Dg/0Dh00SXDMAQk0/8t5d4Q52b9nLOIViKea7K5HZxpy+x2+YCY6
+Io61Jj0Ew8Yjh008NFhdmvahoGHapsAGPsNr2/TLeu/3RO+xN+OGMXD8mwIDAQAB
+AoGAWXFelH1YPbUYSWqK44KPqqW+nLt//PuYF1j65X28IYGyDaIr4czGbT8IuPyv
+TMrLvVaVbGvK2F70UTKiG22RgEFjyjgm5fKhQQgZ+/hTVqrCefk8+ZdBOfhM4V4q
+FAQ2TOSw8uMz6JfPVJuaCBu5T64+3DlamRgZu/2rJh2jMSECQQDry16/peKyWybL
+hvre2kJW48gSniTwgjD/lsisna5H7F7iGPBfG/awLdexmKRL4akW56FXp7QsNf4W
+CemBUV5fAkEAzowDrLxUqAs37ovuKYpGyoCT7uPzZRKWe7zJYBPeP1NtzAjLN75B
+KE1uk9tHlGtrkWKOEfGq7geZWQZ6v+6TRQJBAL9xfVoo+2hILbVtwF4T42zcv+Kt
+19wWOGYsLH5J/+iRd3AnQ3JVJ/NfJRMilbKuYzUfl5WtqdGDfOqz3YyLXg0CQEcE
+sYbFQr59DQBCsOMrnmemijcLvfa0y3VEVmFos3RGtWwAYg+KpVC8PxcrwJLx1Iyq
+vHrDA6jQiBOqPK6d05kCQQDG8QyXPuvPrAdYlQf++7VZ0nYAEovLj4MZMQoWAsbz
+NdaQsiwzO6tSJHqIcQIHu0CGJId+TCP268Lh7mgrOtoc
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/ta3_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXgIBAAKBgQDMMufSDb6CH0jL13RTyXqEmSrS0AGs4iajjAKs2FETMR3GTJN0
+hJ3nMoeqiNvtQWnuXc1xvzvDRVjCxzg+5o6jftfQV/tTqcOdUWtJQ3PqaRifOvJC
+nDx7EyH1uLScWPzqp70/U0WJZI1WEztOJtH5yjqNXnPOfw2xjcLhlgQzsQIDAQAB
+AoGBAIaK3/2h+q0nycItYsM2FFi7xuCCFyh/FbBatwSFvt2jVhfrKpjyLExCGet+
+I1Iu8IoTGiNhOhJOZc5ojyG6ra3UdAbB9H4wuW3xcOxt4rdjDzkWGYFF0XgkvHqJ
+nEEtOoLFn+p1CUlt8Bz9Hu7t/X4zBxR5GOArKB2yRB6cSVwxAkEA7xz7ziSrTeTa
+vd0mrxwhwlEqn3s35xdPaOOf97DCUJt+ywlWKqYuBWjkjb8b1x1JRU5lC+D5PAnz
+JIHFCl48BQJBANqesTFP6b/SUWtTMcH0yBbv+2oPHMgixQ2AUWPZcLKXMXEJWjFA
+AWwwFmeHWo4AFmXijOGb9h+aEAhuPX/zlL0CQQCGk2RxOBglxfkKxO4hvg6OBAqe
+KcZjzK3H1dzRle03Wty4vy9833ylVMzVrkqn/nafiCi8z8jWbq8my9avKCxVAkBx
+9jViAklUYBtnOgf/Fk3Tfyfs4pHbVhyobBKBXVDdF+mDBiAI+leDgRG8yBcRXMRQ
+Oie8V6OWV6Yx7t2KPHx1AkEAkdoOKF6xDdhLGlhKGjTabaMNd8uPTE1NQe0MqcQC
+YCGznZOzxLVF0vUjPhjE9yiFIKT/xlSQaNou6s7wUtwIXQ==
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/ta4_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCfRhrlCZimvc+2XCD8gteG0tCXIMYSpV9seiyaaEy6dTIJ/tWz
+W2rU+5Wqv1o2wy5XPdH0h0yKZhCJOdi5Lxo/N/oG0OJdPwaLpG6FT2SPcgX7/qoH
+9a2wScU27pbASViI9aIvO5B9uB7XsGfNuTgFjaeUjEAzCx99A9yZwVVJWQIDAQAB
+AoGAFEQkWe5dqSHP00FnxRmU+QfMGN7HtUmrma72C/Onh7Yv1svBP2AreMxGYAKX
+JQ6yz9EC7R1mJNoV0pA0vmN68ErwkdjIEi0FDkp0BmjaaN328g3HiFP4tiLtftdW
+96eqr1Sche7b9BILHbDbNRo8jnfaNp/kGf2/5wJ1GUHLVYECQQDRQlxCmZTulSjC
+1Ev40BURqKhDlhm4Cj6Nn8cU8bSBqThzPIHCPCeYh7tqVn8foQIats8PR458LMhe
+e1Uuf9kRAkEAwtmIrxLQkctTPWIUWXike/ApEUNTp7vBMgLwLXWN/HoVERdY8pBT
+HW+ESH73L5imS5gRKIbArvCYRNvL/Z4ryQJAFLM+0yvEKtHAhX1gwo06+FM5ye3I
+P4dr5rCejfjXBViLCAM9RsySkikjJgLGcoeH4MKiuv02IByB+a6zn3TwMQJBAIqz
+x3S48/eUwUBk3Q+DrbL8Fn/PaXFxWel75fS2RciALxbng83HpyLBC21/0/3xsA8H
+xM8QfYEKi5oYzHFRcuECQBS77ANtI6Lw69l7Yq7KO7Z5eVQmQgJ1KSd7gv6vQuaW
+o/ofMLlaxs1MbaLcNLDCq61JlYLS/uMhf0fL5Gv7gdY=
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/keys/ta5_key.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQDAvhLc3dRBq46c+mMstzZqertxTl56cFDmN7RXdXQhRkjuLZtC
+pD9PFgXat3NKTKvBZLKonP63gtPs3oOw8CaGwNo5ypewzjxvFsMHJkcuOZSPowUh
+LMUVKZuYIxJ3OLipD65pxFSi3ANS/pkoLvD80aaRiZu2DMGbSOCZpULpCwIDAQAB
+AoGAZ4KspqkLYOk9gdiGgnEybCTVnZg07RR8nea0l3Oglm4kpKUhiLyks1hkdH2p
+EPH0G7x0plEKCovcPI2Ts+aFCVHtVtIQpQRuHWe0f6oDC6MvQxcBN6Sm4jdLfERU
+Vsp/1TlCAJaNaLfBZbxUVJkX1NoVq3H1u3nsflreW+zTSkECQQDyju9U1yB6Otta
+IchTrjqnJyqcygPnHWSViU9Z9jO9T26XUTsxanR9FIFT2Up1G1XlEBpddwrspBn9
+OF+ZJEBjAkEAy2xsebaA/Nig0OUKHWEFN0h8kvyK4q/ugQ9+lQcAi3O0Tw5LSSzt
+tws7s+2f4+5H3APKWwFlVLfCtDdv744ROQJAZ4qsj8LlkkfdqzQQl+ggEYqenh9+
+WwIpFcxvmy+GFqH5y45Zfla7M0m1i12Ocz8gA5BEMPHIMAw9K+MMrArVkQJAd0aE
+uD0NlrQCX1ncu2s23rpu6NSRLufPZfdK1mD7rcjTEYOlGyvv2mMIx7BuDvyZP+Ut
+En1YB/uTe44B4Smg6QJAOjWqRC8GeK3fyl8BWxBzy00vNQCkgft7OspPM7zD7EGs
+sujcp4G5JwuOPaZ4R7pHhWa/I7kBw9hclG6JvS8GLg==
+-----END RSA PRIVATE KEY-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/publisher_cas/03.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,62 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 3 (0x3)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=i2_ta1/emailAddress=i2_ta1
+        Validity
+            Not Before: Aug  4 20:59:23 2010 GMT
+            Not After : Apr 30 20:59:23 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta1/emailAddress=pubCA1_ta1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:aa:b0:34:d1:f2:16:6f:f7:d5:33:8d:45:66:2c:
+                    be:01:ec:68:c9:31:ca:ee:7f:93:fc:d6:17:13:e0:
+                    ba:fb:29:e1:70:3b:12:15:3a:b2:42:96:8b:25:d1:
+                    f3:59:64:58:fa:ad:8d:26:3b:cf:4b:88:e1:32:6f:
+                    2e:e3:69:d3:4a:4d:7e:c8:f9:5c:7a:40:a9:14:ba:
+                    0e:3e:a7:f1:d9:7f:a7:3f:de:2d:96:83:52:d7:1f:
+                    eb:ff:e9:08:66:35:d8:38:8a:15:b7:0e:5e:a5:e2:
+                    4d:e3:74:b6:1e:14:05:78:67:ed:fb:82:cc:55:c5:
+                    03:df:64:8f:09:d0:3b:c5:d3
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                E8:81:62:06:D5:A6:C6:2E:6C:2A:4F:A3:21:42:59:CD:19:5B:32:ED
+            X509v3 Authority Key Identifier: 
+                keyid:E3:6D:6B:62:16:42:41:2B:9C:3B:68:01:F3:EF:16:3C:31:83:05:41
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=i1_ta1/emailAddress=i1_ta1
+                serial:02
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        72:ed:f0:65:97:65:56:53:3c:c8:78:ae:a1:22:70:c3:a0:1d:
+        db:42:3b:75:43:c9:b1:98:7d:7c:c4:c0:41:07:b4:18:72:26:
+        34:98:35:c1:20:17:1c:dc:53:59:a6:d9:42:01:f3:0d:9b:16:
+        f9:15:73:3f:1f:49:71:06:f0:0c:b0:49:d2:2c:89:f7:42:7f:
+        b5:37:55:fb:49:2e:2b:8e:c1:70:e3:84:96:13:ab:63:f9:70:
+        11:89:86:b7:e9:db:1e:56:dc:9a:78:3b:ad:47:30:5f:98:28:
+        8c:ea:f2:8f:af:40:b8:93:73:72:b0:be:e0:52:72:69:e8:ee:
+        52:4d
+-----BEGIN CERTIFICATE-----
+MIIDKTCCApKgAwIBAgIBAzANBgkqhkiG9w0BAQsFADBuMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEPMA0GA1UEAxQGaTJfdGExMRUwEwYJKoZIhvcNAQkBFgZpMl90YTEw
+HhcNMTAwODA0MjA1OTIzWhcNMTMwNDMwMjA1OTIzWjB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0ExX3RhMTEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0ExX3RhMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqrA00fIWb/fVM41F
+Ziy+AexoyTHK7n+T/NYXE+C6+ynhcDsSFTqyQpaLJdHzWWRY+q2NJjvPS4jhMm8u
+42nTSk1+yPlcekCpFLoOPqfx2X+nP94tloNS1x/r/+kIZjXYOIoVtw5epeJN43S2
+HhQFeGft+4LMVcUD32SPCdA7xdMCAwEAAaOBzjCByzAdBgNVHQ4EFgQU6IFiBtWm
+xi5sKk+jIUJZzRlbMu0wgZgGA1UdIwSBkDCBjYAU421rYhZCQSucO2gB8+8WPDGD
+BUGhcqRwMG4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYD
+VQQHEwpNZW5sbyBQYXJrMQ0wCwYDVQQKEwRwa2c1MQ8wDQYDVQQDFAZpMV90YTEx
+FTATBgkqhkiG9w0BCQEWBmkxX3RhMYIBAjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
+SIb3DQEBCwUAA4GBAHLt8GWXZVZTPMh4rqEicMOgHdtCO3VDybGYfXzEwEEHtBhy
+JjSYNcEgFxzcU1mm2UIB8w2bFvkVcz8fSXEG8AywSdIsifdCf7U3VftJLiuOwXDj
+hJYTq2P5cBGJhrfp2x5W3Jp4O61HMF+YKIzq8o+vQLiTc3KwvuBScmno7lJN
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/publisher_cas/0C.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,62 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 12 (0xc)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta3/emailAddress=ta3
+        Validity
+            Not Before: Aug  4 20:59:25 2010 GMT
+            Not After : Apr 30 20:59:25 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta3/emailAddress=pubCA1_ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:bd:ef:e1:5e:a1:32:ff:ee:9b:64:1a:a3:f0:e2:
+                    63:64:ab:7d:60:5e:32:60:36:f5:67:54:d0:e0:13:
+                    6e:ef:88:c1:ff:0e:64:d2:f4:cc:07:fd:18:03:90:
+                    fb:73:b7:91:c9:9e:97:b2:b0:0a:ae:9f:88:dc:29:
+                    fd:2c:19:09:43:ef:68:7c:ab:de:91:de:51:cb:e2:
+                    35:fc:96:fe:13:e9:3c:ea:97:3c:2a:ef:92:9a:31:
+                    77:e4:a2:24:40:01:6e:a0:59:ef:7e:71:d9:be:5a:
+                    3f:ed:7e:b6:d5:7b:38:6d:4c:16:f8:fd:ec:fb:6f:
+                    8c:41:fb:fd:dc:0c:54:1c:db
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                47:D6:CB:F2:38:3E:A8:40:85:4A:BE:EF:F8:85:B3:49:FF:D0:8F:16
+            X509v3 Authority Key Identifier: 
+                keyid:E0:CE:66:66:57:70:37:16:AF:EB:65:B6:15:DC:2D:2C:B7:B4:49:4D
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta3/emailAddress=ta3
+                serial:E1:F8:52:2F:AC:F4:00:EE
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        6a:25:8d:33:01:c1:a0:fe:99:5f:f0:b4:8a:39:86:55:f5:6c:
+        59:2a:84:a5:01:10:dd:1a:b6:a2:52:17:62:e1:e5:d5:8a:e9:
+        09:bd:04:95:b1:a4:b3:ec:9b:73:f3:54:12:26:97:a5:1e:52:
+        9e:bf:93:c7:4d:dd:a3:c4:ec:0b:46:3e:e4:b7:c3:47:17:68:
+        15:df:a1:1a:67:c0:8b:f6:a8:ea:ab:81:6a:fc:a3:4c:5b:0e:
+        ca:cc:b7:bf:e5:35:73:e9:95:d0:ad:8c:fc:2a:7d:2c:ee:6b:
+        09:53:2f:f3:9b:57:fa:32:bb:02:f9:10:fa:30:a2:e3:55:0c:
+        4a:73
+-----BEGIN CERTIFICATE-----
+MIIDJTCCAo6gAwIBAgIBDDANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEMMAoGA1UEAxMDdGEzMRIwEAYJKoZIhvcNAQkBFgN0YTMwHhcNMTAw
+ODA0MjA1OTI1WhcNMTMwNDMwMjA1OTI1WjB2MQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UEChMEcGtn
+NTETMBEGA1UEAxQKcHViQ0ExX3RhMzEZMBcGCSqGSIb3DQEJARYKcHViQ0ExX3Rh
+MzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAve/hXqEy/+6bZBqj8OJjZKt9
+YF4yYDb1Z1TQ4BNu74jB/w5k0vTMB/0YA5D7c7eRyZ6XsrAKrp+I3Cn9LBkJQ+9o
+fKvekd5Ry+I1/Jb+E+k86pc8Ku+SmjF35KIkQAFuoFnvfnHZvlo/7X621Xs4bUwW
++P3s+2+MQfv93AxUHNsCAwEAAaOB0DCBzTAdBgNVHQ4EFgQUR9bL8jg+qECFSr7v
++IWzSf/QjxYwgZoGA1UdIwSBkjCBj4AU4M5mZldwNxav62W2FdwtLLe0SU2hbKRq
+MGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpN
+ZW5sbyBQYXJrMQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTMxEjAQBgkqhkiG
+9w0BCQEWA3RhM4IJAOH4Ui+s9ADuMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN
+AQELBQADgYEAaiWNMwHBoP6ZX/C0ijmGVfVsWSqEpQEQ3Rq2olIXYuHl1YrpCb0E
+lbGks+ybc/NUEiaXpR5Snr+Tx03do8TsC0Y+5LfDRxdoFd+hGmfAi/ao6quBavyj
+TFsOysy3v+U1c+mV0K2M/Cp9LO5rCVMv85tX+jK7AvkQ+jCi41UMSnM=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/publisher_cas/11.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,55 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 17 (0x11)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta3/emailAddress=ta3
+        Validity
+            Not Before: Aug  4 20:59:27 2010 GMT
+            Not After : Apr 30 20:59:27 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA2_ta3/emailAddress=pubCA2_ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:91:27:b7:93:9d:5d:e5:9e:e9:5d:78:e2:1d:ff:
+                    73:0e:d7:a7:4e:a3:bf:e3:ff:33:08:c9:a9:e4:6f:
+                    bc:a5:b9:33:32:29:8f:da:d1:63:51:0c:3b:da:84:
+                    32:bb:74:28:70:d3:07:3b:3d:ac:2f:7d:c2:9e:4a:
+                    4e:7c:34:37:e6:1d:76:aa:44:a0:56:c9:83:83:13:
+                    7e:67:91:99:af:5d:5a:36:5d:a6:20:23:4a:f5:a8:
+                    08:12:5e:49:52:4b:ae:d3:e6:b4:63:f8:2e:1d:80:
+                    5f:bd:1f:58:75:34:92:ce:be:6a:3b:f8:25:fd:64:
+                    49:b6:fe:6b:03:dc:0c:9e:4f
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 Issuer Alternative Name: critical
+                <EMPTY>
+
+    Signature Algorithm: sha256WithRSAEncryption
+        07:01:15:2c:e6:eb:e6:8a:b4:dc:6c:fa:f5:30:2d:32:e1:6f:
+        27:76:6d:1e:c8:4b:e1:ae:f8:96:fb:15:0e:0e:8f:e7:fe:43:
+        d3:af:f7:b3:f8:19:e0:77:38:43:d3:6b:86:6b:f1:b6:36:b5:
+        34:66:49:ad:c0:58:7a:40:18:da:48:af:b4:b3:24:43:92:06:
+        df:84:c2:ac:ea:c1:0d:8a:82:86:39:ce:44:1e:72:f2:46:0e:
+        c4:cf:70:78:86:a9:8f:35:83:5f:74:e1:30:a3:90:29:f2:f2:
+        5f:d1:d3:84:84:4d:1d:08:ea:05:24:2d:d0:ae:3d:0f:78:7c:
+        c7:10
+-----BEGIN CERTIFICATE-----
+MIICdTCCAd6gAwIBAgIBETANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEMMAoGA1UEAxMDdGEzMRIwEAYJKoZIhvcNAQkBFgN0YTMwHhcNMTAw
+ODA0MjA1OTI3WhcNMTMwNDMwMjA1OTI3WjB2MQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UEChMEcGtn
+NTETMBEGA1UEAxQKcHViQ0EyX3RhMzEZMBcGCSqGSIb3DQEJARYKcHViQ0EyX3Rh
+MzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAkSe3k51d5Z7pXXjiHf9zDten
+TqO/4/8zCMmp5G+8pbkzMimP2tFjUQw72oQyu3QocNMHOz2sL33CnkpOfDQ35h12
+qkSgVsmDgxN+Z5GZr11aNl2mICNK9agIEl5JUkuu0+a0Y/guHYBfvR9YdTSSzr5q
+O/gl/WRJtv5rA9wMnk8CAwEAAaMhMB8wDwYDVR0TAQH/BAUwAwEB/zAMBgNVHRIB
+Af8EAjAAMA0GCSqGSIb3DQEBCwUAA4GBAAcBFSzm6+aKtNxs+vUwLTLhbyd2bR7I
+S+Gu+Jb7FQ4Oj+f+Q9Ov97P4GeB3OEPTa4Zr8bY2tTRmSa3AWHpAGNpIr7SzJEOS
+Bt+EwqzqwQ2KgoY5zkQecvJGDsTPcHiGqY81g1904TCjkCny8l/R04SETR0I6gUk
+LdCuPQ94fMcQ
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/publisher_cas/13.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,62 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 19 (0x13)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta3/emailAddress=ta3
+        Validity
+            Not Before: Jan  1 01:01:01 2009 GMT
+            Not After : Jan  2 01:01:01 2009 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA3_ta3/emailAddress=pubCA3_ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:95:a3:85:b5:71:f3:2f:b2:aa:c2:33:ff:4c:70:
+                    40:e1:06:44:e8:7c:0f:78:77:21:1d:a6:8a:e7:0c:
+                    e7:65:12:f5:cc:99:cf:4a:00:bd:5e:ea:4d:c7:a3:
+                    85:93:0c:4c:4a:17:44:49:d9:b9:06:45:b4:99:d0:
+                    95:08:aa:f6:c4:07:75:46:a7:26:3a:e5:01:64:26:
+                    74:c7:58:73:e9:70:4f:97:15:4e:30:bd:55:8e:cb:
+                    43:33:36:8a:f9:cc:57:e6:ee:2a:1b:aa:0e:67:51:
+                    c5:52:61:ab:43:5b:f2:d7:2c:20:5c:c1:72:a4:3a:
+                    bb:b0:a2:3b:b4:6e:e3:b9:df
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                E9:26:60:80:D1:41:FF:4A:A4:0C:14:05:C0:6B:5D:84:C5:F0:15:04
+            X509v3 Authority Key Identifier: 
+                keyid:E0:CE:66:66:57:70:37:16:AF:EB:65:B6:15:DC:2D:2C:B7:B4:49:4D
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta3/emailAddress=ta3
+                serial:E1:F8:52:2F:AC:F4:00:EE
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        7f:d0:e5:cc:61:28:7a:14:1f:6e:43:f2:1f:98:55:8f:3f:9b:
+        f4:8c:1d:2d:4d:c4:c5:08:2f:eb:1a:6d:1d:99:80:57:3b:45:
+        d3:4f:71:6f:61:ca:17:83:9f:23:5f:0a:77:7b:25:b2:53:2b:
+        ca:e3:3d:ad:28:57:99:b9:3a:d8:f8:d2:3f:55:d8:f4:ef:94:
+        81:36:58:4f:98:a0:2b:6b:8d:77:cb:3d:bd:32:9a:5e:dd:1e:
+        7f:4f:02:fe:de:35:a8:f0:85:3a:eb:a9:22:5a:dd:9d:ba:dc:
+        40:b7:9f:ba:54:f8:84:7d:39:42:ec:87:73:85:11:1d:36:41:
+        9f:e7
+-----BEGIN CERTIFICATE-----
+MIIDJTCCAo6gAwIBAgIBEzANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEMMAoGA1UEAxMDdGEzMRIwEAYJKoZIhvcNAQkBFgN0YTMwHhcNMDkw
+MTAxMDEwMTAxWhcNMDkwMTAyMDEwMTAxWjB2MQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UEChMEcGtn
+NTETMBEGA1UEAxQKcHViQ0EzX3RhMzEZMBcGCSqGSIb3DQEJARYKcHViQ0EzX3Rh
+MzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAlaOFtXHzL7KqwjP/THBA4QZE
+6HwPeHchHaaK5wznZRL1zJnPSgC9XupNx6OFkwxMShdESdm5BkW0mdCVCKr2xAd1
+RqcmOuUBZCZ0x1hz6XBPlxVOML1VjstDMzaK+cxX5u4qG6oOZ1HFUmGrQ1vy1ywg
+XMFypDq7sKI7tG7jud8CAwEAAaOB0DCBzTAdBgNVHQ4EFgQU6SZggNFB/0qkDBQF
+wGtdhMXwFQQwgZoGA1UdIwSBkjCBj4AU4M5mZldwNxav62W2FdwtLLe0SU2hbKRq
+MGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpN
+ZW5sbyBQYXJrMQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTMxEjAQBgkqhkiG
+9w0BCQEWA3RhM4IJAOH4Ui+s9ADuMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN
+AQELBQADgYEAf9DlzGEoehQfbkPyH5hVjz+b9IwdLU3ExQgv6xptHZmAVztF009x
+b2HKF4OfI18Kd3slslMryuM9rShXmbk62PjSP1XY9O+UgTZYT5igK2uNd8s9vTKa
+Xt0ef08C/t41qPCFOuupIlrdnbrcQLefulT4hH05QuyHc4URHTZBn+c=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/publisher_cas/15.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,62 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 21 (0x15)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta3/emailAddress=ta3
+        Validity
+            Not Before: Jan  1 01:01:01 2035 GMT
+            Not After : Jan  2 01:01:01 2035 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA4_ta3/emailAddress=pubCA4_ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:b2:8a:7a:22:17:a3:be:ff:35:73:f1:13:34:e2:
+                    c1:02:e3:1e:a6:d8:bc:c2:29:a6:9d:e1:96:0b:2b:
+                    38:42:db:f4:9f:f8:05:c0:d9:81:ab:37:35:da:24:
+                    1b:e5:95:6b:c5:da:e8:c1:14:c3:c7:3e:a4:20:ce:
+                    25:75:5f:13:d4:94:4d:7c:69:42:82:ef:09:c9:b1:
+                    11:dd:a0:d9:e2:76:47:fd:68:e7:ec:11:02:f7:a6:
+                    92:da:50:b8:9d:e8:90:9d:f7:e2:d6:cd:35:7e:1c:
+                    f6:31:71:39:fe:1a:5d:49:cc:50:c7:34:fd:cb:e1:
+                    85:3a:e4:a6:15:9a:7f:6b:c5
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                A5:56:E6:44:AE:89:5C:8E:24:C2:58:B6:C6:D1:7B:51:BC:F4:7A:83
+            X509v3 Authority Key Identifier: 
+                keyid:E0:CE:66:66:57:70:37:16:AF:EB:65:B6:15:DC:2D:2C:B7:B4:49:4D
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta3/emailAddress=ta3
+                serial:E1:F8:52:2F:AC:F4:00:EE
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        65:98:33:cd:b4:af:b0:67:bf:0e:8e:0e:d6:8c:fd:a6:7c:18:
+        88:a7:2a:ac:55:5d:b3:95:f3:8f:5f:d7:00:78:cc:fd:00:6a:
+        0c:75:12:00:7b:88:f4:93:66:00:be:c7:ce:d7:75:72:0e:44:
+        3e:fc:b2:ff:d1:23:72:9c:be:a7:a7:70:d9:af:0d:e5:84:43:
+        77:6e:73:60:ff:40:f0:f6:94:17:8e:4e:57:0d:d6:35:4f:5b:
+        46:d6:36:6e:3a:03:e6:13:b9:4c:c9:fd:75:c7:e6:4f:f3:75:
+        bc:2a:38:dd:7c:9b:3c:5a:75:27:c9:00:5d:11:11:b6:4e:e9:
+        97:b9
+-----BEGIN CERTIFICATE-----
+MIIDJTCCAo6gAwIBAgIBFTANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEMMAoGA1UEAxMDdGEzMRIwEAYJKoZIhvcNAQkBFgN0YTMwHhcNMzUw
+MTAxMDEwMTAxWhcNMzUwMTAyMDEwMTAxWjB2MQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UEChMEcGtn
+NTETMBEGA1UEAxQKcHViQ0E0X3RhMzEZMBcGCSqGSIb3DQEJARYKcHViQ0E0X3Rh
+MzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsop6Ihejvv81c/ETNOLBAuMe
+pti8wimmneGWCys4Qtv0n/gFwNmBqzc12iQb5ZVrxdrowRTDxz6kIM4ldV8T1JRN
+fGlCgu8JybER3aDZ4nZH/Wjn7BEC96aS2lC4neiQnffi1s01fhz2MXE5/hpdScxQ
+xzT9y+GFOuSmFZp/a8UCAwEAAaOB0DCBzTAdBgNVHQ4EFgQUpVbmRK6JXI4kwli2
+xtF7Ubz0eoMwgZoGA1UdIwSBkjCBj4AU4M5mZldwNxav62W2FdwtLLe0SU2hbKRq
+MGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpN
+ZW5sbyBQYXJrMQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTMxEjAQBgkqhkiG
+9w0BCQEWA3RhM4IJAOH4Ui+s9ADuMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN
+AQELBQADgYEAZZgzzbSvsGe/Do4O1oz9pnwYiKcqrFVds5Xzj1/XAHjM/QBqDHUS
+AHuI9JNmAL7Hztd1cg5EPvyy/9Ejcpy+p6dw2a8N5YRDd25zYP9A8PaUF45OVw3W
+NU9bRtY2bjoD5hO5TMn9dcfmT/N1vCo43XybPFp1J8kAXRERtk7pl7k=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/publisher_cas/17.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,62 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 23 (0x17)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta4/emailAddress=ta4
+        Validity
+            Not Before: Aug  4 20:59:28 2010 GMT
+            Not After : Apr 30 20:59:28 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta4/emailAddress=pubCA1_ta4
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:b4:f4:b1:9f:49:97:92:18:a9:fa:94:37:f9:45:
+                    5f:31:c4:2d:f6:19:fe:9a:ac:4d:bb:da:7d:99:0c:
+                    e1:f0:b2:0f:9b:b8:c5:ba:58:f8:3e:52:7d:83:17:
+                    c2:7a:f9:ae:f6:26:75:9f:17:9a:8a:0b:a0:2c:38:
+                    d4:fc:ac:02:7f:1b:2e:c9:92:da:79:21:10:5b:7c:
+                    56:3c:de:7e:64:52:73:42:5c:1b:44:94:8b:16:de:
+                    ab:eb:b3:6d:8a:41:11:c7:7e:06:93:fa:a6:9b:00:
+                    1d:ec:d4:cd:07:69:46:4b:7e:60:7f:4b:93:f6:8d:
+                    c5:07:fe:0b:44:a8:3c:db:a5
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                EE:8D:78:53:11:FE:07:CB:C8:55:4B:EF:A6:2F:E1:83:72:BB:BA:21
+            X509v3 Authority Key Identifier: 
+                keyid:FE:14:53:EF:9C:0B:AB:ED:96:22:70:11:C2:E6:7D:2E:40:B7:7F:B5
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta4/emailAddress=ta4
+                serial:C0:C8:77:B4:4C:49:4F:AB
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        5c:2c:f2:7c:8d:72:aa:d1:e2:20:a2:c6:76:84:44:b9:6e:54:
+        2c:39:95:99:a9:50:bb:1c:b9:9e:8e:04:92:b5:b6:95:17:92:
+        a8:0b:09:3e:f5:5a:10:99:5a:27:2f:0f:03:4b:ea:bd:2b:bb:
+        b5:1e:51:5b:2f:7f:67:15:88:4a:e0:38:53:50:91:8c:4f:fb:
+        38:bd:52:43:37:19:3f:5b:c0:db:ed:68:90:a7:6e:28:82:2b:
+        6a:a3:08:01:23:4b:1b:3e:b0:4e:02:a6:9b:6f:f4:57:c9:41:
+        7d:66:d9:00:c1:8d:1c:73:96:01:61:b6:92:2b:ac:e8:42:8f:
+        79:29
+-----BEGIN CERTIFICATE-----
+MIIDJTCCAo6gAwIBAgIBFzANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEMMAoGA1UEAxMDdGE0MRIwEAYJKoZIhvcNAQkBFgN0YTQwHhcNMTAw
+ODA0MjA1OTI4WhcNMTMwNDMwMjA1OTI4WjB2MQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UEChMEcGtn
+NTETMBEGA1UEAxQKcHViQ0ExX3RhNDEZMBcGCSqGSIb3DQEJARYKcHViQ0ExX3Rh
+NDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtPSxn0mXkhip+pQ3+UVfMcQt
+9hn+mqxNu9p9mQzh8LIPm7jFulj4PlJ9gxfCevmu9iZ1nxeaigugLDjU/KwCfxsu
+yZLaeSEQW3xWPN5+ZFJzQlwbRJSLFt6r67NtikERx34Gk/qmmwAd7NTNB2lGS35g
+f0uT9o3FB/4LRKg826UCAwEAAaOB0DCBzTAdBgNVHQ4EFgQU7o14UxH+B8vIVUvv
+pi/hg3K7uiEwgZoGA1UdIwSBkjCBj4AU/hRT75wLq+2WInARwuZ9LkC3f7WhbKRq
+MGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpN
+ZW5sbyBQYXJrMQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTQxEjAQBgkqhkiG
+9w0BCQEWA3RhNIIJAMDId7RMSU+rMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN
+AQELBQADgYEAXCzyfI1yqtHiIKLGdoREuW5ULDmVmalQuxy5no4EkrW2lReSqAsJ
+PvVaEJlaJy8PA0vqvSu7tR5RWy9/ZxWISuA4U1CRjE/7OL1SQzcZP1vA2+1okKdu
+KIIraqMIASNLGz6wTgKmm2/0V8lBfWbZAMGNHHOWAWG2kius6EKPeSk=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/publisher_cas/1B.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,67 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 27 (0x1b)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta5/emailAddress=ta5
+        Validity
+            Not Before: Aug  4 20:59:29 2010 GMT
+            Not After : Apr 30 20:59:29 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta5/emailAddress=pubCA1_ta5
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:f1:eb:41:9f:0b:f5:8c:66:1f:8c:5d:e0:9a:a6:
+                    d3:3c:a6:af:66:36:e2:5c:8b:c4:a7:ff:fb:6f:f0:
+                    65:33:b2:a2:f2:8a:1c:94:ad:de:96:d7:7a:75:78:
+                    e1:5f:a8:c9:51:08:ff:38:df:2e:cf:37:b2:a8:e4:
+                    82:60:55:d5:40:bc:a0:b3:94:a4:59:51:ad:d8:26:
+                    64:ce:d5:54:10:5a:78:52:f1:f8:bc:d6:dc:a7:40:
+                    57:82:4f:2f:09:16:de:5b:88:42:aa:67:3e:1f:8b:
+                    b7:6e:a9:1e:6a:12:a8:35:9f:28:85:23:29:3a:20:
+                    0e:cd:89:3e:73:40:e8:d6:1b
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                B7:AD:D9:89:4D:93:68:D0:D6:CB:4B:DB:6D:D6:CB:03:74:85:4B:AC
+            X509v3 Authority Key Identifier: 
+                keyid:AA:44:3A:A2:05:A2:04:EB:62:E0:E5:F5:2C:44:CA:3B:CF:4D:B2:74
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta5/emailAddress=ta5
+                serial:CB:2A:36:97:17:4F:60:24
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 CRL Distribution Points: 
+                URI:http://localhost:12001/file/0/ta5_crl.pem
+
+    Signature Algorithm: sha256WithRSAEncryption
+        93:e0:33:e4:90:54:94:6c:cb:82:8d:18:16:ef:e5:b4:80:16:
+        21:f9:f0:6e:5f:63:36:76:c1:c0:37:13:ca:df:e2:6d:f4:30:
+        5c:10:5c:86:fb:7b:dc:6f:7f:be:d5:ed:9b:65:fc:14:d2:f3:
+        8c:df:21:db:65:88:60:7b:fc:3c:6f:c8:6b:fe:5d:c7:7e:b4:
+        c7:75:54:89:0d:01:4a:0d:1a:f1:f2:5c:65:c7:12:16:98:dd:
+        f7:89:42:6a:85:a4:a6:3c:19:22:bb:99:b6:7e:d2:2a:c7:80:
+        67:6b:0f:ce:f0:c9:1b:a5:5d:39:f4:f2:f0:eb:48:ea:c0:89:
+        b0:df
+-----BEGIN CERTIFICATE-----
+MIIDYzCCAsygAwIBAgIBGzANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEMMAoGA1UEAxMDdGE1MRIwEAYJKoZIhvcNAQkBFgN0YTUwHhcNMTAw
+ODA0MjA1OTI5WhcNMTMwNDMwMjA1OTI5WjB2MQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UEChMEcGtn
+NTETMBEGA1UEAxQKcHViQ0ExX3RhNTEZMBcGCSqGSIb3DQEJARYKcHViQ0ExX3Rh
+NTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA8etBnwv1jGYfjF3gmqbTPKav
+ZjbiXIvEp//7b/BlM7Ki8ooclK3eltd6dXjhX6jJUQj/ON8uzzeyqOSCYFXVQLyg
+s5SkWVGt2CZkztVUEFp4UvH4vNbcp0BXgk8vCRbeW4hCqmc+H4u3bqkeahKoNZ8o
+hSMpOiAOzYk+c0Do1hsCAwEAAaOCAQ0wggEJMB0GA1UdDgQWBBS3rdmJTZNo0NbL
+S9tt1ssDdIVLrDCBmgYDVR0jBIGSMIGPgBSqRDqiBaIE62Lg5fUsRMo7z02ydKFs
+pGowaDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEzARBgNVBAcT
+Ck1lbmxvIFBhcmsxDTALBgNVBAoTBHBrZzUxDDAKBgNVBAMTA3RhNTESMBAGCSqG
+SIb3DQEJARYDdGE1ggkAyyo2lxdPYCQwDwYDVR0TAQH/BAUwAwEB/zA6BgNVHR8E
+MzAxMC+gLaArhilodHRwOi8vbG9jYWxob3N0OjEyMDAxL2ZpbGUvMC90YTVfY3Js
+LnBlbTANBgkqhkiG9w0BAQsFAAOBgQCT4DPkkFSUbMuCjRgW7+W0gBYh+fBuX2M2
+dsHANxPK3+Jt9DBcEFyG+3vcb3++1e2bZfwU0vOM3yHbZYhge/w8b8hr/l3HfrTH
+dVSJDQFKDRrx8lxlxxIWmN33iUJqhaSmPBkiu5m2ftIqx4Bnaw/O8MkbpV059PLw
+60jqwImw3w==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/publisher_cas/pubCA1_ta1_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,62 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 3 (0x3)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=i2_ta1/emailAddress=i2_ta1
+        Validity
+            Not Before: Aug  4 20:59:23 2010 GMT
+            Not After : Apr 30 20:59:23 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta1/emailAddress=pubCA1_ta1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:aa:b0:34:d1:f2:16:6f:f7:d5:33:8d:45:66:2c:
+                    be:01:ec:68:c9:31:ca:ee:7f:93:fc:d6:17:13:e0:
+                    ba:fb:29:e1:70:3b:12:15:3a:b2:42:96:8b:25:d1:
+                    f3:59:64:58:fa:ad:8d:26:3b:cf:4b:88:e1:32:6f:
+                    2e:e3:69:d3:4a:4d:7e:c8:f9:5c:7a:40:a9:14:ba:
+                    0e:3e:a7:f1:d9:7f:a7:3f:de:2d:96:83:52:d7:1f:
+                    eb:ff:e9:08:66:35:d8:38:8a:15:b7:0e:5e:a5:e2:
+                    4d:e3:74:b6:1e:14:05:78:67:ed:fb:82:cc:55:c5:
+                    03:df:64:8f:09:d0:3b:c5:d3
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                E8:81:62:06:D5:A6:C6:2E:6C:2A:4F:A3:21:42:59:CD:19:5B:32:ED
+            X509v3 Authority Key Identifier: 
+                keyid:E3:6D:6B:62:16:42:41:2B:9C:3B:68:01:F3:EF:16:3C:31:83:05:41
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=i1_ta1/emailAddress=i1_ta1
+                serial:02
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        72:ed:f0:65:97:65:56:53:3c:c8:78:ae:a1:22:70:c3:a0:1d:
+        db:42:3b:75:43:c9:b1:98:7d:7c:c4:c0:41:07:b4:18:72:26:
+        34:98:35:c1:20:17:1c:dc:53:59:a6:d9:42:01:f3:0d:9b:16:
+        f9:15:73:3f:1f:49:71:06:f0:0c:b0:49:d2:2c:89:f7:42:7f:
+        b5:37:55:fb:49:2e:2b:8e:c1:70:e3:84:96:13:ab:63:f9:70:
+        11:89:86:b7:e9:db:1e:56:dc:9a:78:3b:ad:47:30:5f:98:28:
+        8c:ea:f2:8f:af:40:b8:93:73:72:b0:be:e0:52:72:69:e8:ee:
+        52:4d
+-----BEGIN CERTIFICATE-----
+MIIDKTCCApKgAwIBAgIBAzANBgkqhkiG9w0BAQsFADBuMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEPMA0GA1UEAxQGaTJfdGExMRUwEwYJKoZIhvcNAQkBFgZpMl90YTEw
+HhcNMTAwODA0MjA1OTIzWhcNMTMwNDMwMjA1OTIzWjB2MQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTETMBEGA1UEAxQKcHViQ0ExX3RhMTEZMBcGCSqGSIb3DQEJARYKcHVi
+Q0ExX3RhMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqrA00fIWb/fVM41F
+Ziy+AexoyTHK7n+T/NYXE+C6+ynhcDsSFTqyQpaLJdHzWWRY+q2NJjvPS4jhMm8u
+42nTSk1+yPlcekCpFLoOPqfx2X+nP94tloNS1x/r/+kIZjXYOIoVtw5epeJN43S2
+HhQFeGft+4LMVcUD32SPCdA7xdMCAwEAAaOBzjCByzAdBgNVHQ4EFgQU6IFiBtWm
+xi5sKk+jIUJZzRlbMu0wgZgGA1UdIwSBkDCBjYAU421rYhZCQSucO2gB8+8WPDGD
+BUGhcqRwMG4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYD
+VQQHEwpNZW5sbyBQYXJrMQ0wCwYDVQQKEwRwa2c1MQ8wDQYDVQQDFAZpMV90YTEx
+FTATBgkqhkiG9w0BCQEWBmkxX3RhMYIBAjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
+SIb3DQEBCwUAA4GBAHLt8GWXZVZTPMh4rqEicMOgHdtCO3VDybGYfXzEwEEHtBhy
+JjSYNcEgFxzcU1mm2UIB8w2bFvkVcz8fSXEG8AywSdIsifdCf7U3VftJLiuOwXDj
+hJYTq2P5cBGJhrfp2x5W3Jp4O61HMF+YKIzq8o+vQLiTc3KwvuBScmno7lJN
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/publisher_cas/pubCA1_ta3_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,62 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 12 (0xc)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta3/emailAddress=ta3
+        Validity
+            Not Before: Aug  4 20:59:25 2010 GMT
+            Not After : Apr 30 20:59:25 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta3/emailAddress=pubCA1_ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:bd:ef:e1:5e:a1:32:ff:ee:9b:64:1a:a3:f0:e2:
+                    63:64:ab:7d:60:5e:32:60:36:f5:67:54:d0:e0:13:
+                    6e:ef:88:c1:ff:0e:64:d2:f4:cc:07:fd:18:03:90:
+                    fb:73:b7:91:c9:9e:97:b2:b0:0a:ae:9f:88:dc:29:
+                    fd:2c:19:09:43:ef:68:7c:ab:de:91:de:51:cb:e2:
+                    35:fc:96:fe:13:e9:3c:ea:97:3c:2a:ef:92:9a:31:
+                    77:e4:a2:24:40:01:6e:a0:59:ef:7e:71:d9:be:5a:
+                    3f:ed:7e:b6:d5:7b:38:6d:4c:16:f8:fd:ec:fb:6f:
+                    8c:41:fb:fd:dc:0c:54:1c:db
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                47:D6:CB:F2:38:3E:A8:40:85:4A:BE:EF:F8:85:B3:49:FF:D0:8F:16
+            X509v3 Authority Key Identifier: 
+                keyid:E0:CE:66:66:57:70:37:16:AF:EB:65:B6:15:DC:2D:2C:B7:B4:49:4D
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta3/emailAddress=ta3
+                serial:E1:F8:52:2F:AC:F4:00:EE
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        6a:25:8d:33:01:c1:a0:fe:99:5f:f0:b4:8a:39:86:55:f5:6c:
+        59:2a:84:a5:01:10:dd:1a:b6:a2:52:17:62:e1:e5:d5:8a:e9:
+        09:bd:04:95:b1:a4:b3:ec:9b:73:f3:54:12:26:97:a5:1e:52:
+        9e:bf:93:c7:4d:dd:a3:c4:ec:0b:46:3e:e4:b7:c3:47:17:68:
+        15:df:a1:1a:67:c0:8b:f6:a8:ea:ab:81:6a:fc:a3:4c:5b:0e:
+        ca:cc:b7:bf:e5:35:73:e9:95:d0:ad:8c:fc:2a:7d:2c:ee:6b:
+        09:53:2f:f3:9b:57:fa:32:bb:02:f9:10:fa:30:a2:e3:55:0c:
+        4a:73
+-----BEGIN CERTIFICATE-----
+MIIDJTCCAo6gAwIBAgIBDDANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEMMAoGA1UEAxMDdGEzMRIwEAYJKoZIhvcNAQkBFgN0YTMwHhcNMTAw
+ODA0MjA1OTI1WhcNMTMwNDMwMjA1OTI1WjB2MQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UEChMEcGtn
+NTETMBEGA1UEAxQKcHViQ0ExX3RhMzEZMBcGCSqGSIb3DQEJARYKcHViQ0ExX3Rh
+MzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAve/hXqEy/+6bZBqj8OJjZKt9
+YF4yYDb1Z1TQ4BNu74jB/w5k0vTMB/0YA5D7c7eRyZ6XsrAKrp+I3Cn9LBkJQ+9o
+fKvekd5Ry+I1/Jb+E+k86pc8Ku+SmjF35KIkQAFuoFnvfnHZvlo/7X621Xs4bUwW
++P3s+2+MQfv93AxUHNsCAwEAAaOB0DCBzTAdBgNVHQ4EFgQUR9bL8jg+qECFSr7v
++IWzSf/QjxYwgZoGA1UdIwSBkjCBj4AU4M5mZldwNxav62W2FdwtLLe0SU2hbKRq
+MGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpN
+ZW5sbyBQYXJrMQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTMxEjAQBgkqhkiG
+9w0BCQEWA3RhM4IJAOH4Ui+s9ADuMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN
+AQELBQADgYEAaiWNMwHBoP6ZX/C0ijmGVfVsWSqEpQEQ3Rq2olIXYuHl1YrpCb0E
+lbGks+ybc/NUEiaXpR5Snr+Tx03do8TsC0Y+5LfDRxdoFd+hGmfAi/ao6quBavyj
+TFsOysy3v+U1c+mV0K2M/Cp9LO5rCVMv85tX+jK7AvkQ+jCi41UMSnM=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/publisher_cas/pubCA1_ta4_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,62 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 23 (0x17)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta4/emailAddress=ta4
+        Validity
+            Not Before: Aug  4 20:59:28 2010 GMT
+            Not After : Apr 30 20:59:28 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta4/emailAddress=pubCA1_ta4
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:b4:f4:b1:9f:49:97:92:18:a9:fa:94:37:f9:45:
+                    5f:31:c4:2d:f6:19:fe:9a:ac:4d:bb:da:7d:99:0c:
+                    e1:f0:b2:0f:9b:b8:c5:ba:58:f8:3e:52:7d:83:17:
+                    c2:7a:f9:ae:f6:26:75:9f:17:9a:8a:0b:a0:2c:38:
+                    d4:fc:ac:02:7f:1b:2e:c9:92:da:79:21:10:5b:7c:
+                    56:3c:de:7e:64:52:73:42:5c:1b:44:94:8b:16:de:
+                    ab:eb:b3:6d:8a:41:11:c7:7e:06:93:fa:a6:9b:00:
+                    1d:ec:d4:cd:07:69:46:4b:7e:60:7f:4b:93:f6:8d:
+                    c5:07:fe:0b:44:a8:3c:db:a5
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                EE:8D:78:53:11:FE:07:CB:C8:55:4B:EF:A6:2F:E1:83:72:BB:BA:21
+            X509v3 Authority Key Identifier: 
+                keyid:FE:14:53:EF:9C:0B:AB:ED:96:22:70:11:C2:E6:7D:2E:40:B7:7F:B5
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta4/emailAddress=ta4
+                serial:C0:C8:77:B4:4C:49:4F:AB
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        5c:2c:f2:7c:8d:72:aa:d1:e2:20:a2:c6:76:84:44:b9:6e:54:
+        2c:39:95:99:a9:50:bb:1c:b9:9e:8e:04:92:b5:b6:95:17:92:
+        a8:0b:09:3e:f5:5a:10:99:5a:27:2f:0f:03:4b:ea:bd:2b:bb:
+        b5:1e:51:5b:2f:7f:67:15:88:4a:e0:38:53:50:91:8c:4f:fb:
+        38:bd:52:43:37:19:3f:5b:c0:db:ed:68:90:a7:6e:28:82:2b:
+        6a:a3:08:01:23:4b:1b:3e:b0:4e:02:a6:9b:6f:f4:57:c9:41:
+        7d:66:d9:00:c1:8d:1c:73:96:01:61:b6:92:2b:ac:e8:42:8f:
+        79:29
+-----BEGIN CERTIFICATE-----
+MIIDJTCCAo6gAwIBAgIBFzANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEMMAoGA1UEAxMDdGE0MRIwEAYJKoZIhvcNAQkBFgN0YTQwHhcNMTAw
+ODA0MjA1OTI4WhcNMTMwNDMwMjA1OTI4WjB2MQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UEChMEcGtn
+NTETMBEGA1UEAxQKcHViQ0ExX3RhNDEZMBcGCSqGSIb3DQEJARYKcHViQ0ExX3Rh
+NDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtPSxn0mXkhip+pQ3+UVfMcQt
+9hn+mqxNu9p9mQzh8LIPm7jFulj4PlJ9gxfCevmu9iZ1nxeaigugLDjU/KwCfxsu
+yZLaeSEQW3xWPN5+ZFJzQlwbRJSLFt6r67NtikERx34Gk/qmmwAd7NTNB2lGS35g
+f0uT9o3FB/4LRKg826UCAwEAAaOB0DCBzTAdBgNVHQ4EFgQU7o14UxH+B8vIVUvv
+pi/hg3K7uiEwgZoGA1UdIwSBkjCBj4AU/hRT75wLq+2WInARwuZ9LkC3f7WhbKRq
+MGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpN
+ZW5sbyBQYXJrMQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTQxEjAQBgkqhkiG
+9w0BCQEWA3RhNIIJAMDId7RMSU+rMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN
+AQELBQADgYEAXCzyfI1yqtHiIKLGdoREuW5ULDmVmalQuxy5no4EkrW2lReSqAsJ
+PvVaEJlaJy8PA0vqvSu7tR5RWy9/ZxWISuA4U1CRjE/7OL1SQzcZP1vA2+1okKdu
+KIIraqMIASNLGz6wTgKmm2/0V8lBfWbZAMGNHHOWAWG2kius6EKPeSk=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/publisher_cas/pubCA1_ta5_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,67 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 27 (0x1b)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta5/emailAddress=ta5
+        Validity
+            Not Before: Aug  4 20:59:29 2010 GMT
+            Not After : Apr 30 20:59:29 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA1_ta5/emailAddress=pubCA1_ta5
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:f1:eb:41:9f:0b:f5:8c:66:1f:8c:5d:e0:9a:a6:
+                    d3:3c:a6:af:66:36:e2:5c:8b:c4:a7:ff:fb:6f:f0:
+                    65:33:b2:a2:f2:8a:1c:94:ad:de:96:d7:7a:75:78:
+                    e1:5f:a8:c9:51:08:ff:38:df:2e:cf:37:b2:a8:e4:
+                    82:60:55:d5:40:bc:a0:b3:94:a4:59:51:ad:d8:26:
+                    64:ce:d5:54:10:5a:78:52:f1:f8:bc:d6:dc:a7:40:
+                    57:82:4f:2f:09:16:de:5b:88:42:aa:67:3e:1f:8b:
+                    b7:6e:a9:1e:6a:12:a8:35:9f:28:85:23:29:3a:20:
+                    0e:cd:89:3e:73:40:e8:d6:1b
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                B7:AD:D9:89:4D:93:68:D0:D6:CB:4B:DB:6D:D6:CB:03:74:85:4B:AC
+            X509v3 Authority Key Identifier: 
+                keyid:AA:44:3A:A2:05:A2:04:EB:62:E0:E5:F5:2C:44:CA:3B:CF:4D:B2:74
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta5/emailAddress=ta5
+                serial:CB:2A:36:97:17:4F:60:24
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 CRL Distribution Points: 
+                URI:http://localhost:12001/file/0/ta5_crl.pem
+
+    Signature Algorithm: sha256WithRSAEncryption
+        93:e0:33:e4:90:54:94:6c:cb:82:8d:18:16:ef:e5:b4:80:16:
+        21:f9:f0:6e:5f:63:36:76:c1:c0:37:13:ca:df:e2:6d:f4:30:
+        5c:10:5c:86:fb:7b:dc:6f:7f:be:d5:ed:9b:65:fc:14:d2:f3:
+        8c:df:21:db:65:88:60:7b:fc:3c:6f:c8:6b:fe:5d:c7:7e:b4:
+        c7:75:54:89:0d:01:4a:0d:1a:f1:f2:5c:65:c7:12:16:98:dd:
+        f7:89:42:6a:85:a4:a6:3c:19:22:bb:99:b6:7e:d2:2a:c7:80:
+        67:6b:0f:ce:f0:c9:1b:a5:5d:39:f4:f2:f0:eb:48:ea:c0:89:
+        b0:df
+-----BEGIN CERTIFICATE-----
+MIIDYzCCAsygAwIBAgIBGzANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEMMAoGA1UEAxMDdGE1MRIwEAYJKoZIhvcNAQkBFgN0YTUwHhcNMTAw
+ODA0MjA1OTI5WhcNMTMwNDMwMjA1OTI5WjB2MQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UEChMEcGtn
+NTETMBEGA1UEAxQKcHViQ0ExX3RhNTEZMBcGCSqGSIb3DQEJARYKcHViQ0ExX3Rh
+NTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA8etBnwv1jGYfjF3gmqbTPKav
+ZjbiXIvEp//7b/BlM7Ki8ooclK3eltd6dXjhX6jJUQj/ON8uzzeyqOSCYFXVQLyg
+s5SkWVGt2CZkztVUEFp4UvH4vNbcp0BXgk8vCRbeW4hCqmc+H4u3bqkeahKoNZ8o
+hSMpOiAOzYk+c0Do1hsCAwEAAaOCAQ0wggEJMB0GA1UdDgQWBBS3rdmJTZNo0NbL
+S9tt1ssDdIVLrDCBmgYDVR0jBIGSMIGPgBSqRDqiBaIE62Lg5fUsRMo7z02ydKFs
+pGowaDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEzARBgNVBAcT
+Ck1lbmxvIFBhcmsxDTALBgNVBAoTBHBrZzUxDDAKBgNVBAMTA3RhNTESMBAGCSqG
+SIb3DQEJARYDdGE1ggkAyyo2lxdPYCQwDwYDVR0TAQH/BAUwAwEB/zA6BgNVHR8E
+MzAxMC+gLaArhilodHRwOi8vbG9jYWxob3N0OjEyMDAxL2ZpbGUvMC90YTVfY3Js
+LnBlbTANBgkqhkiG9w0BAQsFAAOBgQCT4DPkkFSUbMuCjRgW7+W0gBYh+fBuX2M2
+dsHANxPK3+Jt9DBcEFyG+3vcb3++1e2bZfwU0vOM3yHbZYhge/w8b8hr/l3HfrTH
+dVSJDQFKDRrx8lxlxxIWmN33iUJqhaSmPBkiu5m2ftIqx4Bnaw/O8MkbpV059PLw
+60jqwImw3w==
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/publisher_cas/pubCA2_ta3_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,55 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 17 (0x11)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta3/emailAddress=ta3
+        Validity
+            Not Before: Aug  4 20:59:27 2010 GMT
+            Not After : Apr 30 20:59:27 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA2_ta3/emailAddress=pubCA2_ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:91:27:b7:93:9d:5d:e5:9e:e9:5d:78:e2:1d:ff:
+                    73:0e:d7:a7:4e:a3:bf:e3:ff:33:08:c9:a9:e4:6f:
+                    bc:a5:b9:33:32:29:8f:da:d1:63:51:0c:3b:da:84:
+                    32:bb:74:28:70:d3:07:3b:3d:ac:2f:7d:c2:9e:4a:
+                    4e:7c:34:37:e6:1d:76:aa:44:a0:56:c9:83:83:13:
+                    7e:67:91:99:af:5d:5a:36:5d:a6:20:23:4a:f5:a8:
+                    08:12:5e:49:52:4b:ae:d3:e6:b4:63:f8:2e:1d:80:
+                    5f:bd:1f:58:75:34:92:ce:be:6a:3b:f8:25:fd:64:
+                    49:b6:fe:6b:03:dc:0c:9e:4f
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 Issuer Alternative Name: critical
+                <EMPTY>
+
+    Signature Algorithm: sha256WithRSAEncryption
+        07:01:15:2c:e6:eb:e6:8a:b4:dc:6c:fa:f5:30:2d:32:e1:6f:
+        27:76:6d:1e:c8:4b:e1:ae:f8:96:fb:15:0e:0e:8f:e7:fe:43:
+        d3:af:f7:b3:f8:19:e0:77:38:43:d3:6b:86:6b:f1:b6:36:b5:
+        34:66:49:ad:c0:58:7a:40:18:da:48:af:b4:b3:24:43:92:06:
+        df:84:c2:ac:ea:c1:0d:8a:82:86:39:ce:44:1e:72:f2:46:0e:
+        c4:cf:70:78:86:a9:8f:35:83:5f:74:e1:30:a3:90:29:f2:f2:
+        5f:d1:d3:84:84:4d:1d:08:ea:05:24:2d:d0:ae:3d:0f:78:7c:
+        c7:10
+-----BEGIN CERTIFICATE-----
+MIICdTCCAd6gAwIBAgIBETANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEMMAoGA1UEAxMDdGEzMRIwEAYJKoZIhvcNAQkBFgN0YTMwHhcNMTAw
+ODA0MjA1OTI3WhcNMTMwNDMwMjA1OTI3WjB2MQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UEChMEcGtn
+NTETMBEGA1UEAxQKcHViQ0EyX3RhMzEZMBcGCSqGSIb3DQEJARYKcHViQ0EyX3Rh
+MzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAkSe3k51d5Z7pXXjiHf9zDten
+TqO/4/8zCMmp5G+8pbkzMimP2tFjUQw72oQyu3QocNMHOz2sL33CnkpOfDQ35h12
+qkSgVsmDgxN+Z5GZr11aNl2mICNK9agIEl5JUkuu0+a0Y/guHYBfvR9YdTSSzr5q
+O/gl/WRJtv5rA9wMnk8CAwEAAaMhMB8wDwYDVR0TAQH/BAUwAwEB/zAMBgNVHRIB
+Af8EAjAAMA0GCSqGSIb3DQEBCwUAA4GBAAcBFSzm6+aKtNxs+vUwLTLhbyd2bR7I
+S+Gu+Jb7FQ4Oj+f+Q9Ov97P4GeB3OEPTa4Zr8bY2tTRmSa3AWHpAGNpIr7SzJEOS
+Bt+EwqzqwQ2KgoY5zkQecvJGDsTPcHiGqY81g1904TCjkCny8l/R04SETR0I6gUk
+LdCuPQ94fMcQ
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/publisher_cas/pubCA3_ta3_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,62 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 19 (0x13)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta3/emailAddress=ta3
+        Validity
+            Not Before: Jan  1 01:01:01 2009 GMT
+            Not After : Jan  2 01:01:01 2009 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA3_ta3/emailAddress=pubCA3_ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:95:a3:85:b5:71:f3:2f:b2:aa:c2:33:ff:4c:70:
+                    40:e1:06:44:e8:7c:0f:78:77:21:1d:a6:8a:e7:0c:
+                    e7:65:12:f5:cc:99:cf:4a:00:bd:5e:ea:4d:c7:a3:
+                    85:93:0c:4c:4a:17:44:49:d9:b9:06:45:b4:99:d0:
+                    95:08:aa:f6:c4:07:75:46:a7:26:3a:e5:01:64:26:
+                    74:c7:58:73:e9:70:4f:97:15:4e:30:bd:55:8e:cb:
+                    43:33:36:8a:f9:cc:57:e6:ee:2a:1b:aa:0e:67:51:
+                    c5:52:61:ab:43:5b:f2:d7:2c:20:5c:c1:72:a4:3a:
+                    bb:b0:a2:3b:b4:6e:e3:b9:df
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                E9:26:60:80:D1:41:FF:4A:A4:0C:14:05:C0:6B:5D:84:C5:F0:15:04
+            X509v3 Authority Key Identifier: 
+                keyid:E0:CE:66:66:57:70:37:16:AF:EB:65:B6:15:DC:2D:2C:B7:B4:49:4D
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta3/emailAddress=ta3
+                serial:E1:F8:52:2F:AC:F4:00:EE
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        7f:d0:e5:cc:61:28:7a:14:1f:6e:43:f2:1f:98:55:8f:3f:9b:
+        f4:8c:1d:2d:4d:c4:c5:08:2f:eb:1a:6d:1d:99:80:57:3b:45:
+        d3:4f:71:6f:61:ca:17:83:9f:23:5f:0a:77:7b:25:b2:53:2b:
+        ca:e3:3d:ad:28:57:99:b9:3a:d8:f8:d2:3f:55:d8:f4:ef:94:
+        81:36:58:4f:98:a0:2b:6b:8d:77:cb:3d:bd:32:9a:5e:dd:1e:
+        7f:4f:02:fe:de:35:a8:f0:85:3a:eb:a9:22:5a:dd:9d:ba:dc:
+        40:b7:9f:ba:54:f8:84:7d:39:42:ec:87:73:85:11:1d:36:41:
+        9f:e7
+-----BEGIN CERTIFICATE-----
+MIIDJTCCAo6gAwIBAgIBEzANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEMMAoGA1UEAxMDdGEzMRIwEAYJKoZIhvcNAQkBFgN0YTMwHhcNMDkw
+MTAxMDEwMTAxWhcNMDkwMTAyMDEwMTAxWjB2MQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UEChMEcGtn
+NTETMBEGA1UEAxQKcHViQ0EzX3RhMzEZMBcGCSqGSIb3DQEJARYKcHViQ0EzX3Rh
+MzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAlaOFtXHzL7KqwjP/THBA4QZE
+6HwPeHchHaaK5wznZRL1zJnPSgC9XupNx6OFkwxMShdESdm5BkW0mdCVCKr2xAd1
+RqcmOuUBZCZ0x1hz6XBPlxVOML1VjstDMzaK+cxX5u4qG6oOZ1HFUmGrQ1vy1ywg
+XMFypDq7sKI7tG7jud8CAwEAAaOB0DCBzTAdBgNVHQ4EFgQU6SZggNFB/0qkDBQF
+wGtdhMXwFQQwgZoGA1UdIwSBkjCBj4AU4M5mZldwNxav62W2FdwtLLe0SU2hbKRq
+MGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpN
+ZW5sbyBQYXJrMQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTMxEjAQBgkqhkiG
+9w0BCQEWA3RhM4IJAOH4Ui+s9ADuMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN
+AQELBQADgYEAf9DlzGEoehQfbkPyH5hVjz+b9IwdLU3ExQgv6xptHZmAVztF009x
+b2HKF4OfI18Kd3slslMryuM9rShXmbk62PjSP1XY9O+UgTZYT5igK2uNd8s9vTKa
+Xt0ef08C/t41qPCFOuupIlrdnbrcQLefulT4hH05QuyHc4URHTZBn+c=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/publisher_cas/pubCA4_ta3_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,62 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 21 (0x15)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta3/emailAddress=ta3
+        Validity
+            Not Before: Jan  1 01:01:01 2035 GMT
+            Not After : Jan  2 01:01:01 2035 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=pubCA4_ta3/emailAddress=pubCA4_ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:b2:8a:7a:22:17:a3:be:ff:35:73:f1:13:34:e2:
+                    c1:02:e3:1e:a6:d8:bc:c2:29:a6:9d:e1:96:0b:2b:
+                    38:42:db:f4:9f:f8:05:c0:d9:81:ab:37:35:da:24:
+                    1b:e5:95:6b:c5:da:e8:c1:14:c3:c7:3e:a4:20:ce:
+                    25:75:5f:13:d4:94:4d:7c:69:42:82:ef:09:c9:b1:
+                    11:dd:a0:d9:e2:76:47:fd:68:e7:ec:11:02:f7:a6:
+                    92:da:50:b8:9d:e8:90:9d:f7:e2:d6:cd:35:7e:1c:
+                    f6:31:71:39:fe:1a:5d:49:cc:50:c7:34:fd:cb:e1:
+                    85:3a:e4:a6:15:9a:7f:6b:c5
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                A5:56:E6:44:AE:89:5C:8E:24:C2:58:B6:C6:D1:7B:51:BC:F4:7A:83
+            X509v3 Authority Key Identifier: 
+                keyid:E0:CE:66:66:57:70:37:16:AF:EB:65:B6:15:DC:2D:2C:B7:B4:49:4D
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta3/emailAddress=ta3
+                serial:E1:F8:52:2F:AC:F4:00:EE
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        65:98:33:cd:b4:af:b0:67:bf:0e:8e:0e:d6:8c:fd:a6:7c:18:
+        88:a7:2a:ac:55:5d:b3:95:f3:8f:5f:d7:00:78:cc:fd:00:6a:
+        0c:75:12:00:7b:88:f4:93:66:00:be:c7:ce:d7:75:72:0e:44:
+        3e:fc:b2:ff:d1:23:72:9c:be:a7:a7:70:d9:af:0d:e5:84:43:
+        77:6e:73:60:ff:40:f0:f6:94:17:8e:4e:57:0d:d6:35:4f:5b:
+        46:d6:36:6e:3a:03:e6:13:b9:4c:c9:fd:75:c7:e6:4f:f3:75:
+        bc:2a:38:dd:7c:9b:3c:5a:75:27:c9:00:5d:11:11:b6:4e:e9:
+        97:b9
+-----BEGIN CERTIFICATE-----
+MIIDJTCCAo6gAwIBAgIBFTANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UE
+ChMEcGtnNTEMMAoGA1UEAxMDdGEzMRIwEAYJKoZIhvcNAQkBFgN0YTMwHhcNMzUw
+MTAxMDEwMTAxWhcNMzUwMTAyMDEwMTAxWjB2MQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTETMBEGA1UEBxMKTWVubG8gUGFyazENMAsGA1UEChMEcGtn
+NTETMBEGA1UEAxQKcHViQ0E0X3RhMzEZMBcGCSqGSIb3DQEJARYKcHViQ0E0X3Rh
+MzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsop6Ihejvv81c/ETNOLBAuMe
+pti8wimmneGWCys4Qtv0n/gFwNmBqzc12iQb5ZVrxdrowRTDxz6kIM4ldV8T1JRN
+fGlCgu8JybER3aDZ4nZH/Wjn7BEC96aS2lC4neiQnffi1s01fhz2MXE5/hpdScxQ
+xzT9y+GFOuSmFZp/a8UCAwEAAaOB0DCBzTAdBgNVHQ4EFgQUpVbmRK6JXI4kwli2
+xtF7Ubz0eoMwgZoGA1UdIwSBkjCBj4AU4M5mZldwNxav62W2FdwtLLe0SU2hbKRq
+MGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpN
+ZW5sbyBQYXJrMQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTMxEjAQBgkqhkiG
+9w0BCQEWA3RhM4IJAOH4Ui+s9ADuMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN
+AQELBQADgYEAZZgzzbSvsGe/Do4O1oz9pnwYiKcqrFVds5Xzj1/XAHjM/QBqDHUS
+AHuI9JNmAL7Hztd1cg5EPvyy/9Ejcpy+p6dw2a8N5YRDd25zYP9A8PaUF45OVw3W
+NU9bRtY2bjoD5hO5TMn9dcfmT/N1vCo43XybPFp1J8kAXRERtk7pl7k=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/serial	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,1 @@
+1D
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/ta1/ta1_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,63 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            cb:cf:1d:cd:f3:a6:cd:09
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta1/emailAddress=ta1
+        Validity
+            Not Before: Aug  4 20:59:22 2010 GMT
+            Not After : Apr 30 20:59:22 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta1/emailAddress=ta1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:a7:64:67:53:f2:9a:c9:ce:a9:4a:92:16:57:61:
+                    c3:af:9d:0e:9f:61:82:ad:cf:7f:aa:59:f2:fa:06:
+                    3d:a2:ad:4f:db:90:3e:48:3e:00:d4:eb:96:c2:19:
+                    b3:e0:6a:f2:21:61:83:92:dd:86:50:ff:c6:3f:de:
+                    22:9c:1c:74:cb:09:06:e7:78:c2:8c:f8:98:2e:b5:
+                    e4:c2:f4:bf:b7:92:46:af:c7:d6:6c:59:07:d9:8c:
+                    06:96:1b:ef:10:dc:3e:f8:8b:08:9d:bd:81:3c:0d:
+                    a3:e9:55:5f:1b:04:39:b9:7f:f4:cf:d6:f9:a2:31:
+                    3a:83:96:21:92:a7:13:c4:4d
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                BB:C9:C7:62:4B:87:B7:6A:32:3F:A5:51:7B:C1:3A:8E:3F:06:5C:F7
+            X509v3 Authority Key Identifier: 
+                keyid:BB:C9:C7:62:4B:87:B7:6A:32:3F:A5:51:7B:C1:3A:8E:3F:06:5C:F7
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta1/emailAddress=ta1
+                serial:CB:CF:1D:CD:F3:A6:CD:09
+
+            X509v3 Basic Constraints: 
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        07:cb:90:df:b3:18:22:61:79:1d:39:67:ee:3d:94:a8:7b:e1:
+        64:52:41:4a:1f:6e:14:34:b9:27:aa:05:77:f9:38:0c:66:20:
+        cf:92:0e:4e:94:bf:62:f1:2d:08:1c:ca:3e:77:5a:07:e9:35:
+        bb:a7:ca:31:8a:44:10:a9:56:f4:96:81:84:52:2c:36:45:ea:
+        72:46:6c:4a:ca:05:8c:79:d1:03:93:84:96:e4:fa:7b:5d:59:
+        21:9f:87:4d:ab:f1:64:e0:92:14:59:c6:c4:d8:3c:33:64:58:
+        98:96:83:f1:a6:26:fd:54:57:d7:f9:71:3c:83:d6:9b:ab:2a:
+        34:2f
+-----BEGIN CERTIFICATE-----
+MIIDHDCCAoWgAwIBAgIJAMvPHc3zps0JMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTExEjAQBgkqhkiG9w0BCQEWA3Rh
+MTAeFw0xMDA4MDQyMDU5MjJaFw0xMzA0MzAyMDU5MjJaMGgxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJrMQ0wCwYD
+VQQKEwRwa2c1MQwwCgYDVQQDEwN0YTExEjAQBgkqhkiG9w0BCQEWA3RhMTCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAp2RnU/Kayc6pSpIWV2HDr50On2GCrc9/
+qlny+gY9oq1P25A+SD4A1OuWwhmz4GryIWGDkt2GUP/GP94inBx0ywkG53jCjPiY
+LrXkwvS/t5JGr8fWbFkH2YwGlhvvENw++IsInb2BPA2j6VVfGwQ5uX/0z9b5ojE6
+g5YhkqcTxE0CAwEAAaOBzTCByjAdBgNVHQ4EFgQUu8nHYkuHt2oyP6VRe8E6jj8G
+XPcwgZoGA1UdIwSBkjCBj4AUu8nHYkuHt2oyP6VRe8E6jj8GXPehbKRqMGgxCzAJ
+BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQ
+YXJrMQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTExEjAQBgkqhkiG9w0BCQEW
+A3RhMYIJAMvPHc3zps0JMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEA
+B8uQ37MYImF5HTln7j2UqHvhZFJBSh9uFDS5J6oFd/k4DGYgz5IOTpS/YvEtCBzK
+PndaB+k1u6fKMYpEEKlW9JaBhFIsNkXqckZsSsoFjHnRA5OEluT6e11ZIZ+HTavx
+ZOCSFFnGxNg8M2RYmJaD8aYm/VRX1/lxPIPWm6sqNC8=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/ta2/ta2_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,63 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            b0:ef:ff:7c:38:9b:09:88
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta2/emailAddress=ta2
+        Validity
+            Not Before: Aug  4 20:59:25 2010 GMT
+            Not After : Apr 30 20:59:25 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta2/emailAddress=ta2
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:be:3e:9c:d8:84:82:5e:4b:9f:9c:0e:64:8c:9f:
+                    d0:84:d8:e4:ef:5e:0e:c2:83:94:e0:ef:6f:5a:91:
+                    3e:c5:b9:1b:cf:a5:8c:d8:39:7f:11:d3:51:1f:b7:
+                    7c:79:0e:0f:f4:0e:1d:34:49:70:cc:01:09:34:ff:
+                    cb:79:77:84:39:d9:bf:67:2c:e2:15:88:a7:9a:ec:
+                    ae:47:67:1a:72:fb:1d:be:60:26:3a:22:8e:b5:26:
+                    3d:04:c3:c6:23:87:4d:3c:34:58:5d:9a:f6:a1:a0:
+                    61:da:a6:c0:06:3e:c3:6b:db:f4:cb:7a:ef:f7:44:
+                    ef:b1:37:e3:86:31:70:fc:9b
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                F2:36:95:27:CB:21:43:55:A4:D6:1D:C0:D5:1C:39:64:1F:7B:59:28
+            X509v3 Authority Key Identifier: 
+                keyid:F2:36:95:27:CB:21:43:55:A4:D6:1D:C0:D5:1C:39:64:1F:7B:59:28
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta2/emailAddress=ta2
+                serial:B0:EF:FF:7C:38:9B:09:88
+
+            X509v3 Basic Constraints: 
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        2b:16:de:59:9f:d5:d6:88:9c:0c:10:8b:cd:9e:43:b6:d7:a8:
+        cc:4c:12:fb:88:b2:cd:99:f2:a9:d7:0d:2d:fc:48:26:bc:41:
+        09:58:14:a2:79:52:41:6d:94:4c:9b:ce:75:6d:14:4d:e8:43:
+        4a:7d:27:c9:e9:e0:76:2b:ca:4e:9b:af:12:34:83:0c:d5:15:
+        f6:a6:29:89:6e:56:49:ff:27:3c:08:bb:68:29:9e:77:09:f9:
+        1a:67:2a:f5:75:c7:f0:4b:1c:c3:6a:0e:06:50:04:e7:65:83:
+        f6:81:10:a3:4a:a5:96:ef:90:2f:ef:73:57:86:6d:10:ac:2a:
+        34:9d
+-----BEGIN CERTIFICATE-----
+MIIDHDCCAoWgAwIBAgIJALDv/3w4mwmIMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTIxEjAQBgkqhkiG9w0BCQEWA3Rh
+MjAeFw0xMDA4MDQyMDU5MjVaFw0xMzA0MzAyMDU5MjVaMGgxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJrMQ0wCwYD
+VQQKEwRwa2c1MQwwCgYDVQQDEwN0YTIxEjAQBgkqhkiG9w0BCQEWA3RhMjCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvj6c2ISCXkufnA5kjJ/QhNjk714OwoOU
+4O9vWpE+xbkbz6WM2Dl/EdNRH7d8eQ4P9A4dNElwzAEJNP/LeXeEOdm/ZyziFYin
+muyuR2cacvsdvmAmOiKOtSY9BMPGI4dNPDRYXZr2oaBh2qbABj7Da9v0y3rv90Tv
+sTfjhjFw/JsCAwEAAaOBzTCByjAdBgNVHQ4EFgQU8jaVJ8shQ1Wk1h3A1Rw5ZB97
+WSgwgZoGA1UdIwSBkjCBj4AU8jaVJ8shQ1Wk1h3A1Rw5ZB97WSihbKRqMGgxCzAJ
+BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQ
+YXJrMQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTIxEjAQBgkqhkiG9w0BCQEW
+A3RhMoIJALDv/3w4mwmIMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEA
+KxbeWZ/V1oicDBCLzZ5DtteozEwS+4iyzZnyqdcNLfxIJrxBCVgUonlSQW2UTJvO
+dW0UTehDSn0nyengdivKTpuvEjSDDNUV9qYpiW5WSf8nPAi7aCmedwn5Gmcq9XXH
+8Escw2oOBlAE52WD9oEQo0qllu+QL+9zV4ZtEKwqNJ0=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/ta3/ta3_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,63 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            e1:f8:52:2f:ac:f4:00:ee
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta3/emailAddress=ta3
+        Validity
+            Not Before: Aug  4 20:59:25 2010 GMT
+            Not After : Apr 30 20:59:25 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta3/emailAddress=ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:cc:32:e7:d2:0d:be:82:1f:48:cb:d7:74:53:c9:
+                    7a:84:99:2a:d2:d0:01:ac:e2:26:a3:8c:02:ac:d8:
+                    51:13:31:1d:c6:4c:93:74:84:9d:e7:32:87:aa:88:
+                    db:ed:41:69:ee:5d:cd:71:bf:3b:c3:45:58:c2:c7:
+                    38:3e:e6:8e:a3:7e:d7:d0:57:fb:53:a9:c3:9d:51:
+                    6b:49:43:73:ea:69:18:9f:3a:f2:42:9c:3c:7b:13:
+                    21:f5:b8:b4:9c:58:fc:ea:a7:bd:3f:53:45:89:64:
+                    8d:56:13:3b:4e:26:d1:f9:ca:3a:8d:5e:73:ce:7f:
+                    0d:b1:8d:c2:e1:96:04:33:b1
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                E0:CE:66:66:57:70:37:16:AF:EB:65:B6:15:DC:2D:2C:B7:B4:49:4D
+            X509v3 Authority Key Identifier: 
+                keyid:E0:CE:66:66:57:70:37:16:AF:EB:65:B6:15:DC:2D:2C:B7:B4:49:4D
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta3/emailAddress=ta3
+                serial:E1:F8:52:2F:AC:F4:00:EE
+
+            X509v3 Basic Constraints: 
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        b2:f7:78:f6:be:21:e5:91:f2:59:f5:9c:18:a8:3f:02:8b:39:
+        f0:80:84:ac:ed:12:70:83:2f:af:49:3a:6f:00:e8:15:e7:f4:
+        63:7a:53:08:3f:c1:66:bf:61:e9:a0:99:24:4b:93:62:e0:bd:
+        8a:ed:3f:4a:5a:09:6e:51:2e:53:67:f7:02:e0:4a:17:bb:d2:
+        a5:be:ab:e3:de:73:73:a3:ef:9d:ab:af:31:9b:bd:3c:01:9d:
+        08:14:83:44:07:59:86:96:92:59:fe:97:0c:37:9d:da:a1:af:
+        49:77:b4:72:a6:b7:8a:46:9f:ac:f3:db:ff:05:d8:15:4d:46:
+        fb:b5
+-----BEGIN CERTIFICATE-----
+MIIDHDCCAoWgAwIBAgIJAOH4Ui+s9ADuMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTMxEjAQBgkqhkiG9w0BCQEWA3Rh
+MzAeFw0xMDA4MDQyMDU5MjVaFw0xMzA0MzAyMDU5MjVaMGgxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJrMQ0wCwYD
+VQQKEwRwa2c1MQwwCgYDVQQDEwN0YTMxEjAQBgkqhkiG9w0BCQEWA3RhMzCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAzDLn0g2+gh9Iy9d0U8l6hJkq0tABrOIm
+o4wCrNhREzEdxkyTdISd5zKHqojb7UFp7l3Ncb87w0VYwsc4PuaOo37X0Ff7U6nD
+nVFrSUNz6mkYnzryQpw8exMh9bi0nFj86qe9P1NFiWSNVhM7TibR+co6jV5zzn8N
+sY3C4ZYEM7ECAwEAAaOBzTCByjAdBgNVHQ4EFgQU4M5mZldwNxav62W2FdwtLLe0
+SU0wgZoGA1UdIwSBkjCBj4AU4M5mZldwNxav62W2FdwtLLe0SU2hbKRqMGgxCzAJ
+BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQ
+YXJrMQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTMxEjAQBgkqhkiG9w0BCQEW
+A3RhM4IJAOH4Ui+s9ADuMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEA
+svd49r4h5ZHyWfWcGKg/Aos58ICErO0ScIMvr0k6bwDoFef0Y3pTCD/BZr9h6aCZ
+JEuTYuC9iu0/SloJblEuU2f3AuBKF7vSpb6r495zc6PvnauvMZu9PAGdCBSDRAdZ
+hpaSWf6XDDed2qGvSXe0cqa3ikafrPPb/wXYFU1G+7U=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/ta4/ta4_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,63 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            c0:c8:77:b4:4c:49:4f:ab
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta4/emailAddress=ta4
+        Validity
+            Not Before: Aug  4 20:59:28 2010 GMT
+            Not After : Apr 30 20:59:28 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta4/emailAddress=ta4
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:9f:46:1a:e5:09:98:a6:bd:cf:b6:5c:20:fc:82:
+                    d7:86:d2:d0:97:20:c6:12:a5:5f:6c:7a:2c:9a:68:
+                    4c:ba:75:32:09:fe:d5:b3:5b:6a:d4:fb:95:aa:bf:
+                    5a:36:c3:2e:57:3d:d1:f4:87:4c:8a:66:10:89:39:
+                    d8:b9:2f:1a:3f:37:fa:06:d0:e2:5d:3f:06:8b:a4:
+                    6e:85:4f:64:8f:72:05:fb:fe:aa:07:f5:ad:b0:49:
+                    c5:36:ee:96:c0:49:58:88:f5:a2:2f:3b:90:7d:b8:
+                    1e:d7:b0:67:cd:b9:38:05:8d:a7:94:8c:40:33:0b:
+                    1f:7d:03:dc:99:c1:55:49:59
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                FE:14:53:EF:9C:0B:AB:ED:96:22:70:11:C2:E6:7D:2E:40:B7:7F:B5
+            X509v3 Authority Key Identifier: 
+                keyid:FE:14:53:EF:9C:0B:AB:ED:96:22:70:11:C2:E6:7D:2E:40:B7:7F:B5
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta4/emailAddress=ta4
+                serial:C0:C8:77:B4:4C:49:4F:AB
+
+            X509v3 Basic Constraints: 
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        42:b3:66:1a:56:fd:34:a0:2c:92:6d:ee:3f:e0:c1:c2:c6:8b:
+        e0:d5:dd:31:9b:e2:7b:9d:fd:e4:b2:71:72:fd:32:8d:59:a1:
+        36:ea:6a:45:d5:80:d4:79:75:4f:fc:50:34:8c:c1:5b:15:0e:
+        39:fd:40:99:fd:37:12:fa:d2:6a:1a:b9:66:db:7c:a0:54:e0:
+        fa:e3:03:c6:40:cf:71:4e:e4:e9:c2:cb:db:31:3a:a7:0a:5c:
+        97:0a:78:e5:50:03:ac:6d:e3:df:07:11:cd:73:5a:75:95:a7:
+        40:c0:51:28:9b:f1:a6:1a:1c:db:9e:1b:0a:e0:74:3a:8e:69:
+        5b:55
+-----BEGIN CERTIFICATE-----
+MIIDHDCCAoWgAwIBAgIJAMDId7RMSU+rMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTQxEjAQBgkqhkiG9w0BCQEWA3Rh
+NDAeFw0xMDA4MDQyMDU5MjhaFw0xMzA0MzAyMDU5MjhaMGgxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJrMQ0wCwYD
+VQQKEwRwa2c1MQwwCgYDVQQDEwN0YTQxEjAQBgkqhkiG9w0BCQEWA3RhNDCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAn0Ya5QmYpr3Ptlwg/ILXhtLQlyDGEqVf
+bHosmmhMunUyCf7Vs1tq1PuVqr9aNsMuVz3R9IdMimYQiTnYuS8aPzf6BtDiXT8G
+i6RuhU9kj3IF+/6qB/WtsEnFNu6WwElYiPWiLzuQfbge17Bnzbk4BY2nlIxAMwsf
+fQPcmcFVSVkCAwEAAaOBzTCByjAdBgNVHQ4EFgQU/hRT75wLq+2WInARwuZ9LkC3
+f7UwgZoGA1UdIwSBkjCBj4AU/hRT75wLq+2WInARwuZ9LkC3f7WhbKRqMGgxCzAJ
+BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQ
+YXJrMQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTQxEjAQBgkqhkiG9w0BCQEW
+A3RhNIIJAMDId7RMSU+rMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEA
+QrNmGlb9NKAskm3uP+DBwsaL4NXdMZvie5395LJxcv0yjVmhNupqRdWA1Hl1T/xQ
+NIzBWxUOOf1Amf03EvrSahq5Ztt8oFTg+uMDxkDPcU7k6cLL2zE6pwpclwp45VAD
+rG3j3wcRzXNadZWnQMBRKJvxphoc254bCuB0Oo5pW1U=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/ta5/ta5_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,63 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            cb:2a:36:97:17:4f:60:24
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta5/emailAddress=ta5
+        Validity
+            Not Before: Aug  4 20:59:29 2010 GMT
+            Not After : Apr 30 20:59:29 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta5/emailAddress=ta5
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:c0:be:12:dc:dd:d4:41:ab:8e:9c:fa:63:2c:b7:
+                    36:6a:7a:bb:71:4e:5e:7a:70:50:e6:37:b4:57:75:
+                    74:21:46:48:ee:2d:9b:42:a4:3f:4f:16:05:da:b7:
+                    73:4a:4c:ab:c1:64:b2:a8:9c:fe:b7:82:d3:ec:de:
+                    83:b0:f0:26:86:c0:da:39:ca:97:b0:ce:3c:6f:16:
+                    c3:07:26:47:2e:39:94:8f:a3:05:21:2c:c5:15:29:
+                    9b:98:23:12:77:38:b8:a9:0f:ae:69:c4:54:a2:dc:
+                    03:52:fe:99:28:2e:f0:fc:d1:a6:91:89:9b:b6:0c:
+                    c1:9b:48:e0:99:a5:42:e9:0b
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                AA:44:3A:A2:05:A2:04:EB:62:E0:E5:F5:2C:44:CA:3B:CF:4D:B2:74
+            X509v3 Authority Key Identifier: 
+                keyid:AA:44:3A:A2:05:A2:04:EB:62:E0:E5:F5:2C:44:CA:3B:CF:4D:B2:74
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta5/emailAddress=ta5
+                serial:CB:2A:36:97:17:4F:60:24
+
+            X509v3 Basic Constraints: 
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        94:d5:b3:0f:11:c7:df:f9:f2:5a:a3:3c:66:f2:bd:8e:06:22:
+        d1:bb:f5:33:61:6d:8c:60:c3:4c:f8:b4:ab:1c:83:25:ca:49:
+        06:ab:de:23:24:f9:e1:b1:c1:41:4d:c8:19:74:8c:3e:01:17:
+        63:4d:c1:93:99:f1:ac:12:37:df:4e:68:8c:42:c3:51:2c:bf:
+        de:97:2f:2f:1b:58:c4:6e:35:6c:18:a4:f4:2e:21:2a:9a:bf:
+        dd:d8:90:f0:90:de:15:38:8f:c8:91:48:ce:3b:f5:29:c4:26:
+        94:a8:f9:21:7f:50:b3:ff:07:b8:88:1d:e5:68:1c:c1:31:40:
+        a8:0b
+-----BEGIN CERTIFICATE-----
+MIIDHDCCAoWgAwIBAgIJAMsqNpcXT2AkMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTUxEjAQBgkqhkiG9w0BCQEWA3Rh
+NTAeFw0xMDA4MDQyMDU5MjlaFw0xMzA0MzAyMDU5MjlaMGgxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJrMQ0wCwYD
+VQQKEwRwa2c1MQwwCgYDVQQDEwN0YTUxEjAQBgkqhkiG9w0BCQEWA3RhNTCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwL4S3N3UQauOnPpjLLc2anq7cU5eenBQ
+5je0V3V0IUZI7i2bQqQ/TxYF2rdzSkyrwWSyqJz+t4LT7N6DsPAmhsDaOcqXsM48
+bxbDByZHLjmUj6MFISzFFSmbmCMSdzi4qQ+uacRUotwDUv6ZKC7w/NGmkYmbtgzB
+m0jgmaVC6QsCAwEAAaOBzTCByjAdBgNVHQ4EFgQUqkQ6ogWiBOti4OX1LETKO89N
+snQwgZoGA1UdIwSBkjCBj4AUqkQ6ogWiBOti4OX1LETKO89NsnShbKRqMGgxCzAJ
+BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQ
+YXJrMQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTUxEjAQBgkqhkiG9w0BCQEW
+A3RhNYIJAMsqNpcXT2AkMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEA
+lNWzDxHH3/nyWqM8ZvK9jgYi0bv1M2FtjGDDTPi0qxyDJcpJBqveIyT54bHBQU3I
+GXSMPgEXY03Bk5nxrBI3305ojELDUSy/3pcvLxtYxG41bBik9C4hKpq/3diQ8JDe
+FTiPyJFIzjv1KcQmlKj5IX9Qs/8HuIgd5WgcwTFAqAs=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/trust_anchors/ta1_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,63 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            cb:cf:1d:cd:f3:a6:cd:09
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta1/emailAddress=ta1
+        Validity
+            Not Before: Aug  4 20:59:22 2010 GMT
+            Not After : Apr 30 20:59:22 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta1/emailAddress=ta1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:a7:64:67:53:f2:9a:c9:ce:a9:4a:92:16:57:61:
+                    c3:af:9d:0e:9f:61:82:ad:cf:7f:aa:59:f2:fa:06:
+                    3d:a2:ad:4f:db:90:3e:48:3e:00:d4:eb:96:c2:19:
+                    b3:e0:6a:f2:21:61:83:92:dd:86:50:ff:c6:3f:de:
+                    22:9c:1c:74:cb:09:06:e7:78:c2:8c:f8:98:2e:b5:
+                    e4:c2:f4:bf:b7:92:46:af:c7:d6:6c:59:07:d9:8c:
+                    06:96:1b:ef:10:dc:3e:f8:8b:08:9d:bd:81:3c:0d:
+                    a3:e9:55:5f:1b:04:39:b9:7f:f4:cf:d6:f9:a2:31:
+                    3a:83:96:21:92:a7:13:c4:4d
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                BB:C9:C7:62:4B:87:B7:6A:32:3F:A5:51:7B:C1:3A:8E:3F:06:5C:F7
+            X509v3 Authority Key Identifier: 
+                keyid:BB:C9:C7:62:4B:87:B7:6A:32:3F:A5:51:7B:C1:3A:8E:3F:06:5C:F7
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta1/emailAddress=ta1
+                serial:CB:CF:1D:CD:F3:A6:CD:09
+
+            X509v3 Basic Constraints: 
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        07:cb:90:df:b3:18:22:61:79:1d:39:67:ee:3d:94:a8:7b:e1:
+        64:52:41:4a:1f:6e:14:34:b9:27:aa:05:77:f9:38:0c:66:20:
+        cf:92:0e:4e:94:bf:62:f1:2d:08:1c:ca:3e:77:5a:07:e9:35:
+        bb:a7:ca:31:8a:44:10:a9:56:f4:96:81:84:52:2c:36:45:ea:
+        72:46:6c:4a:ca:05:8c:79:d1:03:93:84:96:e4:fa:7b:5d:59:
+        21:9f:87:4d:ab:f1:64:e0:92:14:59:c6:c4:d8:3c:33:64:58:
+        98:96:83:f1:a6:26:fd:54:57:d7:f9:71:3c:83:d6:9b:ab:2a:
+        34:2f
+-----BEGIN CERTIFICATE-----
+MIIDHDCCAoWgAwIBAgIJAMvPHc3zps0JMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTExEjAQBgkqhkiG9w0BCQEWA3Rh
+MTAeFw0xMDA4MDQyMDU5MjJaFw0xMzA0MzAyMDU5MjJaMGgxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJrMQ0wCwYD
+VQQKEwRwa2c1MQwwCgYDVQQDEwN0YTExEjAQBgkqhkiG9w0BCQEWA3RhMTCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAp2RnU/Kayc6pSpIWV2HDr50On2GCrc9/
+qlny+gY9oq1P25A+SD4A1OuWwhmz4GryIWGDkt2GUP/GP94inBx0ywkG53jCjPiY
+LrXkwvS/t5JGr8fWbFkH2YwGlhvvENw++IsInb2BPA2j6VVfGwQ5uX/0z9b5ojE6
+g5YhkqcTxE0CAwEAAaOBzTCByjAdBgNVHQ4EFgQUu8nHYkuHt2oyP6VRe8E6jj8G
+XPcwgZoGA1UdIwSBkjCBj4AUu8nHYkuHt2oyP6VRe8E6jj8GXPehbKRqMGgxCzAJ
+BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQ
+YXJrMQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTExEjAQBgkqhkiG9w0BCQEW
+A3RhMYIJAMvPHc3zps0JMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEA
+B8uQ37MYImF5HTln7j2UqHvhZFJBSh9uFDS5J6oFd/k4DGYgz5IOTpS/YvEtCBzK
+PndaB+k1u6fKMYpEEKlW9JaBhFIsNkXqckZsSsoFjHnRA5OEluT6e11ZIZ+HTavx
+ZOCSFFnGxNg8M2RYmJaD8aYm/VRX1/lxPIPWm6sqNC8=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/trust_anchors/ta2_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,63 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            b0:ef:ff:7c:38:9b:09:88
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta2/emailAddress=ta2
+        Validity
+            Not Before: Aug  4 20:59:25 2010 GMT
+            Not After : Apr 30 20:59:25 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta2/emailAddress=ta2
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:be:3e:9c:d8:84:82:5e:4b:9f:9c:0e:64:8c:9f:
+                    d0:84:d8:e4:ef:5e:0e:c2:83:94:e0:ef:6f:5a:91:
+                    3e:c5:b9:1b:cf:a5:8c:d8:39:7f:11:d3:51:1f:b7:
+                    7c:79:0e:0f:f4:0e:1d:34:49:70:cc:01:09:34:ff:
+                    cb:79:77:84:39:d9:bf:67:2c:e2:15:88:a7:9a:ec:
+                    ae:47:67:1a:72:fb:1d:be:60:26:3a:22:8e:b5:26:
+                    3d:04:c3:c6:23:87:4d:3c:34:58:5d:9a:f6:a1:a0:
+                    61:da:a6:c0:06:3e:c3:6b:db:f4:cb:7a:ef:f7:44:
+                    ef:b1:37:e3:86:31:70:fc:9b
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                F2:36:95:27:CB:21:43:55:A4:D6:1D:C0:D5:1C:39:64:1F:7B:59:28
+            X509v3 Authority Key Identifier: 
+                keyid:F2:36:95:27:CB:21:43:55:A4:D6:1D:C0:D5:1C:39:64:1F:7B:59:28
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta2/emailAddress=ta2
+                serial:B0:EF:FF:7C:38:9B:09:88
+
+            X509v3 Basic Constraints: 
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        2b:16:de:59:9f:d5:d6:88:9c:0c:10:8b:cd:9e:43:b6:d7:a8:
+        cc:4c:12:fb:88:b2:cd:99:f2:a9:d7:0d:2d:fc:48:26:bc:41:
+        09:58:14:a2:79:52:41:6d:94:4c:9b:ce:75:6d:14:4d:e8:43:
+        4a:7d:27:c9:e9:e0:76:2b:ca:4e:9b:af:12:34:83:0c:d5:15:
+        f6:a6:29:89:6e:56:49:ff:27:3c:08:bb:68:29:9e:77:09:f9:
+        1a:67:2a:f5:75:c7:f0:4b:1c:c3:6a:0e:06:50:04:e7:65:83:
+        f6:81:10:a3:4a:a5:96:ef:90:2f:ef:73:57:86:6d:10:ac:2a:
+        34:9d
+-----BEGIN CERTIFICATE-----
+MIIDHDCCAoWgAwIBAgIJALDv/3w4mwmIMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTIxEjAQBgkqhkiG9w0BCQEWA3Rh
+MjAeFw0xMDA4MDQyMDU5MjVaFw0xMzA0MzAyMDU5MjVaMGgxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJrMQ0wCwYD
+VQQKEwRwa2c1MQwwCgYDVQQDEwN0YTIxEjAQBgkqhkiG9w0BCQEWA3RhMjCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvj6c2ISCXkufnA5kjJ/QhNjk714OwoOU
+4O9vWpE+xbkbz6WM2Dl/EdNRH7d8eQ4P9A4dNElwzAEJNP/LeXeEOdm/ZyziFYin
+muyuR2cacvsdvmAmOiKOtSY9BMPGI4dNPDRYXZr2oaBh2qbABj7Da9v0y3rv90Tv
+sTfjhjFw/JsCAwEAAaOBzTCByjAdBgNVHQ4EFgQU8jaVJ8shQ1Wk1h3A1Rw5ZB97
+WSgwgZoGA1UdIwSBkjCBj4AU8jaVJ8shQ1Wk1h3A1Rw5ZB97WSihbKRqMGgxCzAJ
+BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQ
+YXJrMQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTIxEjAQBgkqhkiG9w0BCQEW
+A3RhMoIJALDv/3w4mwmIMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEA
+KxbeWZ/V1oicDBCLzZ5DtteozEwS+4iyzZnyqdcNLfxIJrxBCVgUonlSQW2UTJvO
+dW0UTehDSn0nyengdivKTpuvEjSDDNUV9qYpiW5WSf8nPAi7aCmedwn5Gmcq9XXH
+8Escw2oOBlAE52WD9oEQo0qllu+QL+9zV4ZtEKwqNJ0=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/trust_anchors/ta3_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,63 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            e1:f8:52:2f:ac:f4:00:ee
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta3/emailAddress=ta3
+        Validity
+            Not Before: Aug  4 20:59:25 2010 GMT
+            Not After : Apr 30 20:59:25 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta3/emailAddress=ta3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:cc:32:e7:d2:0d:be:82:1f:48:cb:d7:74:53:c9:
+                    7a:84:99:2a:d2:d0:01:ac:e2:26:a3:8c:02:ac:d8:
+                    51:13:31:1d:c6:4c:93:74:84:9d:e7:32:87:aa:88:
+                    db:ed:41:69:ee:5d:cd:71:bf:3b:c3:45:58:c2:c7:
+                    38:3e:e6:8e:a3:7e:d7:d0:57:fb:53:a9:c3:9d:51:
+                    6b:49:43:73:ea:69:18:9f:3a:f2:42:9c:3c:7b:13:
+                    21:f5:b8:b4:9c:58:fc:ea:a7:bd:3f:53:45:89:64:
+                    8d:56:13:3b:4e:26:d1:f9:ca:3a:8d:5e:73:ce:7f:
+                    0d:b1:8d:c2:e1:96:04:33:b1
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                E0:CE:66:66:57:70:37:16:AF:EB:65:B6:15:DC:2D:2C:B7:B4:49:4D
+            X509v3 Authority Key Identifier: 
+                keyid:E0:CE:66:66:57:70:37:16:AF:EB:65:B6:15:DC:2D:2C:B7:B4:49:4D
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta3/emailAddress=ta3
+                serial:E1:F8:52:2F:AC:F4:00:EE
+
+            X509v3 Basic Constraints: 
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        b2:f7:78:f6:be:21:e5:91:f2:59:f5:9c:18:a8:3f:02:8b:39:
+        f0:80:84:ac:ed:12:70:83:2f:af:49:3a:6f:00:e8:15:e7:f4:
+        63:7a:53:08:3f:c1:66:bf:61:e9:a0:99:24:4b:93:62:e0:bd:
+        8a:ed:3f:4a:5a:09:6e:51:2e:53:67:f7:02:e0:4a:17:bb:d2:
+        a5:be:ab:e3:de:73:73:a3:ef:9d:ab:af:31:9b:bd:3c:01:9d:
+        08:14:83:44:07:59:86:96:92:59:fe:97:0c:37:9d:da:a1:af:
+        49:77:b4:72:a6:b7:8a:46:9f:ac:f3:db:ff:05:d8:15:4d:46:
+        fb:b5
+-----BEGIN CERTIFICATE-----
+MIIDHDCCAoWgAwIBAgIJAOH4Ui+s9ADuMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTMxEjAQBgkqhkiG9w0BCQEWA3Rh
+MzAeFw0xMDA4MDQyMDU5MjVaFw0xMzA0MzAyMDU5MjVaMGgxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJrMQ0wCwYD
+VQQKEwRwa2c1MQwwCgYDVQQDEwN0YTMxEjAQBgkqhkiG9w0BCQEWA3RhMzCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAzDLn0g2+gh9Iy9d0U8l6hJkq0tABrOIm
+o4wCrNhREzEdxkyTdISd5zKHqojb7UFp7l3Ncb87w0VYwsc4PuaOo37X0Ff7U6nD
+nVFrSUNz6mkYnzryQpw8exMh9bi0nFj86qe9P1NFiWSNVhM7TibR+co6jV5zzn8N
+sY3C4ZYEM7ECAwEAAaOBzTCByjAdBgNVHQ4EFgQU4M5mZldwNxav62W2FdwtLLe0
+SU0wgZoGA1UdIwSBkjCBj4AU4M5mZldwNxav62W2FdwtLLe0SU2hbKRqMGgxCzAJ
+BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQ
+YXJrMQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTMxEjAQBgkqhkiG9w0BCQEW
+A3RhM4IJAOH4Ui+s9ADuMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEA
+svd49r4h5ZHyWfWcGKg/Aos58ICErO0ScIMvr0k6bwDoFef0Y3pTCD/BZr9h6aCZ
+JEuTYuC9iu0/SloJblEuU2f3AuBKF7vSpb6r495zc6PvnauvMZu9PAGdCBSDRAdZ
+hpaSWf6XDDed2qGvSXe0cqa3ikafrPPb/wXYFU1G+7U=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/trust_anchors/ta4_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,63 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            c0:c8:77:b4:4c:49:4f:ab
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta4/emailAddress=ta4
+        Validity
+            Not Before: Aug  4 20:59:28 2010 GMT
+            Not After : Apr 30 20:59:28 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta4/emailAddress=ta4
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:9f:46:1a:e5:09:98:a6:bd:cf:b6:5c:20:fc:82:
+                    d7:86:d2:d0:97:20:c6:12:a5:5f:6c:7a:2c:9a:68:
+                    4c:ba:75:32:09:fe:d5:b3:5b:6a:d4:fb:95:aa:bf:
+                    5a:36:c3:2e:57:3d:d1:f4:87:4c:8a:66:10:89:39:
+                    d8:b9:2f:1a:3f:37:fa:06:d0:e2:5d:3f:06:8b:a4:
+                    6e:85:4f:64:8f:72:05:fb:fe:aa:07:f5:ad:b0:49:
+                    c5:36:ee:96:c0:49:58:88:f5:a2:2f:3b:90:7d:b8:
+                    1e:d7:b0:67:cd:b9:38:05:8d:a7:94:8c:40:33:0b:
+                    1f:7d:03:dc:99:c1:55:49:59
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                FE:14:53:EF:9C:0B:AB:ED:96:22:70:11:C2:E6:7D:2E:40:B7:7F:B5
+            X509v3 Authority Key Identifier: 
+                keyid:FE:14:53:EF:9C:0B:AB:ED:96:22:70:11:C2:E6:7D:2E:40:B7:7F:B5
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta4/emailAddress=ta4
+                serial:C0:C8:77:B4:4C:49:4F:AB
+
+            X509v3 Basic Constraints: 
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        42:b3:66:1a:56:fd:34:a0:2c:92:6d:ee:3f:e0:c1:c2:c6:8b:
+        e0:d5:dd:31:9b:e2:7b:9d:fd:e4:b2:71:72:fd:32:8d:59:a1:
+        36:ea:6a:45:d5:80:d4:79:75:4f:fc:50:34:8c:c1:5b:15:0e:
+        39:fd:40:99:fd:37:12:fa:d2:6a:1a:b9:66:db:7c:a0:54:e0:
+        fa:e3:03:c6:40:cf:71:4e:e4:e9:c2:cb:db:31:3a:a7:0a:5c:
+        97:0a:78:e5:50:03:ac:6d:e3:df:07:11:cd:73:5a:75:95:a7:
+        40:c0:51:28:9b:f1:a6:1a:1c:db:9e:1b:0a:e0:74:3a:8e:69:
+        5b:55
+-----BEGIN CERTIFICATE-----
+MIIDHDCCAoWgAwIBAgIJAMDId7RMSU+rMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTQxEjAQBgkqhkiG9w0BCQEWA3Rh
+NDAeFw0xMDA4MDQyMDU5MjhaFw0xMzA0MzAyMDU5MjhaMGgxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJrMQ0wCwYD
+VQQKEwRwa2c1MQwwCgYDVQQDEwN0YTQxEjAQBgkqhkiG9w0BCQEWA3RhNDCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAn0Ya5QmYpr3Ptlwg/ILXhtLQlyDGEqVf
+bHosmmhMunUyCf7Vs1tq1PuVqr9aNsMuVz3R9IdMimYQiTnYuS8aPzf6BtDiXT8G
+i6RuhU9kj3IF+/6qB/WtsEnFNu6WwElYiPWiLzuQfbge17Bnzbk4BY2nlIxAMwsf
+fQPcmcFVSVkCAwEAAaOBzTCByjAdBgNVHQ4EFgQU/hRT75wLq+2WInARwuZ9LkC3
+f7UwgZoGA1UdIwSBkjCBj4AU/hRT75wLq+2WInARwuZ9LkC3f7WhbKRqMGgxCzAJ
+BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQ
+YXJrMQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTQxEjAQBgkqhkiG9w0BCQEW
+A3RhNIIJAMDId7RMSU+rMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEA
+QrNmGlb9NKAskm3uP+DBwsaL4NXdMZvie5395LJxcv0yjVmhNupqRdWA1Hl1T/xQ
+NIzBWxUOOf1Amf03EvrSahq5Ztt8oFTg+uMDxkDPcU7k6cLL2zE6pwpclwp45VAD
+rG3j3wcRzXNadZWnQMBRKJvxphoc254bCuB0Oo5pW1U=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/ro_data/signing_certs/produced/trust_anchors/ta5_cert.pem	Mon Aug 16 16:48:50 2010 -0700
@@ -0,0 +1,63 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            cb:2a:36:97:17:4f:60:24
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta5/emailAddress=ta5
+        Validity
+            Not Before: Aug  4 20:59:29 2010 GMT
+            Not After : Apr 30 20:59:29 2013 GMT
+        Subject: C=US, ST=California, L=Menlo Park, O=pkg5, CN=ta5/emailAddress=ta5
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:c0:be:12:dc:dd:d4:41:ab:8e:9c:fa:63:2c:b7:
+                    36:6a:7a:bb:71:4e:5e:7a:70:50:e6:37:b4:57:75:
+                    74:21:46:48:ee:2d:9b:42:a4:3f:4f:16:05:da:b7:
+                    73:4a:4c:ab:c1:64:b2:a8:9c:fe:b7:82:d3:ec:de:
+                    83:b0:f0:26:86:c0:da:39:ca:97:b0:ce:3c:6f:16:
+                    c3:07:26:47:2e:39:94:8f:a3:05:21:2c:c5:15:29:
+                    9b:98:23:12:77:38:b8:a9:0f:ae:69:c4:54:a2:dc:
+                    03:52:fe:99:28:2e:f0:fc:d1:a6:91:89:9b:b6:0c:
+                    c1:9b:48:e0:99:a5:42:e9:0b
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                AA:44:3A:A2:05:A2:04:EB:62:E0:E5:F5:2C:44:CA:3B:CF:4D:B2:74
+            X509v3 Authority Key Identifier: 
+                keyid:AA:44:3A:A2:05:A2:04:EB:62:E0:E5:F5:2C:44:CA:3B:CF:4D:B2:74
+                DirName:/C=US/ST=California/L=Menlo Park/O=pkg5/CN=ta5/emailAddress=ta5
+                serial:CB:2A:36:97:17:4F:60:24
+
+            X509v3 Basic Constraints: 
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+        94:d5:b3:0f:11:c7:df:f9:f2:5a:a3:3c:66:f2:bd:8e:06:22:
+        d1:bb:f5:33:61:6d:8c:60:c3:4c:f8:b4:ab:1c:83:25:ca:49:
+        06:ab:de:23:24:f9:e1:b1:c1:41:4d:c8:19:74:8c:3e:01:17:
+        63:4d:c1:93:99:f1:ac:12:37:df:4e:68:8c:42:c3:51:2c:bf:
+        de:97:2f:2f:1b:58:c4:6e:35:6c:18:a4:f4:2e:21:2a:9a:bf:
+        dd:d8:90:f0:90:de:15:38:8f:c8:91:48:ce:3b:f5:29:c4:26:
+        94:a8:f9:21:7f:50:b3:ff:07:b8:88:1d:e5:68:1c:c1:31:40:
+        a8:0b
+-----BEGIN CERTIFICATE-----
+MIIDHDCCAoWgAwIBAgIJAMsqNpcXT2AkMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJr
+MQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTUxEjAQBgkqhkiG9w0BCQEWA3Rh
+NTAeFw0xMDA4MDQyMDU5MjlaFw0xMzA0MzAyMDU5MjlaMGgxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQYXJrMQ0wCwYD
+VQQKEwRwa2c1MQwwCgYDVQQDEwN0YTUxEjAQBgkqhkiG9w0BCQEWA3RhNTCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwL4S3N3UQauOnPpjLLc2anq7cU5eenBQ
+5je0V3V0IUZI7i2bQqQ/TxYF2rdzSkyrwWSyqJz+t4LT7N6DsPAmhsDaOcqXsM48
+bxbDByZHLjmUj6MFISzFFSmbmCMSdzi4qQ+uacRUotwDUv6ZKC7w/NGmkYmbtgzB
+m0jgmaVC6QsCAwEAAaOBzTCByjAdBgNVHQ4EFgQUqkQ6ogWiBOti4OX1LETKO89N
+snQwgZoGA1UdIwSBkjCBj4AUqkQ6ogWiBOti4OX1LETKO89NsnShbKRqMGgxCzAJ
+BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpNZW5sbyBQ
+YXJrMQ0wCwYDVQQKEwRwa2c1MQwwCgYDVQQDEwN0YTUxEjAQBgkqhkiG9w0BCQEW
+A3RhNYIJAMsqNpcXT2AkMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEA
+lNWzDxHH3/nyWqM8ZvK9jgYi0bv1M2FtjGDDTPi0qxyDJcpJBqveIyT54bHBQU3I
+GXSMPgEXY03Bk5nxrBI3305ojELDUSy/3pcvLxtYxG41bBik9C4hKpq/3diQ8JDe
+FTiPyJFIzjv1KcQmlKj5IX9Qs/8HuIgd5WgcwTFAqAs=
+-----END CERTIFICATE-----
--- a/src/tests/run.py	Thu Aug 12 09:48:48 2010 -0700
+++ b/src/tests/run.py	Mon Aug 16 16:48:50 2010 -0700
@@ -396,6 +396,7 @@
                     "%s/cherrypy" % vp,
                     "%s/ply" % vp,
                     "%s/mako" % vp,
+                    "%s/M2Crypto" % vp,
                     # This removes test-related stuff, as well as compiled
                     # expressions such as Mako templates and filters.
                     ""