aboutsummaryrefslogtreecommitdiff
path: root/doc/manual
diff options
context:
space:
mode:
Diffstat (limited to 'doc/manual')
-rw-r--r--doc/manual/00.RPKI.md41
-rw-r--r--doc/manual/00.RPKI.wiki39
-rw-r--r--doc/manual/01.RPKI.Installation.md47
-rw-r--r--doc/manual/01.RPKI.Installation.wiki38
-rw-r--r--doc/manual/02.RPKI.Installation.DebianPackages.md66
-rw-r--r--doc/manual/02.RPKI.Installation.DebianPackages.wiki90
-rw-r--r--doc/manual/03.RPKI.Installation.FreeBSDPorts.md68
-rw-r--r--doc/manual/03.RPKI.Installation.FreeBSDPorts.wiki124
-rw-r--r--doc/manual/04.RPKI.Installation.FromSource.md208
-rw-r--r--doc/manual/04.RPKI.Installation.FromSource.wiki297
-rw-r--r--doc/manual/05.RPKI.RP.md78
-rw-r--r--doc/manual/05.RPKI.RP.wiki81
-rw-r--r--doc/manual/06.RPKI.RP.rcynic.md624
-rw-r--r--doc/manual/06.RPKI.RP.rcynic.wiki690
-rw-r--r--doc/manual/07.RPKI.RP.rpki-rtr.md150
-rw-r--r--doc/manual/07.RPKI.RP.rpki-rtr.wiki213
-rw-r--r--doc/manual/08.RPKI.RP.RunningUnderCron.md61
-rw-r--r--doc/manual/08.RPKI.RP.RunningUnderCron.wiki72
-rw-r--r--doc/manual/09.RPKI.RP.HierarchicalRsync.md88
-rw-r--r--doc/manual/09.RPKI.RP.HierarchicalRsync.wiki103
-rw-r--r--doc/manual/10.RPKI.RP.rcynicChroot.md161
-rw-r--r--doc/manual/10.RPKI.RP.rcynicChroot.wiki214
-rw-r--r--doc/manual/11.RPKI.CA.md242
-rw-r--r--doc/manual/11.RPKI.CA.wiki264
-rw-r--r--doc/manual/12.RPKI.CA.Configuration.md192
-rw-r--r--doc/manual/12.RPKI.CA.Configuration.wiki263
-rw-r--r--doc/manual/13.RPKI.CA.Configuration.Common.md71
-rw-r--r--doc/manual/13.RPKI.CA.Configuration.Common.wiki63
-rw-r--r--doc/manual/14.RPKI.CA.Configuration.myrpki.md295
-rw-r--r--doc/manual/14.RPKI.CA.Configuration.myrpki.wiki413
-rw-r--r--doc/manual/15.RPKI.CA.Configuration.rpkid.md80
-rw-r--r--doc/manual/15.RPKI.CA.Configuration.rpkid.wiki129
-rw-r--r--doc/manual/16.RPKI.CA.Configuration.irdbd.md47
-rw-r--r--doc/manual/16.RPKI.CA.Configuration.irdbd.wiki76
-rw-r--r--doc/manual/17.RPKI.CA.Configuration.pubd.md76
-rw-r--r--doc/manual/17.RPKI.CA.Configuration.pubd.wiki123
-rw-r--r--doc/manual/18.RPKI.CA.Configuration.rootd.md145
-rw-r--r--doc/manual/18.RPKI.CA.Configuration.rootd.wiki216
-rw-r--r--doc/manual/19.RPKI.CA.Configuration.CreatingRoot.md123
-rw-r--r--doc/manual/19.RPKI.CA.Configuration.CreatingRoot.wiki143
-rw-r--r--doc/manual/20.RPKI.CA.Configuration.web_portal.md47
-rw-r--r--doc/manual/20.RPKI.CA.Configuration.web_portal.wiki73
-rw-r--r--doc/manual/21.RPKI.CA.Configuration.autoconf.md29
-rw-r--r--doc/manual/21.RPKI.CA.Configuration.autoconf.wiki43
-rw-r--r--doc/manual/22.RPKI.CA.Configuration.Tests.md108
-rw-r--r--doc/manual/22.RPKI.CA.Configuration.Tests.wiki102
-rw-r--r--doc/manual/23.RPKI.CA.Configuration.DifferentServer.md37
-rw-r--r--doc/manual/23.RPKI.CA.Configuration.DifferentServer.wiki69
-rw-r--r--doc/manual/24.RPKI.CA.MySQLSetup.md65
-rw-r--r--doc/manual/24.RPKI.CA.MySQLSetup.wiki73
-rw-r--r--doc/manual/25.RPKI.CA.OOBSetup.md4
-rw-r--r--doc/manual/25.RPKI.CA.OOBSetup.wiki6
-rw-r--r--doc/manual/26.RPKI.CA.UI.md107
-rw-r--r--doc/manual/26.RPKI.CA.UI.wiki177
-rw-r--r--doc/manual/27.RPKI.CA.UI.rpkic.md86
-rw-r--r--doc/manual/27.RPKI.CA.UI.rpkic.wiki105
-rw-r--r--doc/manual/28.RPKI.CA.UI.GUI.00.jpgbin0 -> 18883 bytes
-rw-r--r--doc/manual/28.RPKI.CA.UI.GUI.01.jpgbin0 -> 26282 bytes
-rw-r--r--doc/manual/28.RPKI.CA.UI.GUI.02.jpgbin0 -> 15759 bytes
-rw-r--r--doc/manual/28.RPKI.CA.UI.GUI.03.jpgbin0 -> 23814 bytes
-rw-r--r--doc/manual/28.RPKI.CA.UI.GUI.04.jpgbin0 -> 32473 bytes
-rw-r--r--doc/manual/28.RPKI.CA.UI.GUI.05.jpgbin0 -> 15774 bytes
-rw-r--r--doc/manual/28.RPKI.CA.UI.GUI.06.jpgbin0 -> 19565 bytes
-rw-r--r--doc/manual/28.RPKI.CA.UI.GUI.md52
-rw-r--r--doc/manual/28.RPKI.CA.UI.GUI.wiki47
-rw-r--r--doc/manual/29.RPKI.CA.UI.GUI.Installing.md41
-rw-r--r--doc/manual/29.RPKI.CA.UI.GUI.Installing.wiki34
-rw-r--r--doc/manual/30.RPKI.CA.UI.GUI.Upgrading.md40
-rw-r--r--doc/manual/30.RPKI.CA.UI.GUI.Upgrading.wiki36
-rw-r--r--doc/manual/31.RPKI.CA.UI.GUI.Upgrading.BeforeMigration.md78
-rw-r--r--doc/manual/31.RPKI.CA.UI.GUI.Upgrading.BeforeMigration.wiki71
-rw-r--r--doc/manual/32.RPKI.CA.UI.GUI.Configuring.md89
-rw-r--r--doc/manual/32.RPKI.CA.UI.GUI.Configuring.wiki65
-rw-r--r--doc/manual/33.RPKI.CA.UI.GUI.Configuring.Apache.md85
-rw-r--r--doc/manual/33.RPKI.CA.UI.GUI.Configuring.Apache.wiki79
-rw-r--r--doc/manual/34.RPKI.CA.UI.GUI.UserModel.md130
-rw-r--r--doc/manual/34.RPKI.CA.UI.GUI.UserModel.wiki93
-rw-r--r--doc/manual/35.RPKI.CA.Protocols.LeftRight.md486
-rw-r--r--doc/manual/35.RPKI.CA.Protocols.LeftRight.wiki473
-rw-r--r--doc/manual/36.RPKI.Utils.md182
-rw-r--r--doc/manual/36.RPKI.Utils.wiki179
-rw-r--r--doc/manual/37.RPKI.Protocols.md9
-rw-r--r--doc/manual/37.RPKI.Protocols.wiki8
-rw-r--r--doc/manual/38.RPKI.Protocols.OOB.00.svg321
-rw-r--r--doc/manual/38.RPKI.Protocols.OOB.md15
-rw-r--r--doc/manual/38.RPKI.Protocols.OOB.wiki15
-rw-r--r--doc/manual/38.RPKI.Protocols.OOB.zipbin0 -> 4627 bytes
-rw-r--r--doc/manual/39.RPKI.Protocols.Up-Down.00.svg305
-rw-r--r--doc/manual/39.RPKI.Protocols.Up-Down.md8
-rw-r--r--doc/manual/39.RPKI.Protocols.Up-Down.wiki8
-rw-r--r--doc/manual/39.RPKI.Protocols.Up-Down.zipbin0 -> 4295 bytes
-rw-r--r--doc/manual/README34
-rw-r--r--doc/manual/pubd-bpki.dot42
-rw-r--r--doc/manual/rpki-wiki-to-markdown.py341
-rw-r--r--doc/manual/rpkid-bpki.dot76
95 files changed, 11087 insertions, 0 deletions
diff --git a/doc/manual/00.RPKI.md b/doc/manual/00.RPKI.md
new file mode 100644
index 00000000..30a830e1
--- /dev/null
+++ b/doc/manual/00.RPKI.md
@@ -0,0 +1,41 @@
+# RPKI Tools Manual
+
+This collection of tools implements both the production (CA) and relying party
+(RP) sides of an RPKI environment.
+
+Source code for the entire project is available on [GitHub][].
+
+## Download and Install
+
+Full source code is available, as are binary packages for a few platforms.
+
+See the [installation instructions][Installation] for how
+to download the code and install it once you've downloaded it.
+
+## Relying Party Tools
+
+If you operate routers and want to use RPKI data to help secure them, you
+should look at the [relying party tools][RP].
+
+## CA Tools
+
+If you control RPKI resources and need an engine let you request certificates,
+issue ROAs, or issue certificates to other entities, you should look at the
+[CA tools][CA].
+
+## Thanks
+
+From 2006 through 2008, this work was funded by [ARIN][].
+
+From 2009 through 2016, this work was funded by [DHS][].
+
+Special thanks to Michael Elkins, who wrote the web GUI and generally
+served as a second brain and second set of eyeballs on a long list of
+thorny technical problems.
+
+[GitHub]: https://github.com/dragonresearch/rpki.net
+[Installation]: 01.RPKI.Installation.md
+[RP]: 05.RPKI.RP.md
+[CA]: 11.RPKI.CA.md
+[ARIN]: http://www.arin.net/
+[DHS]: http://www.dhs.gov/
diff --git a/doc/manual/00.RPKI.wiki b/doc/manual/00.RPKI.wiki
new file mode 100644
index 00000000..aaf59d4e
--- /dev/null
+++ b/doc/manual/00.RPKI.wiki
@@ -0,0 +1,39 @@
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= RPKI Tools Manual =
+
+This collection of tools implements both the production (CA) and
+relying party (RP) sides of an RPKI environment.
+
+The Subversion repository for the entire project is available for
+(read-only) anonymous access at https://subvert-rpki.hactrn.net/.
+
+If you just want to browse the code you might find the
+[[http://trac.rpki.net/browser/|Trac source code browser interface]]
+more convenient.
+
+== Download and Install ==
+
+Full source code is available, as are binary packages for a few platforms.
+
+See the [[wiki:doc/RPKI/Installation|installation instructions]] for
+how to download the code and install it once you've downloaded it.
+
+== Relying Party Tools ==
+
+If you operate routers and want to use RPKI data to help secure them,
+you should look at the [[./RP|relying party tools]].
+
+== CA Tools ==
+
+If you control RPKI resources and need an engine let you request
+certificates, issue ROAs, or issue certificates to other entities, you
+should look at the [[./CA|CA tools]].
+
+== Thanks ==
+
+This work was funded from 2006 through 2008 by
+[[http://www.arin.net/|ARIN]], in collaboration with the other
+Regional Internet Registries. Current work is funded by
+[[http://www.dhs.gov/|DHS]].
diff --git a/doc/manual/01.RPKI.Installation.md b/doc/manual/01.RPKI.Installation.md
new file mode 100644
index 00000000..c530ee7e
--- /dev/null
+++ b/doc/manual/01.RPKI.Installation.md
@@ -0,0 +1,47 @@
+# Download and Installation
+
+There are a few different ways to install the RPKI code, depending on what the
+platform on which you're trying to install.
+
+## Debian and Ubuntu
+
+On Ubuntu 16.04 LTS ("Xenial") or Debian 8 ("Jessie"), you can use
+[Debian binary packages][Debian].
+
+## Simple RPKI Cache Install
+
+If you want to install a simple RPKI cache to feed routers from a Ubuntu 14.04
+system, here is a one page ten minute recipe.
+
+## Install a CA and a cache on a Ubuntu 14.04 with a rootd CA
+
+If you want to install a CA and a cache on a Ubuntu 14.04 with a rootd CA,
+here is a one page hack. It will take less than an hour.
+
+## Try the rrdp testbed CA and RP on Ubuntu Xenial
+
+If you are feeling adventurous and want to try the rrdp testbed CA and RP on
+Ubuntu Xenial 16.04 here is a one page hack. It supports a much simpler root
+CA.
+
+## FreeBSD
+
+On FreeBSD, you can use [FreeBSD ports][FreeBSD].
+
+## Other Platforms
+
+On all other platforms, or on the above platforms if the pre-packaged versions
+don't suit your needs, you will have to
+[install from source code][Source].
+
+Once you've finished installing the code, you will need to configure it. Since
+CAs are generally also relying parties (if only so that they can check the
+results of their own actions), you will generally want to start by configuring
+[the relying party tools][RP], then configure [the CA tools][CA]
+if you're planning to use them.
+
+[Debian]: 02.RPKI.Installation.DebianPackages.md
+[FreeBSD]: 03.RPKI.Installation.FreeBSDPorts.md
+[Source]: 04.RPKI.Installation.FromSource.md
+[RP]: 05.RPKI.RP.md
+[CA]: 11.RPKI.CA.md
diff --git a/doc/manual/01.RPKI.Installation.wiki b/doc/manual/01.RPKI.Installation.wiki
new file mode 100644
index 00000000..89b9225b
--- /dev/null
+++ b/doc/manual/01.RPKI.Installation.wiki
@@ -0,0 +1,38 @@
+[[PageOutline]]
+
+[[TracNav(doc/RPKI/TOC)]]
+
+= Download and Installation =
+
+There are a few different ways to install the RPKI code, depending on
+what the platform on which you're trying to install.
+
+* On Ubuntu 12.04 LTS ("Precise Pangolin"), Ubuntu 14.04 ("Trusty Tahir"), or Debian 7 ("Wheezy"), you can use [wiki:doc/RPKI/Installation/DebianPackages Debian binary packages].
+
+== Simple RPKI Cacha Install ==
+
+if you want to install a simple RPKI cache to feed routers from a Ubuntu 14.04 system, [wiki:doc/RPKI/Installation/UbuntuRP here is a one page ten minute recipe].
+
+== install a CA and a cache on a Ubuntu 14.04 with a rootd CA ==
+
+If you want to install a CA and a cache on a Ubuntu 14.04 with a rootd CA, [wiki:doc/RPKI/Installation/UbuntuRootd here is a one page hack]. It will take less than an hour.
+
+== Try the rrdp testbed CA and RP on Ubuntu Xenial ==
+
+If you are feeling adventurous and want to try the rrdp testbed CA and RP on Ubuntu Xenial 16.04 [wiki:RRDPtestbed here is a one page hack.] It supports a much simpler root CA.
+
+== FreeBSD ==
+
+On FreeBSD, you can use [wiki:doc/RPKI/Installation/FreeBSDPorts FreeBSD ports].
+
+== Other Platforms ==
+
+On all other platforms, or on the above platforms if the
+pre-packaged versions don't suit your needs, you will have to
+[wiki:doc/RPKI/Installation/FromSource install from source code].
+
+Once you've finished installing the code, you will need to configure
+it. Since CAs are generally also relying parties (if only so that
+they can check the results of their own actions), you will generally
+want to start by configuring the [[RP|relying party tools]], then
+configure the [[CA|CA tools]] if you're planning to use them.
diff --git a/doc/manual/02.RPKI.Installation.DebianPackages.md b/doc/manual/02.RPKI.Installation.DebianPackages.md
new file mode 100644
index 00000000..4ac60d65
--- /dev/null
+++ b/doc/manual/02.RPKI.Installation.DebianPackages.md
@@ -0,0 +1,66 @@
+# Installation Using Debian Packages on Debian and Ubuntu Systems
+
+Precompiled binary packages for Ubuntu 12.04 LTS ("Precise Pangolin") and
+Debian 7 ("Wheezy") are available from download.rpki.net using the Debian
+Advanced Package Tools (APT). To use these, you need to configure APT on your
+machine to know about our APT repository, but once you've done this you should
+be able to install and update these packages like any other precompiled
+package.
+
+## Initial APT Setup
+
+You should only need to perform these steps once for any particular machine.
+
+ * Add the GPG public key for this repository (optional, but APT will whine unless you do this):
+
+ wget -q -O - https://download.rpki.net/APT/apt-gpg-key.asc | sudo apt-key add -
+
+ * Configure APT to use this repository (for Ubuntu Trusty systems):
+
+ sudo wget -q -O /etc/apt/sources.list.d/rpki.list https://download.rpki.net/APT/rpki.trusty.list
+
+ * Configure APT to use this repository (for Ubuntu Precise systems):
+
+ sudo wget -q -O /etc/apt/sources.list.d/rpki.list https://download.rpki.net/APT/rpki.precise.list
+
+ * Configure APT to use this repository (for Debian Wheezy systems):
+
+ sudo wget -q -O /etc/apt/sources.list.d/rpki.list https://download.rpki.net/APT/rpki.wheezy.list
+
+## Installation Using APT Tools
+
+These instructions assume that you're using apt-get. Other APT tools such as
+aptitude should also work.
+
+ * Update available packages:
+
+ sudo apt-get update
+
+ * Install the software:
+
+ sudo apt-get install rpki-rp rpki-ca
+
+ * Customize the default `rpki.conf` for your environment as necessary. In particular, you want to change `handle` and `rpkid_server_host`. There are [obsessively detailed instructions][Configuration].
+
+ sudo emacs /etc/rpki.conf
+
+> Again, you want to change `handle` and `rpkid_server_host` at the minimum.
+
+ * If you changed anything in `rpki.conf`, you should restart the RPKI CA service:
+
+ sudo service rpki-ca restart
+
+## Upgrading
+
+Once you've performed the steps above you should be able to upgrade to newer
+version of the code using the normal APT upgrade process, eg:
+
+ sudo apt-get update
+ sudo apt-get upgrade
+
+Or, if you only want to update the RPKI tools:
+
+ sudo apt-get update
+ sudo apt-get upgrade rpki-ca rpki-rp
+
+[Configuration]: 12.RPKI.CA.Configuration.md
diff --git a/doc/manual/02.RPKI.Installation.DebianPackages.wiki b/doc/manual/02.RPKI.Installation.DebianPackages.wiki
new file mode 100644
index 00000000..fdf5b1d3
--- /dev/null
+++ b/doc/manual/02.RPKI.Installation.DebianPackages.wiki
@@ -0,0 +1,90 @@
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= Installation Using Debian Packages on Debian and Ubuntu Systems =
+
+Precompiled binary packages for Ubuntu 12.04 LTS ("Precise Pangolin") and
+Debian 7 ("Wheezy") are available from download.rpki.net using the Debian
+Advanced Package Tools (APT). To use these, you need to configure APT on your
+machine to know about our APT repository, but once you've done this you should
+be able to install and update these packages like any other precompiled package.
+
+== Initial APT Setup ==
+
+You should only need to perform these steps once for any particular
+machine.
+
+* Add the GPG public key for this repository (optional, but APT will whine unless you do this):
+{{{
+#!sh
+wget -q -O - https://download.rpki.net/APT/apt-gpg-key.asc | sudo apt-key add -
+}}}
+
+* Configure APT to use this repository (for Ubuntu Trusty systems):
+{{{
+#!sh
+sudo wget -q -O /etc/apt/sources.list.d/rpki.list https://download.rpki.net/APT/rpki.trusty.list
+}}}
+
+* Configure APT to use this repository (for Ubuntu Precise systems):
+{{{
+#!sh
+sudo wget -q -O /etc/apt/sources.list.d/rpki.list https://download.rpki.net/APT/rpki.precise.list
+}}}
+
+* Configure APT to use this repository (for Debian Wheezy systems):
+{{{
+#!sh
+sudo wget -q -O /etc/apt/sources.list.d/rpki.list https://download.rpki.net/APT/rpki.wheezy.list
+}}}
+
+== Installation Using APT Tools ==
+
+These instructions assume that you're using apt-get. Other APT tools
+such as aptitude should also work.
+
+* Update available packages:
+{{{
+#!sh
+sudo apt-get update
+}}}
+
+* Install the software:
+{{{
+#!sh
+sudo apt-get install rpki-rp rpki-ca
+}}}
+
+* Customize the default `rpki.conf` for your environment as necessary. In
+ particular, you want to change `handle` and `rpkid_server_host`.
+ There are [[CA/Configuration|obsessively detailed instructions]].
+{{{#!sh
+sudo emacs /etc/rpki.conf
+}}}
+
+ Again, you want to change `handle` and `rpkid_server_host` at the minimum.
+
+* If you changed anything in `rpki.conf`, you should restart the RPKI CA service:
+{{{
+#!sh
+sudo service rpki-ca restart
+}}}
+
+== Upgrading ==
+
+Once you've performed the steps above you should be able to upgrade
+to newer version of the code using the normal APT upgrade process, eg:
+
+{{{
+#!sh
+sudo apt-get update
+sudo apt-get upgrade
+}}}
+
+Or, if you only want to update the RPKI tools:
+
+{{{
+#!sh
+sudo apt-get update
+sudo apt-get upgrade rpki-ca rpki-rp
+}}}
diff --git a/doc/manual/03.RPKI.Installation.FreeBSDPorts.md b/doc/manual/03.RPKI.Installation.FreeBSDPorts.md
new file mode 100644
index 00000000..d4690425
--- /dev/null
+++ b/doc/manual/03.RPKI.Installation.FreeBSDPorts.md
@@ -0,0 +1,68 @@
+# Installation Using FreeBSD Ports
+
+Port skeletons are available for FreeBSD from download.rpki.net. To use these,
+you need to download the port skeletons then run them using your favorite
+FreeBSD port installation tool.
+
+## Manual Download
+
+To download the port skeletons manually and install from them, do something
+like this:
+
+ for port in rpki-rp rpki-ca
+ do
+ fetch https://download.rpki.net/FreeBSD_Packages/${port}-port.tgz
+ tar xf ${port}-port.tgz
+ cd ${port}
+ make install
+ cd ..
+ rm -rf ${port}
+ done
+
+After performing initial installation, you should customize the default
+`rpki.conf` for your environment as necessary. In particular, you want to
+change `handle` and `rpkid_server_host`. There are [obsessively detailed
+instructions][Configuration].
+
+ emacs /usr/local/etc/rpki.conf
+
+Again, you want to change `handle` and `rpkid_server_host` at the minimum.
+
+To upgrade, you can perform almost the same steps, but the FreeBSD ports
+system, which doesn't really know about upgrades, will require you to use the
+`deinstall` and `reinstall` operations instead of plain `install`:
+
+ for port in rpki-rp rpki-ca
+ do
+ fetch https://download.rpki.net/FreeBSD_Packages/${port}-port.tgz
+ tar xf ${port}-port.tgz
+ cd ${port}
+ make deinstall
+ make reinstall
+ cd ..
+ rm -rf ${port}
+ done
+
+After an upgrade, you may want to check the newly-installed
+`/usr/local/etc/rpki.conf.sample` against your existing
+`/usr/local/etc/rpki.conf` in case any important options have changed. We
+generally try to keep options stable between versions, and provide sane
+defaults where we can, but if you've done a lot of customization to your
+`rpki.conf` you will want to keep track of this.
+
+## Automated Download and Install with portmaster
+
+There's a [script][portmaster] you can use to automate the download steps above and
+perform the updates using portmaster. First, download the script:
+
+ fetch https://download.rpki.net/FreeBSD_Packages/rpki-portmaster.sh
+
+Then, to install or upgrade, just execute the script:
+
+ sh rpki-portmaster.sh
+
+As with manual download (above) you should customize `rpki.conf` after initial
+installation.
+
+[Configuration]: 12.RPKI.CA.Configuration.md
+[portmaster]: https://download.rpki.net/FreeBSD_Packages/rpki-portmaster.sh
diff --git a/doc/manual/03.RPKI.Installation.FreeBSDPorts.wiki b/doc/manual/03.RPKI.Installation.FreeBSDPorts.wiki
new file mode 100644
index 00000000..bff99b78
--- /dev/null
+++ b/doc/manual/03.RPKI.Installation.FreeBSDPorts.wiki
@@ -0,0 +1,124 @@
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= Installation Using FreeBSD Ports =
+
+Port skeletons are available for FreeBSD from download.rpki.net. To
+use these, you need to download the port skeletons then run them using
+your favorite FreeBSD port installation tool.
+
+== Manual Download ==
+
+To download the port skeletons manually and install from them, do
+something like this:
+
+{{{
+#!sh
+for port in rpki-rp rpki-ca
+do
+ fetch https://download.rpki.net/FreeBSD_Packages/${port}-port.tgz
+ tar xf ${port}-port.tgz
+ cd ${port}
+ make install
+ cd ..
+ rm -rf ${port}
+done
+}}}
+
+After performing initial installation, you should customize the
+default `rpki.conf` for your environment as necessary. In particular,
+you want to change `handle` and `rpkid_server_host`. There are
+[[CA/Configuration|obsessively detailed instructions]].
+
+{{{
+#!sh
+emacs /usr/local/etc/rpki.conf
+}}}
+
+Again, you want to change `handle` and `rpkid_server_host` at the minimum.
+
+To upgrade, you can perform almost the same steps, but the FreeBSD
+ports system, which doesn't really know about upgrades, will require
+you to use the `deinstall` and `reinstall` operations instead of plain
+`install`:
+
+{{{
+#!sh
+for port in rpki-rp rpki-ca
+do
+ fetch https://download.rpki.net/FreeBSD_Packages/${port}-port.tgz
+ tar xf ${port}-port.tgz
+ cd ${port}
+ make deinstall
+ make reinstall
+ cd ..
+ rm -rf ${port}
+done
+}}}
+
+After an upgrade, you may want to check the newly-installed
+`/usr/local/etc/rpki.conf.sample` against your existing
+`/usr/local/etc/rpki.conf` in case any important options have changed.
+We generally try to keep options stable between versions, and provide
+sane defaults where we can, but if you've done a lot of customization
+to your `rpki.conf` you will want to keep track of this.
+
+== Automated Download and Install with portmaster ==
+
+There's a
+[[https://download.rpki.net/FreeBSD_Packages/rpki-portmaster.sh|script]]
+you can use to automate the download steps above and perform the
+updates using portmaster. First, download the script:
+
+{{{
+#!sh
+fetch https://download.rpki.net/FreeBSD_Packages/rpki-portmaster.sh
+}}}
+
+Then, to install or upgrade, just execute the script:
+
+{{{
+#!sh
+sh rpki-portmaster.sh
+}}}
+
+As with manual download (above) you should customize `rpki.conf` after
+initial installation.
+
+== Automated Download and Install with portupgrade ==
+
+There's a
+[[https://download.rpki.net/FreeBSD_Packages/rpki-portupgrade.sh|script]]
+you can use to automate the download steps above and perform the
+updates using portupgrade. First, download the script:
+
+{{{
+#!sh
+fetch https://download.rpki.net/FreeBSD_Packages/rpki-portupgrade.sh
+}}}
+
+Next, you will need to add information about the RPKI ports to two
+variables in `/usr/local/etc/pkgtools.conf` before portupgrade will
+know how to deal with these ports:
+
+{{{
+#!ruby
+EXTRA_CATEGORIES = [
+ 'rpki',
+]
+
+ALT_INDEX = [
+ ENV['PORTSDIR'] + '/INDEX.rpki',
+]
+}}}
+
+Once you have completed these steps, you can just execute the script
+to install or upgrade the RPKI code:
+
+{{{
+#!sh
+sh rpki-portupgrade.sh
+}}}
+
+As with manual download (above) you should customize `rpki.conf` after
+initial installation.
diff --git a/doc/manual/04.RPKI.Installation.FromSource.md b/doc/manual/04.RPKI.Installation.FromSource.md
new file mode 100644
index 00000000..71d77821
--- /dev/null
+++ b/doc/manual/04.RPKI.Installation.FromSource.md
@@ -0,0 +1,208 @@
+# Installing From Source Code
+
+At present, the entire RPKI tools collection is a single source tree with a
+shared autoconf configuration. This may change in the future, but for now,
+this means that the build process is essentially the same regardless of which
+tools one wants to use. Some of the tools have dependencies on external
+packages, although we've tried to keep this to a minimum.
+
+Most of the tools require an [RFC-3779][]-aware version of the [OpenSSL][]
+libraries. If necessary, the build process will generate its own private copy
+of the OpenSSL libraries for this purpose.
+
+Other than OpenSSL, most of the relying party tools are fairly self-contained.
+The CA tools have a few additional dependencies, described below.
+
+Note that initial development of this code has been on FreeBSD, so
+installation will probably be easiest on FreeBSD. We do, however, test on
+other platforms, such as Fedora, Ubuntu, Debian, and MacOSX.
+
+## Downloading the Source Code
+
+The recommended way to obtain the source code is via [Subversion][]. To
+download, do:
+
+ $ svn checkout https://subvert-rpki.hactrn.net/trunk/
+
+Code snapshots are also available from <https://download.rpki.net/> as xz-
+compressed tarballs.
+
+## Prerequisites
+
+Before attempting to build the tools from source, you will need to install any
+missing prerequisites.
+
+Some of the relying party tools and most of the CA tools are written in
+Python. Note that the Python code requires Python version 2.6 or 2.7.
+
+On some platforms (particularly MacOSX) the simplest way to install some of
+the Python packages may be the "easy_install" or "pip" tools that comes with
+Python.
+
+Packages you will need:
+
+ * You will need a C compiler. gcc is fine, others such as Clang should also work.
+ * <http://www.python.org/>, the Python interpreter, libraries, and sources. On some platforms the Python sources (in particular, the header files and libraries needed when building Python extensions) are in a separate "development" package, on other platforms they are all part of a single package. If you get compilation errors trying to build the POW code later in the build process and the error message says something about the file "Python.h" being missing, this is almost certainly your problem.
+ * FreeBSD:
+ * /usr/ports/lang/python27 (python)
+ * Debian &amp; Ubuntu:
+ * python
+ * python-dev
+ * python-setuptools
+
+ * <http://codespeak.net/lxml/>, a Pythonic interface to the Gnome LibXML2 libraries. lxml in turn requires the LibXML2 C libraries; on some platforms, some of the LibXML2 utilities are packaged separately and may not be pulled in as dependencies.
+ * FreeBSD: /usr/ports/devel/py-lxml (py27-lxml)
+ * Fedora: python-lxml.i386
+ * Debian &amp; Ubuntu:
+ * python-lxml
+ * libxml2-utils
+ * <http://www.mysql.com/>, MySQL client and server. How these are packaged varies by platform, on some platforms the client and server are separate packages, on others they might be a single monolithic package, or installing the server might automatically install the client as a dependency. On MacOSX you might be best off installing a binary package for MySQL. The RPKI CA tools have been tested with MySQL 5.0, 5.1, and 5.5; they will probably work with any other reasonably recent version.
+ * FreeBSD:
+ * /usr/ports/databases/mysql55-server (mysql55-server)
+ * /usr/ports/databases/mysql55-client (mysql55-client)
+ * Debian &amp; Ubuntu:
+ * mysql-client
+ * mysql-server
+ * <http://sourceforge.net/projects/mysql-python/>, the Python "db" interface to MySQL.
+ * FreeBSD: /usr/ports/databases/py-MySQLdb (py27-MySQLdb)
+ * Fedora: MySQL-python.i386
+ * Debian &amp; Ubuntu: python-mysqldb
+ * <http://www.djangoproject.com/>, the Django web user interface toolkit. The GUI interface to the CA tools requires this. Django 1.4 is required.
+ * FreeBSD: /usr/ports/www/py-django (py27-django)
+ * Debian: python-django
+ * Ubuntu: **Do not use the python-django package (Django 1.3.1) in 12.04 LTS, as it is known not to work.**
+Instead, install a recent version using easy_install or pip:
+
+ $ sudo pip install django==1.4.5
+
+ * <http://vobject.skyhouseconsulting.com/>, a Python library for parsing VCards. The GUI uses this to parse the payload of RPKI Ghostbuster objects.
+ * FreeBSD: /usr/ports/deskutils/py-vobject (py27-vobject)
+ * Debian &amp; Ubuntu: python-vobject
+ * Several programs (more as time goes on) use the Python argparse module. This module is part of the Python standard library as of Python 2.7, but you may need to install it separately if you're stuck with Python 2.6. Don't do this unless you must. In cases where this is necessary, you'll probably need to use pip:
+
+ $ python -c 'import argparse' 2>/dev/null || sudo pip install argparse
+
+ * <http://pyyaml.org/>. Several of the test programs use PyYAML to parse a YAML description of a simulated allocation hierarchy to test.
+ * FreeBSD: /usr/ports/devel/py-yaml (py27-yaml)
+ * Debian &amp; Ubuntu: python-yaml
+ * <http://xmlsoft.org/XSLT/>. Some of the test code uses xsltproc, from the Gnome LibXSLT package.
+ * FreeBSD: /usr/ports/textproc/libxslt (libxslt)
+ * Debian &amp; Ubuntu: xsltproc
+ * <http://www.rrdtool.org/>. The relying party tools use this to generate graphics which you may find useful in monitoring the behavior of your validator. The rest of the software will work fine without rrdtool, you just won't be able to generate those graphics.
+ * FreeBSD: /usr/ports/databases/rrdtool (rrdtool)
+ * Debian &amp; Ubuntu: rrdtool
+ * <http://www.freshports.org/www/mod_wsgi3/> If you intend to run the GUI with wsgi, its default configuration, you will need to install mod_wsgi v3
+ * FreeBSD: /usr/ports/www/mod_wsgi3 (app22-mod_wsgi)
+ * Debian &amp; Ubuntu: libapache2-mod-wsgi
+ * <http://south.aeracode.org/> Django South 0.7.6 or later. This tool is used to ease the pain of changes to the web portal database schema.
+ * FreeBSD: /usr/ports/databases/py-south (py27-south)
+ * Debian: python-django-south
+ * Ubuntu: **Do not use the python-django-south 0.7.3 package in 12.04 LTS, as it is known not to work.**
+Instead, install a recent version using easy_install or pip:
+
+ pip install South>=0.7.6
+
+## Configure and build
+
+Once you have the prerequesite packages installed, you should be able to build
+the toolkit. cd to the top-level directory in the distribution, run the
+configure script, then run "make":
+
+ $ cd $top
+ $ ./configure
+ $ make
+
+This should automatically build everything, in the right order, including
+building a private copy of the OpenSSL libraries with the right options if
+necessary and linking the POW module against either the system OpenSSL
+libraries or the private OpenSSL libraries, as appopriate.
+
+In theory, `./configure` will complain about any required packages which might
+be missing.
+
+If you don't intend to run any of the CA tools, you can simplify the build and
+installation process by telling `./configure` that you only want to build the
+relying party tools:
+
+ $ cd $top
+ $ ./configure --disable-ca-tools
+ $ make
+
+## Testing the build
+
+Assuming the build stage completed without obvious errors, the next step is to
+run some basic regression tests.
+
+Some of the tests for the CA tools require MySQL databases to store their
+data. To set up all the databases that the tests will need, run the SQL
+commands in `ca/tests/smoketest.setup.sql`. The MySQL command line client is
+usually the easiest way to do this, eg:
+
+ $ cd $top/ca
+ $ mysql -u root -p <tests/smoketest.setup.sql
+
+To run the tests, run "make test":
+
+ $ cd $top
+ $ make test
+
+To run a more extensive set of tests on the CA tool, run "make all-tests" in
+the `ca/` directory:
+
+ $ cd $top/ca
+ $ make all-tests
+
+If nothing explodes, your installation is probably ok. Any Python backtraces
+in the output indicate a problem.
+
+## Installing
+
+Assuming the build and test phases went well, you should be ready to install
+the code. The `./configure` script attempts to figure out the "obvious" places
+to install the various programs for your platform: binaries will be installed
+in `/usr/local/bin` or `/usr/local/sbin`, Python modules will be installed
+using the standard Python distutils and should end up wherever your system
+puts locally-installed Python libraries, and so forth.
+
+The RPKI validator, rcynic, is a special case, because the install scripts may
+attempt to build a chroot jail and install rcynic in that environment. This is
+straightforward in FreeBSD, somewhat more complicated on other systems,
+primarily due to hidden dependencies on dynamic libraries.
+
+To install the code, become root (su, sudo, whatever), then run "make
+install":
+
+ $ cd $top
+ $ sudo make install
+
+## Tools you should not need to install
+
+There's a last set of tools that only developers should need, as they're only
+used when modifying schemas or regenerating the documentation. These tools are
+listed here for completeness.
+
+ * <http://www.doxygen.org/>. Doxygen in turn pulls in several other tools, notably Graphviz, pdfLaTeX, and Ghostscript.
+ * FreeBSD: /usr/ports/devel/doxygen
+ * Debian &amp; Ubuntu: doxygen
+ * <http://www.mbayer.de/html2text/>. The documentation build process uses xsltproc and html2text to dump flat text versions of a few critical documentation pages.
+ * FreeBSD: /usr/ports/textproc/html2text
+ * <http://www.thaiopensource.com/relaxng/trang.html>. Trang is used to convert RelaxNG schemas from the human-readable "compact" form to the XML form that LibXML2 understands. Trang in turn requires Java.
+ * FreeBSD: /usr/ports/textproc/trang
+ * <http://search.cpan.org/dist/SQL-Translator/>. SQL-Translator, also known as "SQL Fairy", includes code to parse an SQL schema and dump a description of it as Graphviz input. SQL Fairy in turn requires Perl.
+ * FreeBSD: /usr/ports/databases/p5-SQL-Translator
+ * <http://www.easysw.com/htmldoc/>. The documentation build process uses htmldoc to generate PDF from the project's Trac wiki.
+ * FreeBSD: /usr/ports/textproc/htmldoc
+
+## Next steps
+
+Once you've finished installing the code, you will need to configure it. Since
+CAs are generally also relying parties (if only so that they can check the
+results of their own actions), you will generally want to start by configuring
+the [relying party tools][RP], then configure the [CA tools][CA] if you're
+planning to use them.
+
+[RFC-3779]: http://www.rfc-editor.org/rfc/rfc3779.txt
+[OpenSSL]: http://www.openssl.org/
+[Subversion]: https://subversion.apache.org/
+[RP]: 05.RPKI.RP.md
+[CA]: 11.RPKI.CA.md
diff --git a/doc/manual/04.RPKI.Installation.FromSource.wiki b/doc/manual/04.RPKI.Installation.FromSource.wiki
new file mode 100644
index 00000000..f768e3ea
--- /dev/null
+++ b/doc/manual/04.RPKI.Installation.FromSource.wiki
@@ -0,0 +1,297 @@
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= Installing From Source Code =
+
+At present, the entire RPKI tools collection is a single source tree
+with a shared autoconf configuration. This may change in the future,
+but for now, this means that the build process is essentially the same
+regardless of which tools one wants to use. Some of the tools have
+dependencies on external packages, although we've tried to keep this
+to a minimum.
+
+Most of the tools require an
+[[http://www.rfc-editor.org/rfc/rfc3779.txt|RFC-3779]]-aware version
+of the [[http://www.openssl.org/|OpenSSL]] libraries. If necessary,
+the build process will generate its own private copy of the OpenSSL
+libraries for this purpose.
+
+Other than OpenSSL, most of the relying party tools are fairly
+self-contained. The CA tools have a few additional dependencies,
+described below.
+
+Note that initial development of this code has been on FreeBSD, so
+installation will probably be easiest on FreeBSD. We do, however,
+test on other platforms, such as Fedora, Ubuntu, Debian, and MacOSX.
+
+== Downloading the Source Code ==
+
+The recommended way to obtain the source code is via
+[[https://subversion.apache.org/|subversion]]. To download, do:
+
+{{{
+#!sh
+$ svn checkout https://subvert-rpki.hactrn.net/trunk/
+}}}
+
+Code snapshots are also available from https://download.rpki.net/ as
+xz-compressed tarballs.
+
+== Prerequisites ==
+
+Before attempting to build the tools from source, you will need to
+install any missing prerequisites.
+
+Some of the relying party tools and most of the CA tools are written
+in Python. Note that the Python code requires Python version 2.6 or
+2.7.
+
+On some platforms (particularly MacOSX) the simplest way to install
+some of the Python packages may be the "easy_install" or "pip" tools
+that comes with Python.
+
+Packages you will need:
+
+* You will need a C compiler. gcc is fine, others such as Clang
+ should also work.
+
+* http://www.python.org/, the Python interpreter, libraries, and
+ sources. On some platforms the Python sources (in particular, the
+ header files and libraries needed when building Python extensions)
+ are in a separate "development" package, on other platforms they are
+ all part of a single package. If you get compilation errors trying
+ to build the POW code later in the build process and the error
+ message says something about the file "Python.h" being missing, this
+ is almost certainly your problem.
+ * FreeBSD:
+ * /usr/ports/lang/python27 (python)
+ * Debian & Ubuntu:
+ * python
+ * python-dev
+ * python-setuptools
+
+* http://codespeak.net/lxml/, a Pythonic interface to the Gnome
+ LibXML2 libraries. lxml in turn requires the LibXML2 C libraries;
+ on some platforms, some of the LibXML2 utilities are packaged
+ separately and may not be pulled in as dependencies.
+ * FreeBSD: /usr/ports/devel/py-lxml (py27-lxml)
+ * Fedora: python-lxml.i386
+ * Debian & Ubuntu:
+ * python-lxml
+ * libxml2-utils
+
+* http://www.mysql.com/, MySQL client and server. How these are
+ packaged varies by platform, on some platforms the client and server
+ are separate packages, on others they might be a single monolithic
+ package, or installing the server might automatically install the
+ client as a dependency. On MacOSX you might be best off installing
+ a binary package for MySQL. The RPKI CA tools have been tested with
+ MySQL 5.0, 5.1, and 5.5; they will probably work with any other
+ reasonably recent version.
+ * FreeBSD:
+ * /usr/ports/databases/mysql55-server (mysql55-server)
+ * /usr/ports/databases/mysql55-client (mysql55-client)
+ * Debian & Ubuntu:
+ * mysql-client
+ * mysql-server
+
+* http://sourceforge.net/projects/mysql-python/, the Python "db"
+ interface to MySQL.
+ * FreeBSD: /usr/ports/databases/py-MySQLdb (py27-MySQLdb)
+ * Fedora: MySQL-python.i386
+ * Debian & Ubuntu: python-mysqldb
+
+* http://www.djangoproject.com/, the Django web user interface
+ toolkit. The GUI interface to the CA tools requires this. Django 1.4 is required.
+ * FreeBSD: /usr/ports/www/py-django (py27-django)
+ * Debian: python-django
+ * Ubuntu: **Do not use the python-django package (Django 1.3.1) in 12.04 LTS, as it is known not to work.** \\
+ Instead, install a recent version using easy_install or pip:
+ {{{
+ #!sh
+ $ sudo pip install django==1.4.5
+ }}}
+
+* http://vobject.skyhouseconsulting.com/, a Python library for parsing
+ VCards. The GUI uses this to parse the payload of RPKI Ghostbuster
+ objects.
+ * FreeBSD: /usr/ports/deskutils/py-vobject (py27-vobject)
+ * Debian & Ubuntu: python-vobject
+
+* Several programs (more as time goes on) use the Python argparse
+ module. This module is part of the Python standard library as of
+ Python 2.7, but you may need to install it separately if you're
+ stuck with Python 2.6. Don't do this unless you must. In cases
+ where this is necessary, you'll probably need to use pip:
+ {{{
+ #!sh
+ $ python -c 'import argparse' 2>/dev/null || sudo pip install argparse
+ }}}
+
+* http://pyyaml.org/. Several of the test programs use PyYAML to
+ parse a YAML description of a simulated allocation hierarchy to
+ test.
+ * FreeBSD: /usr/ports/devel/py-yaml (py27-yaml)
+ * Debian & Ubuntu: python-yaml
+
+* http://xmlsoft.org/XSLT/. Some of the test code uses xsltproc, from
+ the Gnome LibXSLT package.
+ * FreeBSD: /usr/ports/textproc/libxslt (libxslt)
+ * Debian & Ubuntu: xsltproc
+
+* http://www.rrdtool.org/. The relying party tools use this to
+ generate graphics which you may find useful in monitoring the
+ behavior of your validator. The rest of the software will work fine
+ without rrdtool, you just won't be able to generate those graphics.
+ * FreeBSD: /usr/ports/databases/rrdtool (rrdtool)
+ * Debian & Ubuntu: rrdtool
+
+* http://www.freshports.org/www/mod_wsgi3/ If you intend to run the GUI
+ with wsgi, its default configuration, you will need to install
+ mod_wsgi v3
+ * FreeBSD: /usr/ports/www/mod_wsgi3 (app22-mod_wsgi)
+ * Debian & Ubuntu: libapache2-mod-wsgi
+
+* http://south.aeracode.org/ Django South 0.7.6 or later.
+ This tool is used to ease the pain of changes to the web portal database schema.
+ * FreeBSD: /usr/ports/databases/py-south (py27-south)
+ * Debian: python-django-south
+ * Ubuntu: **Do not use the python-django-south 0.7.3 package in 12.04 LTS, as it is known not to work.** \\
+ Instead, install a recent version using easy_install or pip:
+ {{{
+ #!sh
+ pip install South>=0.7.6
+ }}}
+
+== Configure and build ==
+
+Once you have the prerequesite packages installed, you should be able
+to build the toolkit. cd to the top-level directory in the
+distribution, run the configure script, then run "make":
+
+{{{
+#!sh
+$ cd $top
+$ ./configure
+$ make
+}}}
+
+This should automatically build everything, in the right order,
+including building a private copy of the OpenSSL libraries with the
+right options if necessary and linking the POW module against either
+the system OpenSSL libraries or the private OpenSSL libraries, as
+appopriate.
+
+In theory, `./configure` will complain about any required packages which
+might be missing.
+
+If you don't intend to run any of the CA tools, you can simplify the
+build and installation process by telling `./configure` that you
+only want to build the relying party tools:
+
+{{{
+#!sh
+$ cd $top
+$ ./configure --disable-ca-tools
+$ make
+}}}
+
+== Testing the build ==
+
+Assuming the build stage completed without obvious errors, the next
+step is to run some basic regression tests.
+
+Some of the tests for the CA tools require MySQL databases to store
+their data. To set up all the databases that the tests will need, run
+the SQL commands in `ca/tests/smoketest.setup.sql`. The MySQL
+command line client is usually the easiest way to do this, eg:
+
+{{{
+#!sh
+$ cd $top/ca
+$ mysql -u root -p <tests/smoketest.setup.sql
+}}}
+
+To run the tests, run "make test":
+
+{{{
+#!sh
+$ cd $top
+$ make test
+}}}
+
+To run a more extensive set of tests on the CA tool, run "make
+all-tests" in the `ca/` directory:
+
+{{{
+#!sh
+$ cd $top/ca
+$ make all-tests
+}}}
+
+If nothing explodes, your installation is probably ok. Any Python
+backtraces in the output indicate a problem.
+
+== Installing ==
+
+Assuming the build and test phases went well, you should be ready to
+install the code. The `./configure` script attempts to figure out the
+"obvious" places to install the various programs for your platform:
+binaries will be installed in `/usr/local/bin` or `/usr/local/sbin`,
+Python modules will be installed using the standard Python distutils
+and should end up wherever your system puts locally-installed Python
+libraries, and so forth.
+
+The RPKI validator, rcynic, is a special case, because the install
+scripts may attempt to build a chroot jail and install rcynic in that
+environment. This is straightforward in FreeBSD, somewhat more
+complicated on other systems, primarily due to hidden dependencies on
+dynamic libraries.
+
+To install the code, become root (su, sudo, whatever), then run "make
+install":
+
+{{{
+#!sh
+$ cd $top
+$ sudo make install
+}}}
+
+== Tools you should not need to install ==
+
+There's a last set of tools that only developers should need, as
+they're only used when modifying schemas or regenerating the
+documentation. These tools are listed here for completeness.
+
+* http://www.doxygen.org/. Doxygen in turn pulls in several other
+ tools, notably Graphviz, pdfLaTeX, and Ghostscript.
+ * FreeBSD: /usr/ports/devel/doxygen
+ * Debian & Ubuntu: doxygen
+
+* http://www.mbayer.de/html2text/. The documentation build process
+ uses xsltproc and html2text to dump flat text versions of a few
+ critical documentation pages.
+ * FreeBSD: /usr/ports/textproc/html2text
+
+* http://www.thaiopensource.com/relaxng/trang.html. Trang is used to
+ convert RelaxNG schemas from the human-readable "compact" form to
+ the XML form that LibXML2 understands. Trang in turn requires Java.
+ * FreeBSD: /usr/ports/textproc/trang
+
+* http://search.cpan.org/dist/SQL-Translator/. SQL-Translator, also
+ known as "SQL Fairy", includes code to parse an SQL schema and dump
+ a description of it as Graphviz input. SQL Fairy in turn requires
+ Perl.
+ * FreeBSD: /usr/ports/databases/p5-SQL-Translator
+
+* http://www.easysw.com/htmldoc/. The documentation build process
+ uses htmldoc to generate PDF from the project's Trac wiki.
+ * FreeBSD: /usr/ports/textproc/htmldoc
+
+== Next steps == #Nextsteps
+
+Once you've finished installing the code, you will need to configure
+it. Since CAs are generally also relying parties (if only so that
+they can check the results of their own actions), you will generally
+want to start by configuring the [[RP|relying party tools]], then
+configure the [[CA|CA tools]] if you're planning to use them.
diff --git a/doc/manual/05.RPKI.RP.md b/doc/manual/05.RPKI.RP.md
new file mode 100644
index 00000000..bc42f6f6
--- /dev/null
+++ b/doc/manual/05.RPKI.RP.md
@@ -0,0 +1,78 @@
+# RPKI Relying Party Tools
+
+These tools implements the "relying party" role of the RPKI system, that is,
+the entity which retrieves RPKI objects from repositories, validates them, and
+uses the result of that validation process as input to other processes, such
+as BGP security.
+
+See the [CA tools][CA] for programs to help you generate RPKI objects, if you
+need to do that.
+
+The RP main tools are [rcynic][RP] and [rpki-rtr][RP], each of which is
+discussed below.
+
+The installation process sets up everything you need for a basic RPKI
+validation installation. You will, however, need to think at least briefly
+about which [RPKI trust anchors][RP] you are using, and may need to change
+these from the defaults.
+
+The installation process sets up a cron job running running [rcynic-cron][RP]
+as user "`rcynic`" once per hour at a randomly-selected minute.
+
+## rcynic
+
+rcynic is the primary validation tool. It does the actual work of RPKI
+validation: checking syntax, signatures, expiration times, and conformance to
+the profiles for RPKI objects. The other relying party programs take rcynic's
+output as their input.
+
+The installation process sets up a basic rcynic configuration. See the [rcynic
+documentation][rcynic] if you need to know more.
+
+See the [discussion of trust anchors][RP].
+
+## rpki-rtr
+
+rpki-rtr is an implementation of the rpki-rtr protocol, using rcynic's output
+as its data source. rpki-rtr includes the rpki-rtr server, a test client, and
+a utiltity for examining the content of the database rpki-rtr generates from
+the data supplied by rcynic.
+
+See the [rpki-rtr documentation][rpki-rtr] for further details.
+
+## rcynic-cron
+
+rcynic-cron is a small script to run the most common set of relying party
+tools under cron. See the [discussion of running relying party tools under
+cron][Cron] for further details.
+
+## Selecting trust anchors
+
+As in any PKI system, validation in the RPKI system requires a set of "trust
+anchors" to use as a starting point when checking certificate chains. By
+definition, trust anchors can only be selected by you, the relying party.
+
+As with most other PKI software, we supply a default set of trust anchors
+which you are welcome to use if they suit your needs. These are installed as
+part of the normal installation process, so if you don't do anything, you'll
+get these. You can, however, override this if you need something different;
+see [the rcynic documentation][rcynic] for details.
+
+Remember: It's only a trust anchor if **you** trust it. We can't make that
+decision for you.
+
+Also note that, at least for now, ARIN's trust anchor locator is absent from
+the default set of trust anchors. This is not an accident: it's the direct
+result of a deliberate policy decision by ARIN to require anyone using their
+trust anchor to [jump through legal hoops][ARIN-TAL]. If you have a problem with
+this, [complain to ARIN][ARIN-PPML]. If and when ARIN changes this policy, we will be
+happy to include their trust anchor locator along with those of the other
+RIRs.
+
+[CA]: 11.RPKI.CA.md
+[RP]: 05.RPKI.RP.md
+[rcynic]: 06.RPKI.RP.rcynic.md
+[rpki-rtr]: 07.RPKI.RP.rpki-rtr.md
+[Cron]: 08.RPKI.RP.RunningUnderCron.md
+[ARIN-TAL]: https://www.arin.net/resources/rpki/faq.html#tal
+[ARIN-PPML]: http://lists.arin.net/mailman/listinfo/arin-ppml
diff --git a/doc/manual/05.RPKI.RP.wiki b/doc/manual/05.RPKI.RP.wiki
new file mode 100644
index 00000000..a05cb2ab
--- /dev/null
+++ b/doc/manual/05.RPKI.RP.wiki
@@ -0,0 +1,81 @@
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= RPKI Relying Party Tools =
+
+These tools implements the "relying party" role of the RPKI system,
+that is, the entity which retrieves RPKI objects from repositories,
+validates them, and uses the result of that validation process as
+input to other processes, such as BGP security.
+
+See the [[CA|CA tools]] for programs to help you generate RPKI
+objects, if you need to do that.
+
+The RP main tools are [[#rcynic|rcynic]] and
+[[#rpki-rtr|rpki-rtr]], each of which is discussed below.
+
+The installation process sets up everything you need for a basic RPKI
+validation installation. You will, however, need to think at least
+briefly about which [[#trust-anchors|RPKI trust anchors]] you are
+using, and may need to change these from the defaults.
+
+The installation process sets up a cron job running running
+[[#rcynic-cron|rcynic-cron]] as user "`rcynic`" once per hour at a
+randomly-selected minute.
+
+== rcynic ==
+
+rcynic is the primary validation tool. It does the actual work of
+RPKI validation: checking syntax, signatures, expiration times, and
+conformance to the profiles for RPKI objects. The other relying party
+programs take rcynic's output as their input.
+
+The installation process sets up a basic rcynic configuration. See
+the [[wiki:doc/RPKI/RP/rcynic|rcynic documentation]] if you need to
+know more.
+
+See the [[#trust-anchors|discussion of trust anchors]].
+
+== rpki-rtr ==
+
+rpki-rtr is an implementation of the rpki-rtr protocol, using
+rcynic's output as its data source. rpki-rtr includes the rpki-rtr
+server, a test client, and a utiltity for examining the content of the
+database rpki-rtr generates from the data supplied by rcynic.
+
+See the [[wiki:doc/RPKI/RP/rpki-rtr|rpki-rtr documentation]] for
+further details.
+
+== rcynic-cron ==
+
+rcynic-cron is a small script to run the most common set of relying
+party tools under cron. See the
+[[wiki:doc/RPKI/RP/RunningUnderCron|discussion of running relying party tools under cron]]
+for further details.
+
+== Selecting trust anchors == #trust-anchors
+
+As in any PKI system, validation in the RPKI system requires a set of
+"trust anchors" to use as a starting point when checking certificate
+chains. By definition, trust anchors can only be selected by you, the
+relying party.
+
+As with most other PKI software, we supply a default set of trust
+anchors which you are welcome to use if they suit your needs. These
+are installed as part of the normal installation process, so if you
+don't do anything, you'll get these. You can, however, override this
+if you need something different; see
+[[wiki:doc/RPKI/RP/rcynic|the rcynic documentation]] for details.
+
+Remember: It's only a trust anchor if **you** trust it. We can't make
+that decision for you.
+
+Also note that, at least for now, ARIN's trust anchor locator is
+absent from the default set of trust anchors. This is not an
+accident: it's the direct result of a deliberate policy decision by
+ARIN to require anyone using their trust anchor to
+[[https://www.arin.net/resources/rpki/faq.html#tal|jump through legal hoops]].
+If you have a problem with this,
+[[http://lists.arin.net/mailman/listinfo/arin-ppml|complain to ARIN]].
+If and when ARIN changes this policy, we will be happy to include
+their trust anchor locator along with those of the other RIRs.
diff --git a/doc/manual/06.RPKI.RP.rcynic.md b/doc/manual/06.RPKI.RP.rcynic.md
new file mode 100644
index 00000000..39a05fa9
--- /dev/null
+++ b/doc/manual/06.RPKI.RP.rcynic.md
@@ -0,0 +1,624 @@
+# rcynic RPKI validator
+
+`rcynic` is the core RPKI relying party tool, and is the code which performs
+the actual RPKI validation. Most of the other relying party tools just use
+`rcynic`'s output.
+
+The name is short for "cynical rsync", because `rcynic`'s task involves an
+interleaved process of `rsync` retrieval and RPKI validation.
+
+This code was developed on FreeBSD, and has been tested most heavily on
+FreeBSD versions 6-STABLE through 8-STABLE. It is also known to work on Ubuntu
+(12.04 LTS), Debian (Wheezy) and Mac OS X (Snow Leopard). In theory it should
+run on any reasonably POSIX-like system. As far as we know, `rcynic` does not
+use any seriously non-portable features, but neither have we done a POSIX
+reference manual lookup for every function call. Please report any portability
+problems.
+
+## Don't panic
+
+`rcynic` has a lot of options, but it attempts to choose reasonable defaults
+where possible. The installation process will create a basic working `rcynic`
+configuration for you and arrange for this to run hourly under cron. If all
+goes well, this should "just work".
+
+`rcynic` has the ability to do all of its work in a chroot jail. This used to
+be the default configuration, but integrating this properly with platform-
+specific packaging systems (FreeBSD ports, `apt-get` on Ubuntu and Debian,
+etc) proved impractical. You can still get this behavior if you need it, by
+[installing from source][Source] and using the `--enable-rcynic-jail` option to
+`./configure`.
+
+The default configuration set up by `make install` and the various packaging
+systems will run `rcynic` under `cron` using the `rcynic-cron` wrapper script.
+See the [instructions for setting up your own cron jobs][Cron] if you need
+something more complicated; also see the [instructions for setting up
+hierarchical rsync][Cron] if you need to build a complex topology of rcynic
+validators.
+
+## Overview
+
+`rcynic` depends heavily on the OpenSSL `libcrypto` library, and requires a
+reasonably current version of OpenSSL with both RFC 3779 and CMS support.
+
+`rcynic` expects all certificates, CRLs, and CMS objects to be in DER format.
+`rcynic` stores its database using filenames derived from the RPKI rsync URIs
+at which the data are published.
+
+All configuration is via an OpenSSL-style configuration file, except for
+selection of the name of the configuration file itself. A few other parameters
+can also be set from the command line. The default name for the configuration
+is "`rcynic.conf`"; you can override this with the `-c` option on the command
+line. The configuration file uses OpenSSL's configuration file syntax, and you
+can set OpenSSL library configuration paramaters (eg, "engine" settings) in
+the config file as well. `rcynic`'s own configuration parameters are in a
+section called "`[rcynic]`".
+
+Most configuration parameters are optional and have defaults which should do
+something reasonable if you are running `rcynic` in a test directory. If
+you're running rcynic as a system program, perhaps under `cron` via the
+`rcynic-cron` script, you'll want to set additional parameters to tell
+`rcynic` where to find its data and where to write its output (the
+installation process sets these parameters for you). The configuration file
+itself, however, is not optional. In order for `rcynic` to do anything useful,
+your configuration file **MUST** at minimum tell `rcynic` where to find one or
+more RPKI trust anchors or trust anchor locators (TALs).
+
+### Trust anchors
+
+ * To specify a trust anchor, use the `trust-anchor` directive to name the local file containing the trust anchor.
+ * To specify a trust anchor locator (TAL), use the `trust-anchor-locator` directive to name a local file containing the trust anchor locator.
+ * To specify a directory containing trust anchors or trust anchor locators, use the `trust-anchor-directory` directive to name the directory. Files in the specified directory with names ending in `".cer"` will be processed as trust anchors, while files with names ending in `".tal"` will be processed as trust anchor locators.
+
+You may use a combination of these methods if necessary.
+
+Trust anchors are represented as DER-formatted X.509 self-signed certificate
+objects, but in practice trust anchor locators are more common, as they reduce
+the amount of locally configured data to the bare minimum and allow the trust
+anchor itself to be updated without requiring reconfiguration of validators
+like rcynic. A trust anchor locator is a file in the format specified in
+[RFC-6490][], consisting of the rsync URI of the trust anchor followed by the
+Base64 encoding of the trust anchor's public key.
+
+Strictly speaking, trust anchors do not need to be self-signed, but many
+programs (including OpenSSL) assume that trust anchors will be self-signed.
+See the `allow-non-self-signed-trust-anchor` configuration option if you need
+to use a non-self-signed trust anchor, but be warned that the results, while
+technically correct, may not be useful.
+
+See the `make-tal.sh` script in this directory if you need to generate your
+own TAL file for a trust anchor.
+
+As of this writing, there still is no single global trust anchor for the RPKI
+system, so you have to provide separate trust anchors for each Regional
+Internet Registry (RIR) which is publishing RPKI data. The installation
+process installs the ones it knows about.
+
+Example of a minimal config file specifying nothing but trust anchor locators:
+
+ [rcynic]
+
+ trust-anchor-locator.0 = trust-anchors/apnic.tal
+ trust-anchor-locator.1 = trust-anchors/ripe.tal
+ trust-anchor-locator.2 = trust-anchors/afrinic.tal
+ trust-anchor-locator.3 = trust-anchors/lacnic.tal
+
+Eventually, this should all be collapsed into a single trust anchor, so that
+relying parties don't need to sort this out on their own, at which point the
+above configuration could become something like:
+
+ [rcynic]
+
+ trust-anchor-locator = trust-anchors/iana.tal
+
+### Output directories
+
+By default, `rcynic` uses two writable directory trees:
+
+`unauthenticated`::
+
+> Raw data fetched via `rsync`. In order to take full advantage of `rsync`'s
+optimized transfers, you should preserve and reuse this directory across
+`rcynic` runs, so that `rcynic` need not re-fetch data that have not changed.
+
+`authenticated`::
+
+> Data which `rcynic` has checked. This is the real output of the validation
+process.
+
+`authenticated` is really a symbolic link to a directory with a name of the
+form "`authenticated`._&lt;timestamp&gt;_", where _&lt;timestamp&gt;_ is an
+ISO 8601 timestamp like `2001-04-01T01:23:45Z`. `rcynic` creates a new
+timestamped directory every time it runs, and moves the symbolic link as an
+atomic operation when the validation process completes. The intent is that
+`authenticated` always points to the most recent usable validation results, so
+that programs which use `rcynic`'s output don't need to worry about whether an
+`rcynic` run is in progress.
+
+`rcynic` installs trust anchors specified via the `trust-anchor-locator`
+directive in the `unauthenticated` tree just like any other fetched object,
+and copies them into the `authenticated` trees just like any other object once
+they pass `rcynic`'s checks.
+
+`rcynic` copies trust anchors specified via the `trust-anchor` directive into
+the top level directory of the `authenticated` tree with filenames of the form
+_&lt;xxxxxxxx&gt;_`.`_&lt;n&gt;_`.cer`, where _&lt;xxxxxxxx&gt;_ and
+_&lt;n&gt;_ are the OpenSSL object name hash and index within the resulting
+virtual hash bucket, respectively. These are the same values that OpenSSL's
+`c_hash` Perl script would produce. The reason for this naming scheme is that
+these trust anchors, by definition, are not fetched automatically, and thus do
+not really have publication URIs in the sense that every other object in these
+trees do. So `rcynic` uses a naming scheme which insures:
+
+ * that each trust anchor has a unique name within the output tree and
+ * that trust anchors cannot be confused with certificates: trust anchors always go in the top level of the tree, data fetched via rsync always go in subdirectories.
+
+Trust anchors and trust anchor locators taken from the directory named by the
+`trust-anchor-directory` directive will follow the same naming scheme trust
+anchors and trust anchor locators specified via the `trust-anchor` and `trust-
+anchor-locator` directives, respectively.
+
+## Usage and configuration
+
+### Logging levels
+
+`rcynic` has its own system of logging levels, similar to what `syslog()`
+uses, but customized to the specific task `rcynic` performs.
+
+`log_sys_err` | Error from operating system or library
+---|---
+`log_usage_err` | Bad usage (local configuration error)
+`log_data_err` | Bad data (broken certificates or CRLs)
+`log_telemetry` | Normal chatter about rcynic's progress
+`log_verbose` | Extra verbose chatter
+`log_debug` | Only useful when debugging
+
+### Command line options
+
+`-c` _configfile_ | Path to configuration file (default: `rcynic.conf`)
+---|---
+`-l` _loglevel_ | Logging level (default: `log_data_err`)
+`-s` | Log via syslog
+`-e` | Log via stderr when also using syslog
+`-j` | Start-up jitter interval (see below; default: `600`)
+`-V` | Print rcynic's version to standard output and exit
+`-x` | Path to XML "summary" file (see below; no default)
+
+## Configuration file reference
+
+`rcynic` uses the OpenSSL `libcrypto` configuration file mechanism. All
+`libcrypto` configuration options (eg, for engine support) are available. All
+`rcynic`-specific options are in the "`[rcynic]`" section. You **MUST** have a
+configuration file in order for `rcynic` to do anything useful, as the
+configuration file is the only way to list your trust anchors.
+
+### authenticated
+
+Path to output directory (where `rcynic` should place objects it has been able
+to validate).
+
+Default: `rcynic-data/authenticated`
+
+### unauthenticated
+
+Path to directory where `rcynic` should store unauthenticatd data retrieved
+via `rsync`. Unless something goes horribly wrong, you want `rcynic` to
+preserve and reuse this directory across runs to minimize the network traffic
+necessary to bring your repository mirror up to date.
+
+Default: `rcynic-data/unauthenticated`
+
+### rsync-timeout
+
+How long (in seconds) to let `rsync` run before terminating the `rsync`
+process, or zero for no timeout. You want this timeout to be fairly long, to
+avoid terminating `rsync` connections prematurely. It's present to let you
+defend against evil `rsync` server operators who try to tarpit your connection
+as a form of denial of service attack on `rcynic`.
+
+Default: `300`
+
+### max-parallel-fetches
+
+Upper limit on the number of copies of `rsync` that `rcynic` is allowed to run
+at once. Used properly, this can speed up synchronization considerably when
+fetching from repositories built with sub-optimal tree layouts or when dealing
+with unreachable repositories. Used improperly, this option can generate
+excessive load on repositories, cause synchronization to be interrupted by
+firewalls, and generally creates create a public nuisance. Use with caution.
+
+As of this writing, values in the range 2-4 are reasonably safe. Values above
+10 have been known to cause problems.
+
+`rcynic` can't really detect all of the possible problems created by excessive
+values of this parameter, but if rcynic's report shows that both successful
+retrivial and skipped retrieval from the same repository host, that's a pretty
+good hint that something is wrong, and an excessive value here is a good first
+guess as to the cause.
+
+Default: `1`
+
+### rsync-program
+
+Path to the rsync program.
+
+Default: `rsync`, but you should probably set this variable rather than just
+trusting the `PATH` environment variable to be set correctly.
+
+### log-level
+
+Same as `-l` option on command line. Command line setting overrides config
+file setting.
+
+Default: `log_log_err`
+
+### use-syslog
+
+Same as `-s` option on command line. Command line setting overrides config
+file setting.
+
+Values: `true` or `false`.
+
+Default: `false`
+
+### use-stderr
+
+Same as -e option on command line. Command line setting overrides config file
+setting.
+
+Values: `true` or `false`.
+
+Default: `false`, but if neither `use-syslog` nor `use-stderr` is set, log
+output goes to `stderr`.
+
+### syslog-facility
+
+Syslog facility to use.
+
+Default: local0
+
+### syslog-priority-xyz
+
+(where xyz is an rcynic logging level, above)
+
+Override the syslog priority value to use when logging messages at this rcynic
+level.
+
+Defaults:
+
+`syslog-priority-log_sys_err` | `err`
+---|---
+`syslog-priority-log_usage_err` | `err`
+`syslog-priority-log_data_err` | `notice`
+`syslog-priority-log_telemetry` | `info`
+`syslog-priority-log_verbose` | `info`
+`syslog-priority-log_debug` | `debug`
+
+### jitter
+
+Startup jitter interval, same as `-j` option on command line. Jitter interval,
+specified in number of seconds. `rcynic` will pick a random number within the
+interval from zero to this value, and will delay for that many seconds on
+startup. The purpose of this is to spread the load from large numbers of
+`rcynic` clients all running under cron with synchronized clocks, in
+particular to avoid hammering the global RPKI `rsync` servers into the ground
+at midnight UTC.
+
+Default: `600`
+
+### lockfile
+
+Name of lockfile, or empty for no lock. If you run `rcynic` directly under
+cron, you should use this parameter to set a lockfile so that successive
+instances of rcynic don't stomp on each other. If you run `rcynic` under
+`rcynic-cron`, you don't need to touch this, as `rcynic-cron` maintains its
+own lock.
+
+Default: no lock
+
+### xml-summary
+
+Enable output of a per-host summary at the end of an `rcynic` run in XML
+format.
+
+Value: filename to which XML summary should be written; "-" will send XML
+summary to standard output.
+
+Default: no XML summary.
+
+### allow-stale-crl
+
+Allow use of CRLs which are past their `nextUpdate` timestamp. This is usually
+harmless, but since there are attack scenarios in which this is the first
+warning of trouble, it's configurable.
+
+Values: `true` or `false`.
+
+Default: `true`
+
+### prune
+
+Clean up old files corresponding to URIs that `rcynic` did not see at all
+during this run. `rcynic` invokes `rsync` with the `--delete` option to clean
+up old objects from collections that `rcynic` revisits, but if a URI changes
+so that `rcynic` never visits the old collection again, old files will remain
+in the local mirror indefinitely unless you enable this option.
+
+Note: Pruning only happens when `run-rsync` is true. When the `run-rsync`
+option is false, pruning is not done regardless of the setting of the prune
+option option.
+
+Values: `true` or `false`.
+
+Default: `true`
+
+### allow-stale-manifest
+
+Allow use of manifests which are past their `nextUpdate` timestamp. This is
+probably harmless, but since it may be an early warning of problems, it's
+configurable.
+
+Values: `true` or `false`.
+
+Default: `true`
+
+### require-crl-in-manifest
+
+Reject publication point if manifest doesn't list the CRL that covers the
+manifest EE certificate.
+
+Values: `true` or `false`.
+
+Default: `false`
+
+### allow-object-not-in-manifest
+
+Allow use of otherwise valid objects which are not listed in the manifest.
+This is not supposed to happen, but is probably harmless.
+
+Enabling this does, however, often result in noisier logs, as it increases the
+chance that `rcynic` will attempt to validate data which a CA removed from the
+manifest but did not completely remove and revoke from the repository.
+
+Values: `true` or `false`
+
+Default: `false`
+
+### allow-digest-mismatch
+
+Allow use of otherwise valid objects which are listed in the manifest with a
+different digest value.
+
+You probably don't want to touch this.
+
+Values: `true` or `false`
+
+Default: `true`
+
+### allow-crl-digest-mismatch
+
+Allow processing to continue on a publication point whose manifest lists a
+different digest value for the CRL than the digest of the CRL we have in hand.
+
+You probably don't want to touch this.
+
+Values: `true` or `false`
+
+Default: `true`
+
+### allow-non-self-signed-trust-anchor
+
+Experimental. Attempts to work around OpenSSL's strong preference for self-
+signed trust anchors.
+
+We're not going to explain this one in any further detail. If you really want
+to know what it does, Use The Source, Luke.
+
+**Do not even consider enabling this option unless you are intimately familiar with both X.509 and the internals of OpenSSL's `X509_verify_cert()` function and really know what you are doing.**
+
+Values: `true` or `false`.
+
+Default: `false`
+
+### run-rsync
+
+Whether to run `rsync` to fetch data. You don't generally want to change this
+except when building complex topologies where `rcynic` running on one set of
+machines acts as aggregators for another set of validators. A large ISP might
+want to build such a topology so that they could have a local validation cache
+in each POP while minimizing load on the global repository system and
+maintaining some degree of internal consistency between POPs. In such cases,
+one might want the `rcynic` instances in the POPs to validate data fetched
+from the aggregators via an external process, without the POP `rcynic`
+instances attempting to fetch anything themselves.
+
+Values: `true` or `false`.
+
+Default: `true`
+
+### use-links
+
+Whether to use hard links rather than copying valid objects from the
+unauthenticated to authenticated tree. Using links is slightly more fragile
+(anything that stomps on the unauthenticated file also stomps on the
+authenticated file) but is a bit faster and reduces the number of inodes
+consumed by a large data collection. At the moment, copying is the default
+behavior, but this may change in the future.
+
+Values: `true` or `false`.
+
+Default: `false`
+
+### rsync-early
+
+Whether to force `rsync` to run even when we have a valid manifest for a
+particular publication point and its `nextUpdate` time has not yet passed.
+
+This is an experimental feature, and currently defaults to **true**, which is
+the old behavior (running `rsync` regardless of whether we have a valid cached
+manifest). This default may change once we have more experience with
+`rcynic`'s behavior when run with this option set to `false`.
+
+Skipping the `rsync` fetch when we already have a valid cached manifest can
+significantly reduce the total number of `rsync` connections we need to make,
+and significantly reduce the load that each validator places on the
+authoritative publication servers. As with any caching scheme, however, there
+are some potential problems involved with not fetching the latest data, and we
+don't yet have enough experience with this option to know how this will play
+out in practice, which is why this is still considered experimental.
+
+Values: `true` or `false`
+
+Default: `true` (but may change in the future)
+
+### trust-anchor
+
+Specify one RPKI trust anchor, represented as a local file containing an X.509
+certificate in DER format. Value of this option is the pathname of the file.
+
+**No default**.
+
+### trust-anchor-locator
+
+Specify one RPKI trust anchor locator, represented as a local file in the
+format specified in [RFC-6490][]. This a simple text format containing an
+rsync URI and the RSA public key of the X.509 object specified by the URI; the
+first line of the file is the URI, the remainder is the public key in Base64
+encoded DER format.
+
+Value of this option is the pathname of the file.
+
+**No default**.
+
+### trust-anchor-directory
+
+Specify a directory containing trust anchors, trust anchor locators, or both.
+Trust anchors in such a directory must have filenames ending in "`.cer`";
+trust anchor locators in such a directory must have names ending in "`.tal`";
+any other files will be skipped.
+
+This directive is an alternative to using the `trust-anchor` and trust-anchor-
+locator` directives. This is probably easier to use than the other trust
+anchor directives when dealing with a collection of trust anchors. This may
+change on that promised day when we have only a single global trust anchor to
+deal with, but we're not there yet.
+
+**No default**.
+
+## Post-processing rcynic's XML output
+
+The distribution includes several post-processors for the XML output `rcynic`
+writes describing the actions it has taken and the validation status of the
+objects it has found.
+
+### rcynic-html
+
+`rcynic-html` converts `rcynic`'s XML output into a collection of HTML pages
+summarizing the results, noting problems encountered, and showing some history
+of `rsync` transfer times and repository object counts in graphical form.
+
+`rcynic-cron` runs `rcynic-html` automatically, immediately after running
+`rcynic`. If for some reason you need to run `rcynic-html` by hand, the
+command syntax is:
+
+ $ rcynic-html rcynic.xml /web/server/directory/
+
+`rcynic-html` will write a collection of HTML and image files to the specified
+output directory, along with a set of RRD databases. `rcynic-html` will create
+the output directory if necessary.
+
+`rcynic-html` requires [`rrdtool`][rrdtool], a specialized database and graphing
+engine designed for this sort of work. You can run `rcynic-html` without
+`rrdtool` by giving it the `--no-show-graphs` option, but the result won't be
+as useful.
+
+`rcynic-html` gets its idea of where to find the `rrdtool` program from
+autoconf, which usually works. If for some reason it doesn't work in your
+environment, you will need to tell `rcynic-html` where to find `rrdtool`,
+using the `--rrdtool-binary` option:
+
+ $ rcynic-html --rrdtoolbinary /some/where/rrdtool rcynic.xml /web/server/directory/
+
+### rcynic.xsl
+
+`rcynic.xsl` was an earlier attempt at the same kind of HTML output as
+[rcynic-html][rcynic] generates. XSLT was a convenient language for our initial
+attempts at this, but as the processing involved got more complex, it became
+obvious that we needed a general purpose programming language.
+
+If for some reason XSLT works better in your environment than Python, you
+might find this stylesheet to be a useful starting point, but be warned that
+it's significantly slower than `rcynic-html`, lacks many features, and is no
+longer under development.
+
+### rcynic-text
+
+`rcynic-text` provides a quick flat text summary of validation results. This
+is useful primarily in test scripts ([smoketest][CA] uses it).
+
+Usage:
+
+ $ rcynic-text rcynic.xml
+
+### validation_status
+
+`validation_status` provides a flat text translation of the detailed
+validation results. This is useful primarily for checking the detailed status
+of some particular object or set of objects, perhaps using a program like
+`grep` or `awk` to filter `validation_status`'s output.
+
+Usage:
+
+ $ validation_status rcynic.xml
+ $ validation_status rcynic.xml | fgrep rpki.misbehaving.org
+ $ validation_status rcynic.xml | fgrep object_rejected
+
+### rcynic-svn
+
+`rcynic-svn` is a tool for archiving `rcynic`'s results in a [Subversion][]
+repository. `rcynic-svn` is not integrated into `rcynic-cron`, because this is
+not something that every relying party is going to want to do. However, for
+relying parties who want to analyze `rcynic`'s output over a long period of
+time, `rcynic-svn` may provide a useful starting point starting point.
+
+To use `rcynic-svn`, you first must set up a Subversion repository and check
+out a working directory:
+
+ $ svnadmin create /some/where/safe/rpki-archive
+ $ svn co file:///some/where/safe/rpki-archive /some/where/else/rpki-archive
+
+The name can be anything you like, in this example we call it "`rpki-
+archive`". The above sequence creates the repository, then checks out an empty
+working directory `/some/where/else/rpki-archive`.
+
+The repository does not need to be on the same machine as the working
+directory, but it probably should be for simplicity unless you have some
+strong need to put it elsewhere.
+
+Once you have the repository and working directory set up, you need to arrange
+for `rcynic-svn` to be run after each `rcynic` run whose results you want to
+archive. One way to do this would be to run `rcynic-svn` in the same cron job
+as `rcynic-cron`, immediately after `rcynic-cron` and specifying the same lock
+file that `rcynic-cron` uses.
+
+Sample usage, assuming that `rcynic`'s data is in the usual place:
+
+ $ rcynic-svn --lockfile /var/rcynic/data/lock \
+ /var/rcynic/data/authenticated \
+ /var/rcynic/data/unauthenticated \
+ /var/rcynic/data/rcynic.xml \
+ /some/where/else/rpki-archive
+
+where the last argument is the name of the Subversion working directory and
+the other arguments are the names of those portions of `rcynic`'s output which
+you wish to archive. Generally, the above set (`authenticated`,
+`unauthenticated`, and `rcynic.xml`) are the ones you want, but feel free to
+experiment.
+
+[Source]: 04.RPKI.Installation.FromSource.md
+[Cron]: 08.RPKI.RP.RunningUnderCron.md
+[RFC-6490]: http://www.rfc-editor.org/rfc/rfc6490.txt
+[rrdtool]: http://www.rrdtool.org/
+[rcynic]: 06.RPKI.RP.rcynic.md
+[CA]: 11.RPKI.CA.md
+[Subversion]: http://subversion.apache.org/
diff --git a/doc/manual/06.RPKI.RP.rcynic.wiki b/doc/manual/06.RPKI.RP.rcynic.wiki
new file mode 100644
index 00000000..6dc30ebe
--- /dev/null
+++ b/doc/manual/06.RPKI.RP.rcynic.wiki
@@ -0,0 +1,690 @@
+= rcynic RPKI validator =
+
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+`rcynic` is the core RPKI relying party tool, and is the code which
+performs the actual RPKI validation. Most of the other relying party
+tools just use `rcynic`'s output.
+
+The name is short for "cynical rsync", because `rcynic`'s task involves
+an interleaved process of `rsync` retrieval and RPKI validation.
+
+This code was developed on FreeBSD, and has been tested most heavily
+on FreeBSD versions 6-STABLE through 8-STABLE. It is also known to
+work on Ubuntu (12.04 LTS), Debian (Wheezy) and Mac OS X (Snow
+Leopard). In theory it should run on any reasonably POSIX-like
+system. As far as we know, `rcynic` does not use any seriously
+non-portable features, but neither have we done a POSIX reference
+manual lookup for every function call. Please report any portability
+problems.
+
+== Don't panic ==
+
+`rcynic` has a lot of options, but it attempts to choose reasonable
+defaults where possible. The installation process will create a basic
+working `rcynic` configuration for you and arrange for this to run
+hourly under cron. If all goes well, this should "just work".
+
+`rcynic` has the ability to do all of its work in a chroot jail. This
+used to be the default configuration, but integrating this properly
+with platform-specific packaging systems (FreeBSD ports, `apt-get` on
+Ubuntu and Debian, etc) proved impractical. You can still get this
+behavior if you need it, by
+[[wiki:doc/RPKI/Installation/FromSource|installing from source]]
+and using the `--enable-rcynic-jail` option to `./configure`.
+
+The default configuration set up by `make install` and the various
+packaging systems will run `rcynic` under `cron` using the `rcynic-cron`
+wrapper script. See the
+[[wiki:doc/RPKI/RP/RunningUnderCron|instructions for setting up your own cron jobs]]
+if you need something more complicated; also see the
+[[wiki:doc/RPKI/RP/RunningUnderCron|instructions for setting up hierarchical rsync]]
+if you need to build a complex topology of rcynic validators.
+
+== Overview ==
+
+`rcynic` depends heavily on the OpenSSL `libcrypto` library, and
+requires a reasonably current version of OpenSSL with both RFC 3779
+and CMS support.
+
+`rcynic` expects all certificates, CRLs, and CMS objects to be in DER
+format. `rcynic` stores its database using filenames derived from the
+RPKI rsync URIs at which the data are published.
+
+All configuration is via an OpenSSL-style configuration file, except
+for selection of the name of the configuration file itself. A few
+other parameters can also be set from the command line. The default
+name for the configuration is "`rcynic.conf`"; you can override this
+with the `-c` option on the command line. The configuration file uses
+OpenSSL's configuration file syntax, and you can set OpenSSL library
+configuration paramaters (eg, "engine" settings) in the config file as
+well. `rcynic`'s own configuration parameters are in a section called
+"`[rcynic]`".
+
+Most configuration parameters are optional and have defaults which
+should do something reasonable if you are running `rcynic` in a test
+directory. If you're running rcynic as a system program, perhaps
+under `cron` via the `rcynic-cron` script, you'll want to set
+additional parameters to tell `rcynic` where to find its data and
+where to write its output (the installation process sets these
+parameters for you). The configuration file itself, however, is not
+optional. In order for `rcynic` to do anything useful, your
+configuration file **MUST** at minimum tell `rcynic` where to find one
+or more RPKI trust anchors or trust anchor locators (TALs).
+
+=== Trust anchors ===
+
+* To specify a trust anchor, use the `trust-anchor` directive to
+ name the local file containing the trust anchor.
+
+* To specify a trust anchor locator (TAL), use the
+ `trust-anchor-locator` directive to name a local file containing
+ the trust anchor locator.
+
+* To specify a directory containing trust anchors or trust anchor
+ locators, use the `trust-anchor-directory` directive to name the
+ directory. Files in the specified directory with names ending in
+ `".cer"` will be processed as trust anchors, while files with names
+ ending in `".tal"` will be processed as trust anchor locators.
+
+You may use a combination of these methods if necessary.
+
+Trust anchors are represented as DER-formatted X.509 self-signed
+certificate objects, but in practice trust anchor locators are more
+common, as they reduce the amount of locally configured data to the
+bare minimum and allow the trust anchor itself to be updated without
+requiring reconfiguration of validators like rcynic. A trust anchor
+locator is a file in the format specified in
+[[http://www.rfc-editor.org/rfc/rfc6490.txt|RFC-6490]], consisting of
+the rsync URI of the trust anchor followed by the Base64 encoding of
+the trust anchor's public key.
+
+Strictly speaking, trust anchors do not need to be self-signed, but
+many programs (including OpenSSL) assume that trust anchors will be
+self-signed. See the `allow-non-self-signed-trust-anchor`
+configuration option if you need to use a non-self-signed trust
+anchor, but be warned that the results, while technically correct, may
+not be useful.
+
+See the `make-tal.sh` script in this directory if you need to generate
+your own TAL file for a trust anchor.
+
+As of this writing, there still is no single global trust anchor for
+the RPKI system, so you have to provide separate trust anchors for
+each Regional Internet Registry (RIR) which is publishing RPKI data.
+The installation process installs the ones it knows about.
+
+Example of a minimal config file specifying nothing but trust anchor
+locators:
+
+{{{
+#!ini
+[rcynic]
+
+trust-anchor-locator.0 = trust-anchors/apnic.tal
+trust-anchor-locator.1 = trust-anchors/ripe.tal
+trust-anchor-locator.2 = trust-anchors/afrinic.tal
+trust-anchor-locator.3 = trust-anchors/lacnic.tal
+}}}
+
+Eventually, this should all be collapsed into a single trust anchor,
+so that relying parties don't need to sort this out on their own, at
+which point the above configuration could become something like:
+
+{{{
+#!ini
+[rcynic]
+
+trust-anchor-locator = trust-anchors/iana.tal
+}}}
+
+=== Output directories ===
+
+By default, `rcynic` uses two writable directory trees:
+
+`unauthenticated`::
+
+ Raw data fetched via `rsync`. In order to take full advantage
+ of `rsync`'s optimized transfers, you should preserve and reuse
+ this directory across `rcynic` runs, so that `rcynic` need not
+ re-fetch data that have not changed.
+
+`authenticated`::
+
+ Data which `rcynic` has checked. This is the real output of
+ the validation process.
+
+`authenticated` is really a symbolic link to a directory with a name of
+the form "`authenticated`.//<timestamp>//", where //<timestamp>// is an
+ISO 8601 timestamp like `2001-04-01T01:23:45Z`. `rcynic` creates a new
+timestamped directory every time it runs, and moves the symbolic link
+as an atomic operation when the validation process completes. The
+intent is that `authenticated` always points to the most recent usable
+validation results, so that programs which use `rcynic`'s output don't
+need to worry about whether an `rcynic` run is in progress.
+
+`rcynic` installs trust anchors specified via the `trust-anchor-locator`
+directive in the `unauthenticated` tree just like any other fetched
+object, and copies them into the `authenticated` trees just like any
+other object once they pass `rcynic`'s checks.
+
+`rcynic` copies trust anchors specified via the `trust-anchor` directive
+into the top level directory of the `authenticated` tree with filenames
+of the form //<xxxxxxxx>//`.`//<n>//`.cer`, where //<xxxxxxxx>// and
+//<n>// are the OpenSSL object name hash and index within the
+resulting virtual hash bucket, respectively. These are the same
+values that OpenSSL's `c_hash` Perl script would produce. The reason
+for this naming scheme is that these trust anchors, by definition, are
+not fetched automatically, and thus do not really have publication
+URIs in the sense that every other object in these trees do. So
+`rcynic` uses a naming scheme which insures:
+
+* that each trust anchor has a unique name within the output tree and
+
+* that trust anchors cannot be confused with certificates: trust
+ anchors always go in the top level of the tree, data fetched via
+ rsync always go in subdirectories.
+
+Trust anchors and trust anchor locators taken from the directory named
+by the `trust-anchor-directory` directive will follow the same naming
+scheme trust anchors and trust anchor locators specified via the
+`trust-anchor` and `trust-anchor-locator` directives, respectively.
+
+== Usage and configuration ==
+
+=== Logging levels ===
+
+`rcynic` has its own system of logging levels, similar to what
+`syslog()` uses, but customized to the specific task `rcynic` performs.
+
+||`log_sys_err` ||Error from operating system or library ||
+||`log_usage_err` ||Bad usage (local configuration error) ||
+||`log_data_err` ||Bad data (broken certificates or CRLs) ||
+||`log_telemetry` ||Normal chatter about rcynic's progress ||
+||`log_verbose` ||Extra verbose chatter ||
+||`log_debug` ||Only useful when debugging ||
+
+=== Command line options ===
+
+||`-c` //configfile// ||Path to configuration file (default: `rcynic.conf`) ||
+||`-l` //loglevel// ||Logging level (default: `log_data_err`) ||
+||`-s` ||Log via syslog ||
+||`-e` ||Log via stderr when also using syslog ||
+||`-j` ||Start-up jitter interval (see below; default: `600`) ||
+||`-V` ||Print rcynic's version to standard output and exit ||
+||`-x` ||Path to XML "summary" file (see below; no default) ||
+
+== Configuration file reference ==
+
+`rcynic` uses the OpenSSL `libcrypto` configuration file mechanism.
+All `libcrypto` configuration options (eg, for engine support) are
+available. All `rcynic`-specific options are in the "`[rcynic]`" section.
+You **MUST** have a configuration file in order for `rcynic` to do
+anything useful, as the configuration file is the only way to list
+your trust anchors.
+
+=== authenticated ===
+
+Path to output directory (where `rcynic` should place objects it
+has been able to validate).
+
+Default: `rcynic-data/authenticated`
+
+=== unauthenticated ===
+
+Path to directory where `rcynic` should store unauthenticatd
+data retrieved via `rsync`. Unless something goes horribly
+wrong, you want `rcynic` to preserve and reuse this directory
+across runs to minimize the network traffic necessary to bring
+your repository mirror up to date.
+
+Default: `rcynic-data/unauthenticated`
+
+=== rsync-timeout ===
+
+How long (in seconds) to let `rsync` run before terminating the
+`rsync` process, or zero for no timeout. You want this timeout
+to be fairly long, to avoid terminating `rsync` connections
+prematurely. It's present to let you defend against evil
+`rsync` server operators who try to tarpit your connection as a
+form of denial of service attack on `rcynic`.
+
+Default: `300`
+
+=== max-parallel-fetches ===
+
+Upper limit on the number of copies of `rsync` that `rcynic` is
+allowed to run at once. Used properly, this can speed up
+synchronization considerably when fetching from repositories
+built with sub-optimal tree layouts or when dealing with
+unreachable repositories. Used improperly, this option can
+generate excessive load on repositories, cause synchronization
+to be interrupted by firewalls, and generally creates create a
+public nuisance. Use with caution.
+
+As of this writing, values in the range 2-4 are reasonably
+safe. Values above 10 have been known to cause problems.
+
+`rcynic` can't really detect all of the possible problems
+created by excessive values of this parameter, but if rcynic's
+report shows that both successful retrivial and skipped
+retrieval from the same repository host, that's a pretty good
+hint that something is wrong, and an excessive value here is a
+good first guess as to the cause.
+
+Default: `1`
+
+=== rsync-program ===
+
+Path to the rsync program.
+
+Default: `rsync`, but you should probably set this variable rather
+than just trusting the `PATH` environment variable to be set
+correctly.
+
+=== log-level ===
+
+Same as `-l` option on command line. Command line setting overrides
+config file setting.
+
+Default: `log_log_err`
+
+=== use-syslog ===
+
+Same as `-s` option on command line. Command line setting overrides
+config file setting.
+
+Values: `true` or `false`.
+
+Default: `false`
+
+=== use-stderr ===
+
+Same as -e option on command line. Command line setting overrides
+config file setting.
+
+Values: `true` or `false`.
+
+Default: `false`, but if neither `use-syslog` nor `use-stderr` is set,
+log output goes to `stderr`.
+
+=== syslog-facility ===
+
+Syslog facility to use.
+
+Default: local0
+
+=== syslog-priority-xyz ===
+
+(where xyz is an rcynic logging level, above)
+
+Override the syslog priority value to use when
+logging messages at this rcynic level.
+
+Defaults:
+
+||`syslog-priority-log_sys_err` ||`err` ||
+||`syslog-priority-log_usage_err` ||`err` ||
+||`syslog-priority-log_data_err` ||`notice` ||
+||`syslog-priority-log_telemetry` ||`info` ||
+||`syslog-priority-log_verbose` ||`info` ||
+||`syslog-priority-log_debug` ||`debug` ||
+
+=== jitter ===
+
+Startup jitter interval, same as `-j` option on command line. Jitter
+interval, specified in number of seconds. `rcynic` will pick a random
+number within the interval from zero to this value, and will delay for
+that many seconds on startup. The purpose of this is to spread the
+load from large numbers of `rcynic` clients all running under cron
+with synchronized clocks, in particular to avoid hammering the global
+RPKI `rsync` servers into the ground at midnight UTC.
+
+Default: `600`
+
+=== lockfile ===
+
+Name of lockfile, or empty for no lock. If you run `rcynic` directly
+under cron, you should use this parameter to set a lockfile so that
+successive instances of rcynic don't stomp on each other. If you run
+`rcynic` under `rcynic-cron`, you don't need to touch this, as
+`rcynic-cron` maintains its own lock.
+
+Default: no lock
+
+=== xml-summary ===
+
+Enable output of a per-host summary at the end of an `rcynic`
+run in XML format.
+
+Value: filename to which XML summary should be written; "-" will send
+XML summary to standard output.
+
+Default: no XML summary.
+
+=== allow-stale-crl ===
+
+Allow use of CRLs which are past their `nextUpdate` timestamp.
+This is usually harmless, but since there are attack scenarios
+in which this is the first warning of trouble, it's
+configurable.
+
+Values: `true` or `false`.
+
+Default: `true`
+
+=== prune ===
+
+Clean up old files corresponding to URIs that `rcynic` did not
+see at all during this run. `rcynic` invokes `rsync` with the
+`--delete` option to clean up old objects from collections
+that `rcynic` revisits, but if a URI changes so that `rcynic`
+never visits the old collection again, old files will remain
+in the local mirror indefinitely unless you enable this
+option.
+
+Note: Pruning only happens when `run-rsync` is true. When the
+`run-rsync` option is false, pruning is not done regardless of
+the setting of the prune option option.
+
+Values: `true` or `false`.
+
+Default: `true`
+
+=== allow-stale-manifest ===
+
+Allow use of manifests which are past their `nextUpdate`
+timestamp. This is probably harmless, but since it may be an
+early warning of problems, it's configurable.
+
+Values: `true` or `false`.
+
+Default: `true`
+
+=== require-crl-in-manifest ===
+
+Reject publication point if manifest doesn't list the CRL that
+covers the manifest EE certificate.
+
+Values: `true` or `false`.
+
+Default: `false`
+
+=== allow-object-not-in-manifest ===
+
+Allow use of otherwise valid objects which are not listed in the
+manifest. This is not supposed to happen, but is probably harmless.
+
+Enabling this does, however, often result in noisier logs, as it
+increases the chance that `rcynic` will attempt to validate data which a
+CA removed from the manifest but did not completely remove and revoke
+from the repository.
+
+Values: `true` or `false`
+
+Default: `false`
+
+=== allow-digest-mismatch ===
+
+Allow use of otherwise valid objects which are listed in the
+manifest with a different digest value.
+
+You probably don't want to touch this.
+
+Values: `true` or `false`
+
+Default: `true`
+
+=== allow-crl-digest-mismatch ===
+
+Allow processing to continue on a publication point whose
+manifest lists a different digest value for the CRL than the
+digest of the CRL we have in hand.
+
+You probably don't want to touch this.
+
+Values: `true` or `false`
+
+Default: `true`
+
+=== allow-non-self-signed-trust-anchor ===
+
+Experimental. Attempts to work around OpenSSL's strong
+preference for self-signed trust anchors.
+
+We're not going to explain this one in any further detail. If you
+really want to know what it does, Use The Source, Luke.
+
+**Do not even consider enabling this option unless you are intimately
+familiar with both X.509 and the internals of OpenSSL's
+`X509_verify_cert()` function and really know what you are doing.**
+
+Values: `true` or `false`.
+
+Default: `false`
+
+=== run-rsync ===
+
+Whether to run `rsync` to fetch data. You don't generally want to
+change this except when building complex topologies where `rcynic`
+running on one set of machines acts as aggregators for another set of
+validators. A large ISP might want to build such a topology so that
+they could have a local validation cache in each POP while minimizing
+load on the global repository system and maintaining some degree of
+internal consistency between POPs. In such cases, one might want the
+`rcynic` instances in the POPs to validate data fetched from the
+aggregators via an external process, without the POP `rcynic`
+instances attempting to fetch anything themselves.
+
+Values: `true` or `false`.
+
+Default: `true`
+
+=== use-links ===
+
+Whether to use hard links rather than copying valid objects
+from the unauthenticated to authenticated tree. Using links
+is slightly more fragile (anything that stomps on the
+unauthenticated file also stomps on the authenticated file)
+but is a bit faster and reduces the number of inodes consumed
+by a large data collection. At the moment, copying is the
+default behavior, but this may change in the future.
+
+Values: `true` or `false`.
+
+Default: `false`
+
+=== rsync-early ===
+
+Whether to force `rsync` to run even when we have a valid manifest for
+a particular publication point and its `nextUpdate` time has not yet
+passed.
+
+This is an experimental feature, and currently defaults to **true**,
+which is the old behavior (running `rsync` regardless of whether we
+have a valid cached manifest). This default may change once we have
+more experience with `rcynic`'s behavior when run with this option set
+to `false`.
+
+Skipping the `rsync` fetch when we already have a valid cached
+manifest can significantly reduce the total number of `rsync`
+connections we need to make, and significantly reduce the load that
+each validator places on the authoritative publication servers. As
+with any caching scheme, however, there are some potential problems
+involved with not fetching the latest data, and we don't yet have
+enough experience with this option to know how this will play out in
+practice, which is why this is still considered experimental.
+
+Values: `true` or `false`
+
+Default: `true` (but may change in the future)
+
+=== trust-anchor ===
+
+Specify one RPKI trust anchor, represented as a local file
+containing an X.509 certificate in DER format. Value of this
+option is the pathname of the file.
+
+**No default**.
+
+=== trust-anchor-locator ===
+
+Specify one RPKI trust anchor locator, represented as a local file in
+the format specified in
+[[http://www.rfc-editor.org/rfc/rfc6490.txt|RFC-6490]]. This a simple
+text format containing an rsync URI and the RSA public key of the
+X.509 object specified by the URI; the first line of the file is the
+URI, the remainder is the public key in Base64 encoded DER format.
+
+Value of this option is the pathname of the file.
+
+**No default**.
+
+=== trust-anchor-directory ===
+
+Specify a directory containing trust anchors, trust anchor locators,
+or both. Trust anchors in such a directory must have filenames ending
+in "`.cer`"; trust anchor locators in such a directory must have names
+ending in "`.tal`"; any other files will be skipped.
+
+This directive is an alternative to using the `trust-anchor` and
+trust-anchor-locator` directives. This is probably easier to use than
+the other trust anchor directives when dealing with a collection of
+trust anchors. This may change on that promised day when we have only
+a single global trust anchor to deal with, but we're not there yet.
+
+**No default**.
+
+== Post-processing rcynic's XML output ==
+
+The distribution includes several post-processors for the XML output
+`rcynic` writes describing the actions it has taken and the validation
+status of the objects it has found.
+
+=== rcynic-html === #rcynichtml
+
+`rcynic-html` converts `rcynic`'s XML output into a collection of HTML
+pages summarizing the results, noting problems encountered, and
+showing some history of `rsync` transfer times and repository object
+counts in graphical form.
+
+`rcynic-cron` runs `rcynic-html` automatically, immediately after running
+`rcynic`. If for some reason you need to run `rcynic-html` by hand, the
+command syntax is:
+
+{{{
+#!sh
+$ rcynic-html rcynic.xml /web/server/directory/
+}}}
+
+`rcynic-html` will write a collection of HTML and image files to the
+specified output directory, along with a set of RRD databases.
+`rcynic-html` will create the output directory if necessary.
+
+`rcynic-html` requires [[http://www.rrdtool.org/|`rrdtool`]], a
+specialized database and graphing engine designed for this sort of
+work. You can run `rcynic-html` without `rrdtool` by giving it the
+`--no-show-graphs` option, but the result won't be as useful.
+
+`rcynic-html` gets its idea of where to find the `rrdtool` program from
+autoconf, which usually works. If for some reason it doesn't work in
+your environment, you will need to tell `rcynic-html` where to find
+`rrdtool`, using the `--rrdtool-binary` option:
+
+{{{
+#!sh
+$ rcynic-html --rrdtoolbinary /some/where/rrdtool rcynic.xml /web/server/directory/
+}}}
+
+=== rcynic.xsl ===
+
+`rcynic.xsl` was an earlier attempt at the same kind of HTML output as
+[[#rcynichtml|rcynic-html]] generates. XSLT was a convenient language
+for our initial attempts at this, but as the processing involved got
+more complex, it became obvious that we needed a general purpose
+programming language.
+
+If for some reason XSLT works better in your environment than Python,
+you might find this stylesheet to be a useful starting point, but be
+warned that it's significantly slower than `rcynic-html`, lacks many
+features, and is no longer under development.
+
+=== rcynic-text ===
+
+`rcynic-text` provides a quick flat text summary of validation results.
+This is useful primarily in test scripts
+([[wiki:doc/RPKI/CA#smoketest|smoketest]] uses it).
+
+Usage:
+
+{{{
+#!sh
+$ rcynic-text rcynic.xml
+}}}
+
+=== validation_status ===
+
+`validation_status` provides a flat text translation of the detailed
+validation results. This is useful primarily for checking the
+detailed status of some particular object or set of objects, perhaps
+using a program like `grep` or `awk` to filter `validation_status`'s
+output.
+
+Usage:
+
+{{{
+#!sh
+$ validation_status rcynic.xml
+$ validation_status rcynic.xml | fgrep rpki.misbehaving.org
+$ validation_status rcynic.xml | fgrep object_rejected
+}}}
+
+=== rcynic-svn ===
+
+`rcynic-svn` is a tool for archiving `rcynic`'s results in a
+[[http://subversion.apache.org/|Subversion]] repository. `rcynic-svn`
+is not integrated into `rcynic-cron`, because this is not something
+that every relying party is going to want to do. However, for relying
+parties who want to analyze `rcynic`'s output over a long period of
+time, `rcynic-svn` may provide a useful starting point starting point.
+
+To use `rcynic-svn`, you first must set up a Subversion repository and
+check out a working directory:
+
+{{{
+#!sh
+$ svnadmin create /some/where/safe/rpki-archive
+$ svn co file:///some/where/safe/rpki-archive /some/where/else/rpki-archive
+}}}
+
+The name can be anything you like, in this example we call it
+"`rpki-archive`". The above sequence creates the repository, then
+checks out an empty working directory `/some/where/else/rpki-archive`.
+
+The repository does not need to be on the same machine as the working
+directory, but it probably should be for simplicity unless you have
+some strong need to put it elsewhere.
+
+Once you have the repository and working directory set up, you need to
+arrange for `rcynic-svn` to be run after each `rcynic` run whose results
+you want to archive. One way to do this would be to run `rcynic-svn` in
+the same cron job as `rcynic-cron`, immediately after `rcynic-cron` and
+specifying the same lock file that `rcynic-cron` uses.
+
+Sample usage, assuming that `rcynic`'s data is in the usual place:
+
+{{{
+#!sh
+$ rcynic-svn --lockfile /var/rcynic/data/lock \
+ /var/rcynic/data/authenticated \
+ /var/rcynic/data/unauthenticated \
+ /var/rcynic/data/rcynic.xml \
+ /some/where/else/rpki-archive
+}}}
+
+where the last argument is the name of the Subversion working
+directory and the other arguments are the names of those portions of
+`rcynic`'s output which you wish to archive. Generally, the above set
+(`authenticated`, `unauthenticated`, and `rcynic.xml`) are the ones
+you want, but feel free to experiment.
diff --git a/doc/manual/07.RPKI.RP.rpki-rtr.md b/doc/manual/07.RPKI.RP.rpki-rtr.md
new file mode 100644
index 00000000..59f6fdb0
--- /dev/null
+++ b/doc/manual/07.RPKI.RP.rpki-rtr.md
@@ -0,0 +1,150 @@
+# rpki-rtr
+
+`rpki-rtr` is an implementation of the ["RPKI-router" protocol (RFC-6810)][RFC-6810].
+
+`rpki-rtr` depends on [rcynic][] to collect and validate the RPKI data.
+`rpki-rtr`'s's job is to serve up that data in a lightweight format suitable
+for routers that want to do prefix origin authentication.
+
+To use `rpki-rtr`, you need to do two things beyond just running `rcynic`:
+
+ 1. You need to [post-process `rcynic`'s output][rpki-rtr] into the data files used by rpki-rtr. The `rcynic-cron` script handles this automatically, so the default installation should already be taking care of this for you.
+ 2. You need to [set up a listener][rpki-rtr] for the `rpki-rtr` server, using the generated data files. The platform-specific packages for FreeBSD, Debian, and Ubuntu automatically set up a plain TCP listener, but you will have to do something on other platforms, or if you're using a transport protocol other than plain TCP.
+
+## Post-processing rcynic's output
+
+`rpki-rtr` is designed to do the translation from raw RPKI data into the rpki-
+rtr protocol only once. It does this by pre-computing the answers to all the
+queries it is willing to answer for a given data set, and storing them on
+disk. `rpki-rtr`'s `cronjob` command handles this computation.
+
+To set this up, add an invocation of `rpki-rtr cronjob` to the cron job you're
+already running to run `rcynic`. As mentioned above, if you're running the
+`rcynic-cron` script, this is already being done for you automatically, so you
+don't need to do anything. If you've written your own cron script, you'll need
+to add something like this to your script:
+
+ /usr/local/bin/rpki-rtr cronjob /var/rcynic/data/authenticated /var/rcynic/rpki-rtr
+
+`rpki-rtr cronjob` needs write access to a directory where it can store pre-
+digested versions of the data it pulls from `rcynic`. In the example above,
+the directory `/var/rcynic/rpki-rtr` should be writable by the user ID that is
+executing the cron script.
+
+`rpki-rtr` creates a collection of data files, as well as a subdirectory in
+which each instance of `rpki-rtr server` can place a `PF_UNIX` socket file. By
+default, `rpki-rtr` creates these files under the directory in which you run
+it, but you can change that by specifying the target directory as a second
+command line argument, as shown above.
+
+You should make sure that `rpki-rtr cronjob` runs at least once before
+attempting to configure `rpki-rtr server`. Nothing terrible will happen if you
+don't do this, but `rpki-rtr server` invocations started before the first
+`rpki-rtr cronjob` run may behave oddly.
+
+## Setting up the rpki-rtr server
+
+You need to to set up a server listener that invokes `rpki-rtr server`. What
+kind of server listener you set up depends on which network protocol you're
+using to transport this protocol. `rpki-rtr` is happy to run under inetd,
+xinetd, sshd, or pretty much anything -- `rpki-rtr` doesn't really care, it
+just reads from `stdin` and writes to `stdout`.
+
+`rpki-rtr server` should be run as a non-privileged user (it is read-only for
+a reason). You may want to set up a separate UNIX userid for this purpose.
+
+`rpki-rtr server` takes an optional argument specifying the path to its data
+directory; if you omit this argument, it uses the directory in in which you
+run it.
+
+The details of how you set up a listener for this vary depending on the
+network protocol and the operating system on which you run it. Here are three
+examples, for running under `inetd` on FreeBSD, under `sshd`, or as a free-
+standing server using `rpki-rtr listener`.
+
+### Running rpki-rtr server under inetd
+
+Running under `inetd` with plain TCP is insecure and should only be done for
+testing, but you can also run it with TCP-MD5 or TCP-AO, or over IPsec. The
+inetd configuration is generally the same, the details of how you set up TCP-
+MD5, TCP-AO, or IPsec are platform specific.
+
+To run under `inetd`, you need to:
+
+ 1. Add an entry to `/etc/services` defining a symbolic name for the port, if one doesn't exist already. At present there is no well-known port defined for this protocol, for this example we'll use port 42420 and the symbolic name `rpki-rtr`.
+
+> Add to `/etc/services`:
+
+ rpki-rtr 42420/tcp
+
+ 2. Add the service line to `/etc/inetd.conf`:
+
+ rpki-rtr stream tcp nowait nobody /usr/local/bin/rpki-rtr rpki-rtr server /var/rcynic/rpki-rtr
+
+> This assumes that you want the server to run as user "nobody", which is
+generally a safe choice, or you could create a new non-priviledged user for
+this purpose. **DO NOT** run the server as root; it shouldn't do anything bad,
+but it's a network server that doesn't need root access, therefore it
+shouldn't have root access.
+
+### Running rpki-rtr server under sshd
+
+To run `rpki-rtr server` under `sshd`, you need to:
+
+ 1. Decide whether to run a new instance of sshd on a separate port or use the standard port. `rpki-rtr` doesn't care, but some people seem to think that it's somehow more secure to run this service on a different port. Setting up `sshd` in general is beyond the scope of this documention, but most likely you can copy the bulk of your configuration from the standard config.
+ 2. Configure `sshd` to know about the `rpki-rtr` subsystem. Add something like this to your `sshd.conf`:
+
+ Subsystem rpki-rtr /usr/local/bin/rpki-rtr
+
+ 3. Configure the userid(s) you expect SSH clients to use to connect to the server. For operational use you almost certainly do _NOT_ want this user to have a normal shell, instead you should configure its shell to be the server (`/usr/local/bin/rpki-rtr` or wherever you've installed it on your system) and its home directory to be the `rpki-rtr` data directory (`/var/rcynic/rpki-rtr` or whatever you're using). If you're using passwords to authenticate instead of ssh keys (not recommended) you will always need to set the password(s) here when configuring the userid(s).
+ 4. Configure the `.ssh/authorized_keys` file for your clients; if you're using the example values given above, this would be `/var/rcynic/rpki-rtr/.ssh/authorized_keys`. You can have multiple SSH clients using different keys all logging in as the same SSH user, you just have to list all of the SSH keys here. You may want to consider using a `command=` parameter in the key line (see the `sshd(8)` man page) to lock down the SSH keys listed here so that they can only be used to run the `rpki-rtr` service.
+
+> If you're running a separate `sshd` for this purpose, you might also want to
+add an `!AuthorizedKeysFile` entry pointing at this `authorized_keys` file so
+that the server will only use this `authorized_keys` file regardless of what
+other user accounts might exist on the machine:
+
+ AuthorizedKeysFile /var/rcynic/rpki-rtr/.ssh/authorized_keys
+
+> There's a sample `sshd.conf` in the source directory. You will have to
+modify it to suit your environment. The most important part is the `Subsystem`
+line, which runs the `server.sh` script as the "`rpki-rtr`" service, as
+required by the protocol specification.
+
+### Running rpki-rtr listener
+
+`rpki-rtr listener` is a free-standing plain TCP server which just listens on
+a TCP socket then forks a child process running `rpki-rtr server`.
+
+All of the [caveats regarding plain TCP][rpki-rtr] apply to `rpki-rtr listener`.
+
+`rpki-rtr listener` takes one required argument, the TCP port number on which
+to listen; it also accepts a second argument which specifies the rcynic output
+directory, like `rpki-rtr server`.
+
+ /usr/local/bin/rpki-rtr listener 42420 /var/rcynic/rpki-rtr
+
+### Other transports
+
+You can also run this code under `xinetd`, or the netpipes "`faucet`" program,
+or `stunnel`...other than a few lines that might need hacking to log the
+connection peer properly, the program really doesn't care.
+
+You _should_, however, care whether the channel you have chosen is secure; it
+doesn't make a lot of sense to go to all the trouble of checking RPKI data
+then let the bad guys feed bad data into your routers anyway because you were
+running the rpki-rtr link over an unsecured TCP connection.
+
+## Other commands
+
+`rpki-rtr` has two other commands which might be useful for debugging:
+
+ 1. `rpki-rtr client` implements a dumb client program for this protocol, over SSH, raw TCP, or by invoking `rpki-rtr server` directly in a subprocess. The output is not expected to be useful except for debugging. Either run it locally where you run the cron job, or run it anywhere on the net, as in
+
+ $ rpki-rtr client tcp <hostname> <port>
+
+ 2. `rpki-rtr show` will display a text dump of pre-digested data files in the current directory.
+
+[RFC-6810]: http://www.rfc-editor.org/rfc/rfc6810.txt
+[rcynic]: 06.RPKI.RP.rcynic.md
+[rpki-rtr]: 07.RPKI.RP.rpki-rtr.md
diff --git a/doc/manual/07.RPKI.RP.rpki-rtr.wiki b/doc/manual/07.RPKI.RP.rpki-rtr.wiki
new file mode 100644
index 00000000..17bb5def
--- /dev/null
+++ b/doc/manual/07.RPKI.RP.rpki-rtr.wiki
@@ -0,0 +1,213 @@
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= rpki-rtr =
+
+`rpki-rtr` is an implementation of the
+[[http://www.rfc-editor.org/rfc/rfc6810.txt|"RPKI-router" protocol (RFC-6810)]].
+
+`rpki-rtr` depends on [[rcynic|`rcynic`]] to collect and validate the
+RPKI data. `rpki-rtr`'s's job is to serve up that data in a
+lightweight format suitable for routers that want to do prefix origin
+authentication.
+
+To use `rpki-rtr`, you need to do two things beyond just running `rcynic`:
+
+1. You need to [[#cronjob-mode|post-process `rcynic`'s output]] into the
+ data files used by rpki-rtr. The `rcynic-cron` script handles this
+ automatically, so the default installation should already be taking
+ care of this for you.
+
+2. You need to [[#server-mode|set up a listener]] for the `rpki-rtr`
+ server, using the generated data files. The platform-specific
+ packages for FreeBSD, Debian, and Ubuntu automatically set up a
+ plain TCP listener, but you will have to do something on other
+ platforms, or if you're using a transport protocol other than plain
+ TCP.
+
+== Post-processing rcynic's output == #cronjob-mode
+
+`rpki-rtr` is designed to do the translation from raw RPKI data into
+the rpki-rtr protocol only once. It does this by pre-computing the
+answers to all the queries it is willing to answer for a given data
+set, and storing them on disk. `rpki-rtr`'s `cronjob` command handles
+this computation.
+
+To set this up, add an invocation of `rpki-rtr cronjob` to the
+cron job you're already running to run `rcynic`. As mentioned above,
+if you're running the `rcynic-cron` script, this is already being done
+for you automatically, so you don't need to do anything. If you've
+written your own cron script, you'll need to add something like this
+to your script:
+
+{{{
+#!sh
+/usr/local/bin/rpki-rtr cronjob /var/rcynic/data/authenticated /var/rcynic/rpki-rtr
+}}}
+
+`rpki-rtr cronjob` needs write access to a directory where it can
+store pre-digested versions of the data it pulls from `rcynic`. In
+the example above, the directory `/var/rcynic/rpki-rtr` should be
+writable by the user ID that is executing the cron script.
+
+`rpki-rtr` creates a collection of data files, as well as a
+subdirectory in which each instance of `rpki-rtr server` can place a
+`PF_UNIX` socket file. By default, `rpki-rtr` creates these files
+under the directory in which you run it, but you can change that by
+specifying the target directory as a second command line argument, as
+shown above.
+
+You should make sure that `rpki-rtr cronjob` runs at least once before
+attempting to configure `rpki-rtr server`. Nothing terrible will
+happen if you don't do this, but `rpki-rtr server` invocations started
+before the first `rpki-rtr cronjob` run may behave oddly.
+
+== Setting up the rpki-rtr server == #server-mode
+
+You need to to set up a server listener that invokes `rpki-rtr
+server`. What kind of server listener you set up depends on which
+network protocol you're using to transport this protocol. `rpki-rtr`
+is happy to run under inetd, xinetd, sshd, or pretty much anything --
+`rpki-rtr` doesn't really care, it just reads from `stdin` and writes
+to `stdout`.
+
+`rpki-rtr server` should be run as a non-privileged user (it is
+read-only for a reason). You may want to set up a separate UNIX
+userid for this purpose.
+
+`rpki-rtr server` takes an optional argument specifying the path to
+its data directory; if you omit this argument, it uses the directory
+in in which you run it.
+
+The details of how you set up a listener for this vary depending on
+the network protocol and the operating system on which you run it.
+Here are three examples, for running under `inetd` on FreeBSD, under
+`sshd`, or as a free-standing server using `rpki-rtr listener`.
+
+=== Running rpki-rtr server under inetd === #under-inetd
+
+Running under `inetd` with plain TCP is insecure and should only be done
+for testing, but you can also run it with TCP-MD5 or TCP-AO, or over
+IPsec. The inetd configuration is generally the same, the details of
+how you set up TCP-MD5, TCP-AO, or IPsec are platform specific.
+
+To run under `inetd`, you need to:
+
+a. Add an entry to `/etc/services` defining a symbolic name for the
+ port, if one doesn't exist already. At present there is no
+ well-known port defined for this protocol, for this example we'll
+ use port 42420 and the symbolic name `rpki-rtr`.
+
+ Add to `/etc/services`:
+
+ {{{
+ rpki-rtr 42420/tcp
+ }}}
+
+b. Add the service line to `/etc/inetd.conf`:
+
+ {{{
+ rpki-rtr stream tcp nowait nobody /usr/local/bin/rpki-rtr rpki-rtr server /var/rcynic/rpki-rtr
+ }}}
+
+ This assumes that you want the server to run as user "nobody",
+ which is generally a safe choice, or you could create a new
+ non-priviledged user for this purpose. **DO NOT** run the server
+ as root; it shouldn't do anything bad, but it's a network server
+ that doesn't need root access, therefore it shouldn't have root
+ access.
+
+=== Running rpki-rtr server under sshd ===
+
+To run `rpki-rtr server` under `sshd`, you need to:
+
+a. Decide whether to run a new instance of sshd on a separate port or
+ use the standard port. `rpki-rtr` doesn't care, but some people
+ seem to think that it's somehow more secure to run this service on
+ a different port. Setting up `sshd` in general is beyond the scope
+ of this documention, but most likely you can copy the bulk of your
+ configuration from the standard config.
+
+b. Configure `sshd` to know about the `rpki-rtr` subsystem. Add something
+ like this to your `sshd.conf`:
+
+ {{{
+ Subsystem rpki-rtr /usr/local/bin/rpki-rtr
+ }}}
+
+c. Configure the userid(s) you expect SSH clients to use to connect to
+ the server. For operational use you almost certainly do //NOT//
+ want this user to have a normal shell, instead you should configure
+ its shell to be the server (`/usr/local/bin/rpki-rtr` or wherever
+ you've installed it on your system) and its home directory to be
+ the `rpki-rtr` data directory (`/var/rcynic/rpki-rtr` or whatever
+ you're using). If you're using passwords to authenticate instead
+ of ssh keys (not recommended) you will always need to set the
+ password(s) here when configuring the userid(s).
+
+d. Configure the `.ssh/authorized_keys` file for your clients; if you're
+ using the example values given above, this would be
+ `/var/rcynic/rpki-rtr/.ssh/authorized_keys`. You can have multiple
+ SSH clients using different keys all logging in as the same SSH
+ user, you just have to list all of the SSH keys here. You may want
+ to consider using a `command=` parameter in the key line (see the
+ `sshd(8)` man page) to lock down the SSH keys listed here so that
+ they can only be used to run the `rpki-rtr` service.
+
+ If you're running a separate `sshd` for this purpose, you might also
+ want to add an `!AuthorizedKeysFile` entry pointing at this
+ `authorized_keys` file so that the server will only use this
+ `authorized_keys` file regardless of what other user accounts might
+ exist on the machine:
+
+ {{{
+ AuthorizedKeysFile /var/rcynic/rpki-rtr/.ssh/authorized_keys
+ }}}
+
+ There's a sample `sshd.conf` in the source directory. You will have
+ to modify it to suit your environment. The most important part is
+ the `Subsystem` line, which runs the `server.sh` script as the
+ "`rpki-rtr`" service, as required by the protocol specification.
+
+=== Running rpki-rtr listener ===
+
+`rpki-rtr listener` is a free-standing plain TCP server which just
+listens on a TCP socket then forks a child process running `rpki-rtr server`.
+
+All of the [[#under-inetd|caveats regarding plain TCP]] apply to `rpki-rtr listener`.
+
+`rpki-rtr listener` takes one required argument, the TCP port number
+on which to listen; it also accepts a second argument which specifies
+the rcynic output directory, like `rpki-rtr server`.
+
+{{{
+/usr/local/bin/rpki-rtr listener 42420 /var/rcynic/rpki-rtr
+}}}
+
+=== Other transports ===
+
+You can also run this code under `xinetd`, or the netpipes "`faucet`"
+program, or `stunnel`...other than a few lines that might need hacking
+to log the connection peer properly, the program really doesn't care.
+
+You //should//, however, care whether the channel you have chosen is
+secure; it doesn't make a lot of sense to go to all the trouble of
+checking RPKI data then let the bad guys feed bad data into your
+routers anyway because you were running the rpki-rtr link over an
+unsecured TCP connection.
+
+== Other commands ==
+
+`rpki-rtr` has two other commands which might be useful for debugging:
+
+a. `rpki-rtr client` implements a dumb client program for this
+ protocol, over SSH, raw TCP, or by invoking `rpki-rtr server`
+ directly in a subprocess. The output is not expected to be useful
+ except for debugging. Either run it locally where you run the
+ cron job, or run it anywhere on the net, as in
+ {{{
+ $ rpki-rtr client tcp <hostname> <port>
+ }}}
+
+b. `rpki-rtr show` will display a text dump of pre-digested data
+ files in the current directory.
diff --git a/doc/manual/08.RPKI.RP.RunningUnderCron.md b/doc/manual/08.RPKI.RP.RunningUnderCron.md
new file mode 100644
index 00000000..bea2e4dc
--- /dev/null
+++ b/doc/manual/08.RPKI.RP.RunningUnderCron.md
@@ -0,0 +1,61 @@
+# Running relying party tools under cron
+
+rcynic is the primary relying party tool, and it's designed to run under the
+cron daemon. Consequently, most of the other tools are also designed to run
+under the cron daemon, so that they can make use of rcynic's output
+immediately after rcynic finishes a validation run.
+
+[rcynic-cron][RP] runs the basic set of relying party tools (`rcynic`, `rcynic-
+html`, and `rpki-rtr cronjob`); if this suffices for your purposes, you don't
+need to do anything else. This section is a discussion of alternative
+approaches.
+
+Which tools you want to run depends on how you intend to use the relying party
+tools. Here we assume a typical case in which you want to gather and validate
+RPKI data and feed the results to routers using the rpki-rtr protocol. We also
+assume that everything has been installed in the default locations.
+
+The exact sequence for invoking rcynic itself varies depending both on whether
+you're using a chroot jail or not and on the platform on which you're running
+rcynic, as the chroot utilities on different platforms behave slightly
+differently. Using a chroot jail used to be the default for rcynic, but it
+turned out that many users found the setup involved to be too complex.
+
+If you're not using rcynic-cron, it's probably simplest to generate a short
+shell script which calls the tools you want in the correct order, so that's
+what we show here.
+
+Once you've written this script, install it in your crontab, running at some
+appropriate interval: perhaps hourly, or perhaps every six hours, depending on
+your needs. You should run it at least once per day, and probably should not
+run it more frequently than once per hour unless you really know what you are
+doing. Please do _NOT_ just arrange for the script to run on the hour, instead
+pick some random minute value within the hour as the start time for your
+script, to help spread the load on the repository servers.
+
+On FreeBSD or MacOSX, this script might look like this:
+
+ #!/bin/sh -
+ /usr/sbin/chroot -u rcynic -g rcynic /var/rcynic /bin/rcynic -c /etc/rcynic.conf || exit
+ /var/rcynic/bin/rcynic-html /var/rcynic/data/rcynic.xml /usr/local/www/data/rcynic
+ /usr/bin/su -m rcynic -c '/usr/local/bin/rpki-rtr cronjob /var/rcynic/data/authenticated /var/rcynic/rpki-rtr'
+
+This assumes that you have done
+
+ mkdir /var/rcynic/rpki-rtr
+ chown rcynic /var/rcynic/rpki-rtr
+
+On GNU/Linux systems, the script might look like this if you use the chrootuid
+program:
+
+ #!/bin/sh -
+ /usr/bin/chrootuid /var/rcynic rcynic /bin/rcynic -c /etc/rcynic.conf || exit
+ /var/rcynic/bin/rcynic-html /var/rcynic/data/rcynic.xml /var/www/rcynic
+ /usr/bin/su -m rcynic -c '/usr/local/bin/rpki-rtr cronjob /var/rcynic/data/authenticated /var/rcynic/rpki-rtr'
+
+If you use the chroot program instead of chrootuid, change the line that
+invokes rcynic to:
+
+ /usr/sbin/chroot --userspec rcynic:rcynic /var/rcynic /bin/rcynic -c /etc/rcynic.conf || exit
+
+[RP]: 05.RPKI.RP.md
diff --git a/doc/manual/08.RPKI.RP.RunningUnderCron.wiki b/doc/manual/08.RPKI.RP.RunningUnderCron.wiki
new file mode 100644
index 00000000..dd323c1a
--- /dev/null
+++ b/doc/manual/08.RPKI.RP.RunningUnderCron.wiki
@@ -0,0 +1,72 @@
+[[TracNav(doc/RPKI/TOC)]]
+
+= Running relying party tools under cron =
+
+rcynic is the primary relying party tool, and it's designed to run
+under the cron daemon. Consequently, most of the other tools are also
+designed to run under the cron daemon, so that they can make use of
+rcynic's output immediately after rcynic finishes a validation run.
+
+[[wiki:doc/RPKI/RP#rcynic-cron|rcynic-cron]] runs the basic set of
+relying party tools (`rcynic`, `rcynic-html`, and `rpki-rtr cronjob`);
+if this suffices for your purposes, you don't need to do anything
+else. This section is a discussion of alternative approaches.
+
+Which tools you want to run depends on how you intend to use the
+relying party tools. Here we assume a typical case in which you want
+to gather and validate RPKI data and feed the results to routers using
+the rpki-rtr protocol. We also assume that everything has been
+installed in the default locations.
+
+The exact sequence for invoking rcynic itself varies depending both on
+whether you're using a chroot jail or not and on the platform on which
+you're running rcynic, as the chroot utilities on different platforms
+behave slightly differently. Using a chroot jail used to be the
+default for rcynic, but it turned out that many users found the setup
+involved to be too complex.
+
+If you're not using rcynic-cron, it's probably simplest to generate a
+short shell script which calls the tools you want in the correct
+order, so that's what we show here.
+
+Once you've written this script, install it in your crontab, running
+at some appropriate interval: perhaps hourly, or perhaps every six
+hours, depending on your needs. You should run it at least once per
+day, and probably should not run it more frequently than once per hour
+unless you really know what you are doing. Please do //NOT// just
+arrange for the script to run on the hour, instead pick some random
+minute value within the hour as the start time for your script, to
+help spread the load on the repository servers.
+
+On FreeBSD or MacOSX, this script might look like this:
+
+{{{
+#!sh
+#!/bin/sh -
+/usr/sbin/chroot -u rcynic -g rcynic /var/rcynic /bin/rcynic -c /etc/rcynic.conf || exit
+/var/rcynic/bin/rcynic-html /var/rcynic/data/rcynic.xml /usr/local/www/data/rcynic
+/usr/bin/su -m rcynic -c '/usr/local/bin/rpki-rtr cronjob /var/rcynic/data/authenticated /var/rcynic/rpki-rtr'
+}}}
+
+This assumes that you have done
+{{{
+mkdir /var/rcynic/rpki-rtr
+chown rcynic /var/rcynic/rpki-rtr
+}}}
+
+On GNU/Linux systems, the script might look like this if you use the chrootuid program:
+
+{{{
+#!sh
+#!/bin/sh -
+/usr/bin/chrootuid /var/rcynic rcynic /bin/rcynic -c /etc/rcynic.conf || exit
+/var/rcynic/bin/rcynic-html /var/rcynic/data/rcynic.xml /var/www/rcynic
+/usr/bin/su -m rcynic -c '/usr/local/bin/rpki-rtr cronjob /var/rcynic/data/authenticated /var/rcynic/rpki-rtr'
+}}}
+
+If you use the chroot program instead of chrootuid, change the line that invokes rcynic to:
+
+{{{
+#!sh
+/usr/sbin/chroot --userspec rcynic:rcynic /var/rcynic /bin/rcynic -c /etc/rcynic.conf || exit
+}}}
diff --git a/doc/manual/09.RPKI.RP.HierarchicalRsync.md b/doc/manual/09.RPKI.RP.HierarchicalRsync.md
new file mode 100644
index 00000000..196f0d2d
--- /dev/null
+++ b/doc/manual/09.RPKI.RP.HierarchicalRsync.md
@@ -0,0 +1,88 @@
+# Running a hierarchical rsync configuration
+
+Having every relying party on the Internet contact every publication service
+is not terribly efficient. In many cases, it may make more sense to use a
+hierarchical configuration in which a few "gatherer" relying parties contact
+the publication servers directly, while a collection of other relying parties
+get their raw data from the gatherers.
+
+Note
+
+ The relying parties in this configuration still perform their own validation, they just let the gatherers do the work of collecting the unvalidated data for them.
+
+A gatherer in a configuration like this would look just like a stand-alone
+relying party as discussed [above][HierarchicalRsync]. The only real difference is that a
+gatherer must also make its unauthenticated data collection available to other
+relying parties. Assuming the standard configuration, this will be the
+directory `/var/rcynic/data/unauthenticated` and its subdirectories.
+
+There are two slightly different ways to do this with rsync:
+
+ 1. Via unauthenticated rsync, by configuring an `rsyncd.conf` "module", or
+ 2. Via rsync over a secure transport protocol such as ssh.
+
+Since the downstream relying party performs its own validation in any case,
+either of these will work, but using a secure transport such as ssh makes it
+easier to track problems back to their source if a downstream relying party
+concludes that it's been receiving bad data.
+
+Script for a downstream relying party using ssh might look like this:
+
+ #!/bin/sh -
+
+ PATH=/usr/bin:/bin:/usr/local/bin
+ umask 022
+ eval `/usr/bin/ssh-agent -s` >/dev/null
+ /usr/bin/ssh-add /root/rpki_ssh_id_rsa 2>&1 | /bin/fgrep -v 'Identity added:'
+ hosts='larry.example.org moe.example.org curly.example.org'
+ for host in $hosts
+ do
+ /usr/bin/rsync --archive --update --safe-links rpkisync@${host}:/var/rcynic/data/unauthenticated/ /var/rcynic/data/unauthenticated.${host}/
+ done
+ eval `/usr/bin/ssh-agent -s -k` >/dev/null
+ for host in $hosts
+ do
+ /usr/sbin/chroot -u rcynic -g rcynic /var/rcynic /bin/rcynic -c /etc/rcynic.conf -u /data/unauthenticated.${host}
+ /var/rcynic/bin/rcynic-html /var/rcynic/data/rcynic.xml /usr/local/www/data/rcynic.${host}
+ done
+ cd /var/rcynic/rpki-rtr
+ /usr/bin/su -m rcynic -c '/usr/local/bin/rpki-rtr cronjob /var/rcynic/data/authenticated'
+
+where /root/rpki_ssh_id_rsa is an SSH private key authorized to log in as user
+"rpkisync" on the gatherer machines. If you want to lock this down a little
+tighter, you could use ssh's `command="..."` mechanism as described in the
+sshd documentation to restrict the rpkisync user so that it can only run this
+one rsync command.
+
+If you prefer to use insecure rsync, perhaps to avoid allowing the downstream
+relying parties any sort of login access at all on the gatherer machines, the
+configuration would look more like this:
+
+ #!/bin/sh -
+
+ PATH=/usr/bin:/bin:/usr/local/bin
+ umask 022
+ hosts='larry.example.org moe.example.org curly.example.org'
+ for host in $hosts
+ do
+ /usr/bin/rsync --archive --update --safe-links rsync://${host}/unauthenticated/ /var/rcynic/data/unauthenticated.${host}/
+ done
+ for host in $hosts
+ do
+ /usr/sbin/chroot -u rcynic -g rcynic /var/rcynic /bin/rcynic -c /etc/rcynic.conf -u /data/unauthenticated.${host}
+ /var/rcynic/bin/rcynic-html /var/rcynic/data/rcynic.xml /usr/local/www/data/rcynic.${host}
+ done
+ cd /var/rcynic/rpki-rtr
+ /usr/bin/su -m rcynic -c '/usr/local/bin/rpki-rtr cronjob /var/rcynic/data/authenticated'
+
+where "unauthenticated" here is an rsync module pointing at
+`/var/rcynic/data/unauthenticated` on each of the gatherer machines.
+Configuration for such a module would look like:
+
+ [unauthenticated]
+ read only = yes
+ transfer logging = yes
+ path = /var/rcynic/data/unauthenticated
+ comment = Unauthenticated RPKI data
+
+[HierarchicalRsync]: 09.RPKI.RP.HierarchicalRsync.md
diff --git a/doc/manual/09.RPKI.RP.HierarchicalRsync.wiki b/doc/manual/09.RPKI.RP.HierarchicalRsync.wiki
new file mode 100644
index 00000000..6727b073
--- /dev/null
+++ b/doc/manual/09.RPKI.RP.HierarchicalRsync.wiki
@@ -0,0 +1,103 @@
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= Running a hierarchical rsync configuration =
+
+Having every relying party on the Internet contact every publication
+service is not terribly efficient. In many cases, it may make more
+sense to use a hierarchical configuration in which a few "gatherer"
+relying parties contact the publication servers directly, while a
+collection of other relying parties get their raw data from the
+gatherers.
+
+ Note:: The relying parties in this configuration still perform their
+ own validation, they just let the gatherers do the work of
+ collecting the unvalidated data for them.
+
+A gatherer in a configuration like this would look just like a
+stand-alone relying party as discussed [[#cronjob|above]]. The only
+real difference is that a gatherer must also make its unauthenticated
+data collection available to other relying parties. Assuming the
+standard configuration, this will be the directory
+`/var/rcynic/data/unauthenticated` and its subdirectories.
+
+There are two slightly different ways to do this with rsync:
+
+1. Via unauthenticated rsync, by configuring an `rsyncd.conf`
+ "module", or
+
+2. Via rsync over a secure transport protocol such as ssh.
+
+Since the downstream relying party performs its own validation in any
+case, either of these will work, but using a secure transport such as
+ssh makes it easier to track problems back to their source if a
+downstream relying party concludes that it's been receiving bad
+data.
+
+Script for a downstream relying party using ssh might look like this:
+
+{{{
+#!sh
+#!/bin/sh -
+
+PATH=/usr/bin:/bin:/usr/local/bin
+umask 022
+eval `/usr/bin/ssh-agent -s` >/dev/null
+/usr/bin/ssh-add /root/rpki_ssh_id_rsa 2>&1 | /bin/fgrep -v 'Identity added:'
+hosts='larry.example.org moe.example.org curly.example.org'
+for host in $hosts
+do
+ /usr/bin/rsync --archive --update --safe-links rpkisync@${host}:/var/rcynic/data/unauthenticated/ /var/rcynic/data/unauthenticated.${host}/
+done
+eval `/usr/bin/ssh-agent -s -k` >/dev/null
+for host in $hosts
+do
+ /usr/sbin/chroot -u rcynic -g rcynic /var/rcynic /bin/rcynic -c /etc/rcynic.conf -u /data/unauthenticated.${host}
+ /var/rcynic/bin/rcynic-html /var/rcynic/data/rcynic.xml /usr/local/www/data/rcynic.${host}
+done
+cd /var/rcynic/rpki-rtr
+/usr/bin/su -m rcynic -c '/usr/local/bin/rpki-rtr cronjob /var/rcynic/data/authenticated'
+}}}
+
+where /root/rpki_ssh_id_rsa is an SSH private key authorized to log in
+as user "rpkisync" on the gatherer machines. If you want to lock this
+down a little tighter, you could use ssh's `command="..."`
+mechanism as described in the sshd documentation to restrict the
+rpkisync user so that it can only run this one rsync command.
+
+If you prefer to use insecure rsync, perhaps to avoid allowing the
+downstream relying parties any sort of login access at all on the
+gatherer machines, the configuration would look more like this:
+
+{{{
+#!sh
+#!/bin/sh -
+
+PATH=/usr/bin:/bin:/usr/local/bin
+umask 022
+hosts='larry.example.org moe.example.org curly.example.org'
+for host in $hosts
+do
+ /usr/bin/rsync --archive --update --safe-links rsync://${host}/unauthenticated/ /var/rcynic/data/unauthenticated.${host}/
+done
+for host in $hosts
+do
+ /usr/sbin/chroot -u rcynic -g rcynic /var/rcynic /bin/rcynic -c /etc/rcynic.conf -u /data/unauthenticated.${host}
+ /var/rcynic/bin/rcynic-html /var/rcynic/data/rcynic.xml /usr/local/www/data/rcynic.${host}
+done
+cd /var/rcynic/rpki-rtr
+/usr/bin/su -m rcynic -c '/usr/local/bin/rpki-rtr cronjob /var/rcynic/data/authenticated'
+}}}
+
+where "unauthenticated" here is an rsync module pointing at
+`/var/rcynic/data/unauthenticated` on each of the gatherer
+machines. Configuration for such a module would look like:
+
+{{{
+#!ini
+[unauthenticated]
+ read only = yes
+ transfer logging = yes
+ path = /var/rcynic/data/unauthenticated
+ comment = Unauthenticated RPKI data
+}}}
diff --git a/doc/manual/10.RPKI.RP.rcynicChroot.md b/doc/manual/10.RPKI.RP.rcynicChroot.md
new file mode 100644
index 00000000..27db8b03
--- /dev/null
+++ b/doc/manual/10.RPKI.RP.rcynicChroot.md
@@ -0,0 +1,161 @@
+# Running rcynic chrooted
+
+This is an attempt to describe the process of setting up rcynic in a chrooted
+environment. The installation scripts that ship with rcynic attempt to do this
+automatically when requested for the platforms we support, but the process is
+somewhat finicky, so some explanation seems in order. If you're running on one
+of the supported platforms, the following steps may be handled for you by the
+Makefiles, but you may still want to understand what all this is trying to do.
+
+rcynic itself does not include any direct support for running chrooted, but is
+designed to be (relatively) easy to run in a chroot jail.
+
+To enable chroot support during installation, you should [install from
+source][1] and use the `--enable-rcynic-jail` option to `./configure`.
+
+rcynic-cron includes support for running chrooted. To use it, specify the
+`--chroot` option on rcynic-cron's command line. This will cause rcynic-cron
+to run rcynic in the chrooted environment. Note that, in order for this to
+work, rcynic-cron itself must run as root, since only root can issue the
+`chroot()` system call. When run as root, rcynic-cron takes care of changing
+the user ID of each process it starts to the unprivileged "`rcynic`" user.
+
+## Creating the chroot jail environment
+
+By far the most tedious and finicky part of setting up rcynic to run in a
+chroot jail is setting the jail itself. The underlying principal is simple and
+obvious: a process running in the jail can't use files outside the jail. The
+difficulty is that the list of files that needs to be in the jail is system-
+dependent, can be rather long, and sometimes can only be discovered by trial
+and error.
+
+You'll either need staticly linked copies of rcynic and rsync, or you'll need
+to figure out which shared libraries these programs need (try using the "ldd"
+command). Here we assume staticly linked binaries, because that's simpler, but
+be warned that statically linked binaries are not even possible on some
+platforms, whether due to concious decisions on the part of operating system
+vendors or due to hidden use of dynamic loading by other libraries at runtime.
+Once again, the Makefiles attempt to do the correct thing for your environment
+if they know what it is, but they might get it wrong.
+
+You may also find that the dynamic loader looks in a different place than you
+(and the Makefiles) would expect when running within the chroot jail. For
+example, you might think that library `/usr/local/lib/libfoo.so` being
+installed into a jail named `/var/rcynic` should go into
+`/var/rcynic/usr/local/lib/libfoo.so`, but we've seen cases where the dynamic
+loader ended up expecting to find it in `/var/rcynic/lib/libfoo.so`. Getting
+this right may require a bit of trial and error.
+
+You'll need a chroot wrapper program. As mentioned above, rcynic-cron can act
+as that wrapper program; if this works for you, we recommend it, because it
+works the same way on all platforms and doesn't require additional external
+programs. Otherwise, you'll have to find a suitable wrapper program. Your
+platform may already have one (FreeBSD does -- `/usr/sbin/chroot`), but if you
+don't, you can download Wietse Venema's "chrootuid" program from
+<ftp://ftp.porcupine.org/pub/security/chrootuid1.3.tar.gz>.
+
+Warning
+
+ The chroot program included in at least some GNU/Linux distributions is not adaquate to this task. You need a wrapper that knows how to drop privileges after performing the chroot() operation itself. If in doubt, use chrootuid.
+
+Unfortunately, the precise details of setting up a proper chroot jail vary
+wildly from one system to another, so the following instructions may not be a
+precise match for the preferred way of doing this on your platform. Please
+feel free to contribute scripts for other platforms.
+
+ 1. Build the static binaries. You might want to test them at this stage too, although you can defer that until after you've got the jail built.
+ 2. Create a userid under which to run rcynic. Here we'll assume that's a user named "rcynic", whose default group is also named "rcynic". Do not add any other userids to the rcynic group unless you really know what you are doing.
+ 3. Build the jail. You'll need, at minimum, a directory in which to put the binaries, a subdirectory tree that's writable by the userid which will be running rcynic and rsync, your trust anchors, and whatever device inodes the various libraries need on your system. Most likely the devices that matter will be `/dev/null`, `/dev/random`, and `/dev/urandom`; if you're running a FreeBSD system with devfs, you do this by mounting and configuring a devfs instance in the jail, on other platforms you probably use the `mknod` program or something similar.
+
+Important
+
+ Other than the directories that you want rcynic and rsync to be able to modify, _nothing_ in the initial jail setup should be writable by the rcynic userid. In particular, rcynic and rsync should _not_ be allowed to modify: their own binary images, any of the configuration files, or your trust anchors. It's simplest just to have root own all the files and directories that rcynic and rsync are not allowed to modify, and make sure that the permissions for all of those directories and files make them writable only by root.
+
+Sample jail tree, assuming that we're putting all of this under `/var/rcynic`:
+
+ $ mkdir /var/rcynic
+ $ mkdir /var/rcynic/bin
+ $ mkdir /var/rcynic/data
+ $ mkdir /var/rcynic/dev
+ $ mkdir /var/rcynic/etc
+ $ mkdir /var/rcynic/etc/trust-anchors
+
+Copy your trust anchors into `/var/rcynic/etc/trust-anchors`.
+
+Copy the staticly linked rcynic and rsync into `/var/rcynic/bin`.
+
+Copy `/etc/resolv.conf` and `/etc/localtime` (if it exists) into
+`/var/rcynic/etc`.
+
+Write an rcynic configuration file as `/var/rcynic/etc/rcynic.conf`. Path
+names in this file must match the jail setup, more on this below.
+
+ $ chmod -R go-w /var/rcynic
+ $ chown -R root:wheel /var/rcynic
+ $ chown -R rcynic:rcynic /var/rcynic/data
+
+If you're using devfs, arrange for it to be mounted at `/var/rcynic/dev`;
+otherwise, create whatever device inodes you need in `/var/rcynic/dev` and
+make sure that they have sane permissions (copying whatever permissions are
+used in your system `/dev` directory should suffice).
+
+`rcynic.conf` to match this configuration:
+
+ [rcynic]
+
+ rsync-program = /bin/rsync
+ authenticated = /data/authenticated
+ unauthenticated = /data/unauthenticated
+ xml-summary = /data/rcynic.xml
+ trust-anchor-directory = /etc/trust-anchors
+
+Once you've got all this set up, you're ready to try running rcynic in the
+jail. Try it from the command line first, then if that works, you should be
+able to run it under cron.
+
+Note: chroot, chrootuid, and other programs of this type are usually intended
+to be run by root, and should _not_ be setuid programs unless you _really_
+know what you are doing.
+
+Sample command line:
+
+ $ /usr/local/bin/chrootuid /var/rcynic rcynic /bin/rcynic -s -c /etc/rcynic.conf
+
+Note that we use absolute pathnames everywhere. This is not an accident.
+Programs running in jails under cron should not make assumptions about the
+current working directory or environment variable settings, and programs
+running in chroot jails would need different `PATH` settings anyway. Best just
+to specify everything.
+
+### Building static binaries
+
+On FreeBSD, building a staticly linked rsync is easy: one just sets the
+environment variable `LDFLAGS='-static'` before building rsync and the right
+thing will happen. Since this is really just GNU configure picking up the
+environment variable, the same trick should work on other platforms...except
+that some compilers don't support `-static`, and some platforms are missing
+some or all of the non-shared libraries you'd need to link the resulting
+binary.
+
+For simplicity, we've taken the same approach with rcynic, so
+
+ $ make LDFLAGS='-static'
+
+works. This isn't necessary on platforms where we know that static linking
+works -- the default is static linking where supported.
+
+### syslog from chrooted environment
+
+Depending on how the `syslog()` library call and the syslog daemon (`syslogd`,
+`rsyslogd`, ...) are implemented on your platform, syslog may not work
+properly with rcynic in a chroot jail. On FreeBSD, the easiest way to fix this
+is to add the following lines to /etc/rc.conf:
+
+ altlog_proglist="named rcynic"
+ rcynic_chrootdir="/var/rcynic"
+ rcynic_enable="YES"
+
+This tells syslogd to listen on an additional `PF_UNIX` socket within rcynic's
+chroot jail.
+
+[1]: 04.RPKI.Installation.FromSource.md
diff --git a/doc/manual/10.RPKI.RP.rcynicChroot.wiki b/doc/manual/10.RPKI.RP.rcynicChroot.wiki
new file mode 100644
index 00000000..d46be8a4
--- /dev/null
+++ b/doc/manual/10.RPKI.RP.rcynicChroot.wiki
@@ -0,0 +1,214 @@
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= Running rcynic chrooted =
+
+This is an attempt to describe the process of setting up rcynic in a
+chrooted environment. The installation scripts that ship with rcynic
+attempt to do this automatically when requested for the platforms we
+support, but the process is somewhat finicky, so some explanation
+seems in order. If you're running on one of the supported platforms,
+the following steps may be handled for you by the Makefiles, but you
+may still want to understand what all this is trying to do.
+
+rcynic itself does not include any direct support for running
+chrooted, but is designed to be (relatively) easy to run in a chroot
+jail.
+
+To enable chroot support during installation, you should
+[[wiki:doc/RPKI/Installation/FromSource|install from source]] and use
+the `--enable-rcynic-jail` option to `./configure`.
+
+rcynic-cron includes support for running chrooted. To use it, specify
+the `--chroot` option on rcynic-cron's command line. This will cause
+rcynic-cron to run rcynic in the chrooted environment. Note that, in
+order for this to work, rcynic-cron itself must run as root, since
+only root can issue the `chroot()` system call. When run as root,
+rcynic-cron takes care of changing the user ID of each process it
+starts to the unprivileged "`rcynic`" user.
+
+== Creating the chroot jail environment ==
+
+By far the most tedious and finicky part of setting up rcynic to run
+in a chroot jail is setting the jail itself. The underlying principal
+is simple and obvious: a process running in the jail can't use files
+outside the jail. The difficulty is that the list of files that needs
+to be in the jail is system-dependent, can be rather long, and
+sometimes can only be discovered by trial and error.
+
+You'll either need staticly linked copies of rcynic and rsync, or
+you'll need to figure out which shared libraries these programs need
+(try using the "ldd" command). Here we assume staticly linked
+binaries, because that's simpler, but be warned that statically linked
+binaries are not even possible on some platforms, whether due to
+concious decisions on the part of operating system vendors or due to
+hidden use of dynamic loading by other libraries at runtime. Once
+again, the Makefiles attempt to do the correct thing for your
+environment if they know what it is, but they might get it wrong.
+
+You may also find that the dynamic loader looks in a different place
+than you (and the Makefiles) would expect when running within the
+chroot jail. For example, you might think that library
+`/usr/local/lib/libfoo.so` being installed into a jail named
+`/var/rcynic` should go into `/var/rcynic/usr/local/lib/libfoo.so`,
+but we've seen cases where the dynamic loader ended up expecting to
+find it in `/var/rcynic/lib/libfoo.so`. Getting this right may
+require a bit of trial and error.
+
+You'll need a chroot wrapper program. As mentioned above, rcynic-cron
+can act as that wrapper program; if this works for you, we recommend
+it, because it works the same way on all platforms and doesn't require
+additional external programs. Otherwise, you'll have to find a
+suitable wrapper program. Your platform may already have one (FreeBSD
+does -- `/usr/sbin/chroot`), but if you don't, you can download Wietse
+Venema's "chrootuid" program from
+ftp://ftp.porcupine.org/pub/security/chrootuid1.3.tar.gz.
+
+ Warning::
+ The chroot program included in at least some GNU/Linux
+ distributions is not adaquate to this task. You need a wrapper
+ that knows how to drop privileges after performing the
+ chroot() operation itself. If in doubt, use chrootuid.
+
+Unfortunately, the precise details of setting up a proper chroot jail
+vary wildly from one system to another, so the following instructions
+may not be a precise match for the preferred way of doing this on your
+platform. Please feel free to contribute scripts for other platforms.
+
+1. Build the static binaries. You might want to test them at this
+ stage too, although you can defer that until after you've got the
+ jail built.
+
+2. Create a userid under which to run rcynic. Here we'll assume
+ that's a user named "rcynic", whose default group is also named
+ "rcynic". Do not add any other userids to the rcynic group unless
+ you really know what you are doing.
+
+3. Build the jail. You'll need, at minimum, a directory in which to
+ put the binaries, a subdirectory tree that's writable by the userid
+ which will be running rcynic and rsync, your trust anchors, and
+ whatever device inodes the various libraries need on your system.
+ Most likely the devices that matter will be `/dev/null`,
+ `/dev/random`, and `/dev/urandom`; if you're running a FreeBSD system
+ with devfs, you do this by mounting and configuring a devfs
+ instance in the jail, on other platforms you probably use the `mknod`
+ program or something similar.
+
+ Important::
+ Other than the directories that you want rcynic and rsync to
+ be able to modify, //nothing// in the initial jail setup should
+ be writable by the rcynic userid. In particular, rcynic and
+ rsync should //not// be allowed to modify: their own binary
+ images, any of the configuration files, or your trust anchors.
+ It's simplest just to have root own all the files and
+ directories that rcynic and rsync are not allowed to modify,
+ and make sure that the permissions for all of those
+ directories and files make them writable only by root.
+
+Sample jail tree, assuming that we're putting all of this under
+`/var/rcynic`:
+
+{{{
+#!sh
+$ mkdir /var/rcynic
+$ mkdir /var/rcynic/bin
+$ mkdir /var/rcynic/data
+$ mkdir /var/rcynic/dev
+$ mkdir /var/rcynic/etc
+$ mkdir /var/rcynic/etc/trust-anchors
+}}}
+
+Copy your trust anchors into `/var/rcynic/etc/trust-anchors`.
+
+Copy the staticly linked rcynic and rsync into `/var/rcynic/bin`.
+
+Copy `/etc/resolv.conf` and `/etc/localtime` (if it exists) into
+`/var/rcynic/etc`.
+
+Write an rcynic configuration file as `/var/rcynic/etc/rcynic.conf`.
+Path names in this file must match the jail setup, more on this below.
+
+{{{
+#!sh
+$ chmod -R go-w /var/rcynic
+$ chown -R root:wheel /var/rcynic
+$ chown -R rcynic:rcynic /var/rcynic/data
+}}}
+
+If you're using devfs, arrange for it to be mounted at
+`/var/rcynic/dev`; otherwise, create whatever device inodes you need in
+`/var/rcynic/dev` and make sure that they have sane permissions (copying
+whatever permissions are used in your system `/dev` directory should
+suffice).
+
+`rcynic.conf` to match this configuration:
+
+{{{
+#!ini
+
+[rcynic]
+
+rsync-program = /bin/rsync
+authenticated = /data/authenticated
+unauthenticated = /data/unauthenticated
+xml-summary = /data/rcynic.xml
+trust-anchor-directory = /etc/trust-anchors
+}}}
+
+Once you've got all this set up, you're ready to try running rcynic in
+the jail. Try it from the command line first, then if that works, you
+should be able to run it under cron.
+
+Note: chroot, chrootuid, and other programs of this type are usually
+intended to be run by root, and should //not// be setuid programs
+unless you //really// know what you are doing.
+
+Sample command line:
+
+{{{
+#!sh
+$ /usr/local/bin/chrootuid /var/rcynic rcynic /bin/rcynic -s -c /etc/rcynic.conf
+}}}
+
+Note that we use absolute pathnames everywhere. This is not an
+accident. Programs running in jails under cron should not make
+assumptions about the current working directory or environment
+variable settings, and programs running in chroot jails would need
+different `PATH` settings anyway. Best just to specify everything.
+
+=== Building static binaries ===
+
+On FreeBSD, building a staticly linked rsync is easy: one just sets
+the environment variable `LDFLAGS='-static'` before building rsync and
+the right thing will happen. Since this is really just GNU configure
+picking up the environment variable, the same trick should work on
+other platforms...except that some compilers don't support `-static`,
+and some platforms are missing some or all of the non-shared libraries
+you'd need to link the resulting binary.
+
+For simplicity, we've taken the same approach with rcynic, so
+
+{{{
+#!sh
+$ make LDFLAGS='-static'
+}}}
+
+works. This isn't necessary on platforms where we know that static
+linking works -- the default is static linking where supported.
+
+=== syslog from chrooted environment ===
+
+Depending on how the `syslog()` library call and the syslog daemon
+(`syslogd`, `rsyslogd`, ...) are implemented on your platform, syslog
+may not work properly with rcynic in a chroot jail. On FreeBSD, the
+easiest way to fix this is to add the following lines to /etc/rc.conf:
+
+{{{
+#!sh
+altlog_proglist="named rcynic"
+rcynic_chrootdir="/var/rcynic"
+rcynic_enable="YES"
+}}}
+
+This tells syslogd to listen on an additional `PF_UNIX` socket within
+rcynic's chroot jail.
diff --git a/doc/manual/11.RPKI.CA.md b/doc/manual/11.RPKI.CA.md
new file mode 100644
index 00000000..a26f91e9
--- /dev/null
+++ b/doc/manual/11.RPKI.CA.md
@@ -0,0 +1,242 @@
+# RPKI CA Engine
+
+The RPKI CA engine is an implementation of the production-side tools for
+generating certificates, CRLs, ROAs, and other RPKI objects. The CA tools are
+implemented primarily in Python, with an extension module linked against an
+RFC-3779-enabled version of the OpenSSL libraries to handle some of the low-
+level details.
+
+See the [relying party tools][1] for tools for retrieving, verifying, and
+using RPKI data.
+
+## Getting started
+
+If you just want to get started with the CA tools and hate reading
+documentation, here's a roadmap on what you do need to read:
+
+ 1. Start with the [installation instructions][2]; if you're using pre-built packages you may be able to skip this step.
+ 2. Then read the [configuration instructions][3]
+ 3. Then the [MySQL setup instructions][4]
+ 4. And finally either the [command line tool][5] or [web interface][6]
+
+## Overview of the CA engine
+
+### Terminology
+
+A few special terms appear often enough in code and documentation that they
+need explaining.
+
+IRBE::
+
+> "Internet Registry Back End."
+
+IRDB::
+
+> "Internet Registry Data Base."
+
+BPKI::
+
+> "Business PKI."
+
+RPKI::
+
+> "Resource PKI."
+
+### Programs
+
+See the [installation instructions][2] for how to build and install the code.
+
+The RPKI CA engine includes the following programs:
+
+rpkid::
+
+> The main RPKI engine daemon.
+
+pubd::
+
+> The publication engine daemon.
+
+rootd::
+
+> A separate daemon for handling the root of an RPKI certificate tree. This is
+essentially a stripped down version of rpkid with no SQL database, no left-
+right protocol implementation, and only the parent side of the up-down
+protocol. It's separate because the root is a special case in several ways and
+it was simpler to keep the special cases out of the main daemon.
+
+irdbd::
+
+> A sample implementation of an IR database daemon. rpkid calls into this to
+perform lookups via the left-right protocol.
+
+rpkic::
+
+> A command line interface to control rpkid and pubd.
+
+GUI::
+
+> A web-based graphical interface to control rpkid and pubd.
+
+irdbd, rpkic, and the GUI collectively make up the "Internet registry back
+end" (IRBE) component of the system.
+
+These programs take configuration files in a common format similar to that
+used by the OpenSSL command line tool, see the [configuration guide][3] for
+details.
+
+Basic operation consists of creating the appropriate MySQL databases (see
+[MySQL setup][4]), starting the daemons, and using [rpkic][5] or [the web
+interface][6] to configure relationships between parents and children,
+relationships between publication clients and repositories, allocate resources
+to children, and create ROAs. Once setup is complete, rpkid should maintain
+the requested data automatically, including re-querying its parent(s)
+periodically to check for changes, reissuing certificates and other objects as
+needed, and so forth.
+
+The daemons are all event-driven, and are (in theory) capable of supporting an
+arbitrary number of hosted RPKI engines to run in a single rpkid instance, up
+to the performance limits of the underlying hardware.
+
+## Starting the servers
+
+You need to follow the instructions in the [configuration guide][3] before
+attempting to start the servers.
+
+Once you've written the servers' configuration file, the easiest way to run
+the servers is to run the `rpki-start-servers` script, which examines your
+`rpki.conf` file and starts the appropriate servers in background.
+
+If you prefer, you can run each server by hand instead of using the script,
+eg, using Bourne shell syntax to run rpkid in background:
+
+ rpkid &
+ echo >rpkid.pid "$!"
+
+You can also use separate configuration files for each server if necessary,
+run multiple copies of the same server with different configuration files, and
+so forth.
+
+All of the daemons use syslog by default. You can change this by running
+either the servers themselves or the `rpki-start-servers` script with the "-d"
+option. Used as an argument to a server directly, "-d" causes that server to
+log to stderr instead of to syslog. Used as an argument to `rpki-start-
+servers`, "-d" starts each of the servers with "-d" while redirecting stderr
+from each server to a separate log file. This is intended primarily for
+debugging.
+
+Some of the configuration options are common to all daemons: which daemon they
+affect depends only on which sections of the configuration file they are in.
+See [Common Options][7] for details.
+
+### rpkid
+
+rpkid is the main RPKI engine daemon. Configuration of rpkid is a two step
+process: a config file to bootstrap rpkid to the point where it can speak
+using the [left-right protocol][8], followed by dynamic configuration via the
+left-right protocol. The latter stage is handled by the [command line tool][5]
+or the [web interface][6].
+
+rpkid stores dynamic data in an SQL database, which must have been created for
+it, as explained in in the [MySQL setup instructions][4].
+
+### pubd
+
+pubd is the publication daemon. It implements the server side of the
+publication protocol, and is used by rpkid to publish the certificates and
+other objects that rpkid generates.
+
+pubd is separate from rpkid for two reasons:
+
+ * The hosting model allows entities which choose to run their own copies of rpkid to publish their output under a common publication point. In general, encouraging shared publication services where practical is a good thing for relying parties, as it will speed up rcynic synchronization time.
+ * The publication server has to run on (or at least close to) the publication point itself, which in turn must be on a publically reachable server to be useful. rpkid, on the other hand, need only be reachable by the IRBE and its children in the RPKI tree. rpkid is a much more complex piece of software than pubd, so in some situations it might make sense to wrap tighter firewall constraints around rpkid than would be practical if rpkid and pubd were a single program.
+
+pubd stores dynamic data in an SQL database, which must have been created for
+it, as explained in the [MySQL setup instructions][4]. pubd also stores the
+published objects themselves as disk files in a configurable location which
+should correspond to an appropriate module definition in rsync.conf; see the
+[configuration guide][3] for details.
+
+### rootd
+
+rootd is a stripped down implmenetation of (only) the server side of the up-
+down protocol. It's a separate program because the root certificate of an RPKI
+certificate tree requires special handling and may also require a special
+handling policy. rootd is a simple implementation intended for test use, it's
+not suitable for use in a production system. All configuration comes via the
+config file; see the [configuration guide][3] for details.
+
+### irdbd
+
+irdbd is a sample implemntation of the server side of the IRDB callback subset
+of the left-right protocol. In production use this service is a function of
+the IRBE stub; irdbd may be suitable for production use in simple cases, but
+an IR with a complex IRDB may need to extend or rewrite irdbd.
+
+irdbd is part of the IR back-end system, and shares its SQL database with
+rpkic and the web interface.
+
+The package actually includes a second implementation of irdbd, used only for
+testing: `ca/tests/old_irdbd` is a mininmal implementation, used only by
+smoketest, which itself constitues a fairly complete (if rather strange) IRBE
+implementatation. Ordinarly you won't care about this, but if for some reason
+you need to write your own irdbd implementation, you might find it easier to
+start from the minimal version.
+
+See the [configuration guide][3] for details on configuring irdbd.
+
+## Test programs
+
+The package includes two separate test programs, which take similar test
+description files but use them in different ways. The test tools are only
+present in the source tree ("make install" does not install them).
+
+Unlike the configuration files used by the other programs, these test programs
+read test descriptions written in the YAML serialization language (see
+<http://www.yaml.org/> for more information on YAML). Each test script
+describes a hierarchy of RPKI entities, including hosting relationships and
+resource assignments, in a relatively compact form. The test programs use
+these descriptions to generate a set of configuration files, populate the back
+end database, and drive the test.
+
+See the [test configuration language][9] for details on the content of these
+YAML files.
+
+### smoketest
+
+smoketest is a test harness to set up and run a collection of rpkid and irdbd
+instances under scripted control. The YAML test description defines the test
+configuration for smoketest to run, including initial resource assignments.
+Subsequent YAML "documents" in the same description file define an ordered
+series of changes to be made to the configuration. smoketest runs the rcynic
+RPKI validator between each update cycle, to check the output of the CA
+programs.
+
+smoketest is designed to support running a fairly wide set of test
+configurations as canned scripts, without writing any new control code. The
+intent is to make it possible to write meaningful regression tests.
+
+### yamltest
+
+yamltest is another test harness to set up and run a collection of rpkid and
+irdbd instances under scripted control. It is similar in many ways to, and
+uses the same YAML test description language, but its purpose is different:
+smoketest runs a particular test scenario through a series of changes, then
+shuts it down; yamltest, on the other hand, sets up a test network using the
+same tools that a real user would use (principally the rpkic tool), and leaves
+the test running indefinitely.
+
+At present, this means that yamltest ignores all but the first "document" in a
+test description file. This may change in the future.
+
+Running yamltest will generate a fairly complete set configuration files,
+which may be useful as examples.
+
+[1]: 05.RPKI.RP.md
+[2]: 01.RPKI.Installation.md
+[3]: 12.RPKI.CA.Configuration.md
+[4]: 24.RPKI.CA.MySQLSetup.md
+[5]: 27.RPKI.CA.UI.rpkic.md
+[6]: 28.RPKI.CA.UI.GUI.md
+[7]: 13.RPKI.CA.Configuration.Common.md
+[8]: 35.RPKI.CA.Protocols.LeftRight.md
+[9]: 22.RPKI.CA.Configuration.Tests.md
diff --git a/doc/manual/11.RPKI.CA.wiki b/doc/manual/11.RPKI.CA.wiki
new file mode 100644
index 00000000..9fd1f7f0
--- /dev/null
+++ b/doc/manual/11.RPKI.CA.wiki
@@ -0,0 +1,264 @@
+= RPKI CA Engine =
+
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+The RPKI CA engine is an implementation of the production-side tools
+for generating certificates, CRLs, ROAs, and other RPKI objects. The
+CA tools are implemented primarily in Python, with an extension module
+linked against an RFC-3779-enabled version of the OpenSSL libraries
+to handle some of the low-level details.
+
+See the [[RP|relying party tools]] for tools for retrieving,
+verifying, and using RPKI data.
+
+== Getting started ==
+
+If you just want to get started with the CA tools and hate reading
+documentation, here's a roadmap on what you do need to read:
+
+1. Start with the [[Installation|installation instructions]]; if you're using pre-built packages you may be able to skip this step.
+
+2. Then read the [[./Configuration|configuration instructions]]
+
+3. Then the [[./MySQLSetup|MySQL setup instructions]]
+
+4. And finally either the [[./UI/rpkic|command line tool]] or [[./UI/GUI|web interface]]
+
+== Overview of the CA engine ==
+
+=== Terminology ===
+
+A few special terms appear often enough in code and documentation that
+they need explaining.
+
+IRBE::
+ "Internet Registry Back End."
+
+IRDB::
+ "Internet Registry Data Base."
+
+BPKI::
+ "Business PKI."
+
+RPKI::
+ "Resource PKI."
+
+=== Programs ===
+
+See the [[Installation|installation instructions]] for how to build and install the code.
+
+The RPKI CA engine includes the following programs:
+
+rpkid::
+ The main RPKI engine daemon.
+
+pubd::
+ The publication engine daemon.
+
+rootd::
+
+ A separate daemon for handling the root of an RPKI certificate
+ tree. This is essentially a stripped down version of rpkid
+ with no SQL database, no left-right protocol implementation,
+ and only the parent side of the up-down protocol. It's
+ separate because the root is a special case in several ways
+ and it was simpler to keep the special cases out of the main
+ daemon.
+
+irdbd::
+ A sample implementation of an IR database daemon. rpkid calls
+ into this to perform lookups via the left-right protocol.
+
+rpkic::
+ A command line interface to control rpkid and pubd.
+
+GUI::
+ A web-based graphical interface to control rpkid and pubd.
+
+irdbd, rpkic, and the GUI collectively make up the "Internet registry
+back end" (IRBE) component of the system.
+
+These programs take configuration files in a common format similar to
+that used by the OpenSSL command line tool, see the
+[[./Configuration|configuration guide]] for details.
+
+Basic operation consists of creating the appropriate MySQL databases
+(see [[./MySQLSetup|MySQL setup]]), starting the daemons, and using
+[[./UI/rpkic|rpkic]] or [[./UI/GUI|the web interface]] to configure
+relationships between parents and children, relationships between
+publication clients and repositories, allocate resources to children,
+and create ROAs. Once setup is complete, rpkid should maintain the
+requested data automatically, including re-querying its parent(s)
+periodically to check for changes, reissuing certificates and other
+objects as needed, and so forth.
+
+The daemons are all event-driven, and are (in theory) capable of
+supporting an arbitrary number of hosted RPKI engines to run in a
+single rpkid instance, up to the performance limits of the underlying
+hardware.
+
+== Starting the servers ==
+
+You need to follow the instructions in the
+[[./Configuration|configuration guide]] before attempting to start the
+servers.
+
+Once you've written the servers' configuration file, the easiest way
+to run the servers is to run the `rpki-start-servers` script,
+which examines your `rpki.conf` file and starts the appropriate
+servers in background.
+
+If you prefer, you can run each server by hand instead of using the
+script, eg, using Bourne shell syntax to run rpkid in background:
+
+{{{
+#!sh
+rpkid &
+echo >rpkid.pid "$!"
+}}}
+
+You can also use separate configuration files for each server if
+necessary, run multiple copies of the same server with different
+configuration files, and so forth.
+
+All of the daemons use syslog by default. You can change this by
+running either the servers themselves or the `rpki-start-servers`
+script with the "-d" option. Used as an argument to a server
+directly, "-d" causes that server to log to stderr instead of to
+syslog. Used as an argument to `rpki-start-servers`, "-d" starts
+each of the servers with "-d" while redirecting stderr from each
+server to a separate log file. This is intended primarily for
+debugging.
+
+Some of the configuration options are common to all daemons: which
+daemon they affect depends only on which sections of the configuration
+file they are in. See [[./Configuration/Common|Common Options]] for
+details.
+
+=== rpkid ===
+
+rpkid is the main RPKI engine daemon. Configuration of rpkid is a two
+step process: a config file to bootstrap rpkid to the point where it
+can speak using the [[./Protocols/LeftRight|left-right protocol]],
+followed by dynamic configuration via the left-right protocol. The
+latter stage is handled by the [[./UI/rpkic|command line tool]] or the
+[[./UI/GUI|web interface]].
+
+rpkid stores dynamic data in an SQL database, which must have been
+created for it, as explained in in the
+[[./MySQLSetup|MySQL setup instructions]].
+
+=== pubd ===
+
+pubd is the publication daemon. It implements the server side of
+the publication protocol, and is used by rpkid to publish the
+certificates and other objects that rpkid generates.
+
+pubd is separate from rpkid for two reasons:
+
+* The hosting model allows entities which choose to run their own
+ copies of rpkid to publish their output under a common publication
+ point. In general, encouraging shared publication services where
+ practical is a good thing for relying parties, as it will speed up
+ rcynic synchronization time.
+
+* The publication server has to run on (or at least close to) the
+ publication point itself, which in turn must be on a publically
+ reachable server to be useful. rpkid, on the other hand, need only
+ be reachable by the IRBE and its children in the RPKI tree. rpkid
+ is a much more complex piece of software than pubd, so in some
+ situations it might make sense to wrap tighter firewall constraints
+ around rpkid than would be practical if rpkid and pubd were a single
+ program.
+
+pubd stores dynamic data in an SQL database, which must have been
+created for it, as explained in the
+[[./MySQLSetup|MySQL setup instructions]].
+pubd also stores the published objects themselves as disk files in a
+configurable location which should correspond to an appropriate module
+definition in rsync.conf; see the
+[[./Configuration|configuration guide]] for details.
+
+=== rootd ===
+
+rootd is a stripped down implmenetation of (only) the server side of
+the up-down protocol. It's a separate program because the root
+certificate of an RPKI certificate tree requires special handling and
+may also require a special handling policy. rootd is a simple
+implementation intended for test use, it's not suitable for use in a
+production system. All configuration comes via the config file; see
+the [[./Configuration|configuration guide]] for details.
+
+=== irdbd ===
+
+irdbd is a sample implemntation of the server side of the IRDB
+callback subset of the left-right protocol. In production use this
+service is a function of the IRBE stub; irdbd may be suitable for
+production use in simple cases, but an IR with a complex IRDB may need
+to extend or rewrite irdbd.
+
+irdbd is part of the IR back-end system, and shares its SQL database
+with rpkic and the web interface.
+
+The package actually includes a second implementation of irdbd, used
+only for testing: `ca/tests/old_irdbd` is a mininmal
+implementation, used only by smoketest, which itself constitues
+a fairly complete (if rather strange) IRBE implementatation.
+Ordinarly you won't care about this, but if for some reason you need
+to write your own irdbd implementation, you might find it easier to
+start from the minimal version.
+
+See the [[./Configuration|configuration guide]] for details on
+configuring irdbd.
+
+== Test programs ==
+
+The package includes two separate test programs, which take similar
+test description files but use them in different ways. The test tools
+are only present in the source tree ("make install" does not install
+them).
+
+Unlike the configuration files used by the other programs, these test
+programs read test descriptions written in the YAML serialization
+language (see http://www.yaml.org/ for more information on YAML).
+Each test script describes a hierarchy of RPKI entities, including
+hosting relationships and resource assignments, in a relatively
+compact form. The test programs use these descriptions to generate a
+set of configuration files, populate the back end database, and drive
+the test.
+
+See the [[./Configuration/Tests|test configuration language]] for
+details on the content of these YAML files.
+
+=== smoketest === #smoketest
+
+smoketest is a test harness to set up and run a collection of rpkid
+and irdbd instances under scripted control. The YAML test description
+defines the test configuration for smoketest to run, including initial
+resource assignments. Subsequent YAML "documents" in the same
+description file define an ordered series of changes to be made to the
+configuration. smoketest runs the rcynic RPKI validator between each
+update cycle, to check the output of the CA programs.
+
+smoketest is designed to support running a fairly wide set of test
+configurations as canned scripts, without writing any new control
+code. The intent is to make it possible to write meaningful
+regression tests.
+
+=== yamltest ===
+
+yamltest is another test harness to set up and run a collection of
+rpkid and irdbd instances under scripted control. It is similar in
+many ways to, and uses the same YAML test description language, but
+its purpose is different: smoketest runs a particular test scenario
+through a series of changes, then shuts it down; yamltest, on the
+other hand, sets up a test network using the same tools that a real
+user would use (principally the rpkic tool), and leaves the test
+running indefinitely.
+
+At present, this means that yamltest ignores all but the first
+"document" in a test description file. This may change in the future.
+
+Running yamltest will generate a fairly complete set configuration
+files, which may be useful as examples.
diff --git a/doc/manual/12.RPKI.CA.Configuration.md b/doc/manual/12.RPKI.CA.Configuration.md
new file mode 100644
index 00000000..22804b18
--- /dev/null
+++ b/doc/manual/12.RPKI.CA.Configuration.md
@@ -0,0 +1,192 @@
+# Configuring the RPKI CA tools: `rpki.conf`
+
+This section describes `rpki.conf`, the the configuration file for the RPKI CA
+tools.
+
+The first subsection is a quick summary of the options you're most likely to
+need to configure (or at least check) for a basic setup.
+
+The rest of this section contains a more complete reference to the
+configuration file and some of the things you might need to do with it if your
+needs are more complex.
+
+There are a lot of configuration options, but in most cases you will never
+have to touch more than a few of them. Keep reading, and don't panic.
+
+## Quick guide to the most common configuration options
+
+This subsection describes only a handful of `rpki.conf` configuration options.
+These are the ones you'll need to set, or at least check, as part of initial
+installation. In general, the installation process will have already set sane
+values for these, but you may need to a few of them depending on exactly what
+you're doing.
+
+The location of `rpki.conf` varies depending on the operating system you're
+running and how you installed the software. Unless you did something unusual
+during installation, it's either `/etc/rpki.conf` or
+`/usr/local/etc/rpki.conf`.
+
+ * All of the configuration options you're most likely to need to change are in the `[myrpki]` section of `rpki.conf`.
+
+ [myrpki]
+
+ * You need to check the setting of `rpkid_server_host`. The installation process sets this to the fully-qualified DNS hostname of the server on which you installed the code, but if you use a service-specific DNS name for RPKI service you will need to change this option to match that service name.
+
+ rpkid_server_host = rpkid.example.org
+
+ * You need to set the value of `run_pubd` to reflect whether you intend to run your own RPKI publication server and rsync server.
+
+ run_pubd = yes
+
+> or
+
+ run_pubd = no
+
+ * If you are running your own RPKI publication server, you need to check the setting of `pubd_server_host`. The installation process sets this to the fully-qualified DNS hostname of the server on which you installed the code, but if you use a service-specific DNS name for RPKI publication service you will need to change this option to match that service name.
+
+ pubd_server_host = pubd.example.org
+
+There are _many_ other configuration options, but setting the above correctly
+should suffice to get you started with the default configuration. Read on for
+details if you need to know more, otherwise go to [next steps][1].
+
+## Configuration file syntax
+
+The general format of `rpki.conf` is the same as the configuration language
+used by many other programs, including the OpenSSL package. The file is
+divided into "sections", labeled with square brackets; individual options
+within a section look like variable assignments, with the option name on the
+left and the option value on the right.
+
+ [foo]
+
+ bar = fred
+ baz = 42
+
+The configuration file parser supports a limited version of the macro facility
+used in OpenSSL's configuration parser. An expression such as
+
+ foo = ${bar::baz}
+
+sets foo to the value of the baz variable from section bar.
+
+The section name `ENV` is special: it refers to environment variables.
+
+ home = ${ENV::HOME}
+
+Each of the programs that make up the RPKI tookit can potentially take its own
+configuration file, but for most uses this is unnecessarily complicated. The
+recommended approach is to use a single configuration file, and to put all of
+the parameters that a normal user might need to change into a single section
+of that configuration file, then reference these common settings from the
+program-specific sections of the configuration file via macro expansion.
+
+The default name for the shared configuration file is `rpki.conf`. The
+location of the system-wide `rpki.conf` file is selected by `./configure`
+during installation. The default location is `/usr/local/etc/rpki.conf` when
+building from source or on platforms like FreeBSD or MacOSX where packaged
+software goes in the `/usr/local` tree; on GNU/Linux platforms, binary
+packages will use `/etc/rpki.conf` per GNU/Linux convention.
+
+Regardless of the default location, you can override the build-time default
+filename at runtime if necessary by setting the `RPKI_CONF` environment
+variable to the name of the configuration file you want to use. Most of the
+programs also take a command-line option (generally "`-c`") specifying the
+name of the configuration file; if both the command line option and the
+environment variable are set, the command line option wins.
+
+The installation process builds a sample configuration file `rpki.conf.sample`
+and installs it alongside of `rpki.conf`. If you have no `rpki.conf`
+installed, the installation process will copy `rpki.conf.sample` to
+`rpki.conf`, but it will not overwrite an existing `rpki.conf` file.
+
+## Too much information about `rpki.conf` options
+
+The list of options that you can set in `rpki.conf` is ridiculously long. The
+default configuration includes what we hope are reasonable default settings
+for all of them, so in many cases you will never need to know about most of
+these options. A number of the options for individual programs are specified
+in terms of other options, using the macro facility [described above][2].
+
+In general, if you don't understand what an option does, you probably should
+leave it alone.
+
+Detailed information about individual options is listed in separate sections,
+one per section of `rpki.conf`. These documentation sections are generated
+from the same source file as the sample configuration file.
+
+ * [ Common Options ][3]
+ * [ [myrpki] section ][4]
+ * [ [rpkid] section ][5]
+ * [ [irdbd] section ][6]
+ * [ [pubd] section ][7]
+ * [ [rootd] section ][8]
+ * [ [web_portal] section ][9]
+ * [ [autoconf] section ][10]
+
+## rsyncd.conf
+
+If you're running pubd, you'll also need to run rsyncd. Your rsyncd
+configuration will need to match your pubd configuration in order for relying
+parties to find the RPKI objects managed by pubd.
+
+Here's a sample rsyncd.conf file:
+
+ pid file = /var/run/rsyncd.pid
+ uid = nobody
+ gid = nobody
+
+ [rpki]
+ use chroot = no
+ read only = yes
+ transfer logging = yes
+ path = /some/where/publication
+ comment = RPKI publication
+
+You may need to adapt this to your system. In particular, you will need to set
+the `path` option to match the directory you named as
+`publication_base_directory` in `rpki.conf`.
+
+You may need to do something more complicated if you are already running
+rsyncd for other purposes. See the `rsync(1)` and `rsyncd.conf(5)` manual
+pages for more details.
+
+## Running your own RPKI root
+
+In general, we do not recommend running your own RPKI root environment, for
+various reasons. If, however, you need to do so, you should read [ the
+documentation for the [rootd] section ][8], and [ the instructions for
+creating a RPKI root certificate ][11].
+
+## Running rpkid or pubd on a different server
+
+The default configuration runs rpkid, pubd (if enabled) and the back end code
+all on the same server. For most purposes, this is fine, but in some cases you
+might want to split these functions up among different servers. If you need to
+do this, see [these instructions][12].
+
+## Configuring the test harness
+
+We expect the test harness to be of interest primarily to developers, but if
+you need to understand how it works, you will probably want to read [these
+instructions][13].
+
+## Next steps
+
+Once you've finished with configuration, the next thing you should read is the
+[MySQL setup instructions][14].
+
+[1]: 12.RPKI.CA.Configuration.md
+[2]: 12.RPKI.CA.Configuration.md
+[3]: 13.RPKI.CA.Configuration.Common.md
+[4]: 14.RPKI.CA.Configuration.myrpki.md
+[5]: 15.RPKI.CA.Configuration.rpkid.md
+[6]: 16.RPKI.CA.Configuration.irdbd.md
+[7]: 17.RPKI.CA.Configuration.pubd.md
+[8]: 18.RPKI.CA.Configuration.rootd.md
+[9]: 20.RPKI.CA.Configuration.web_portal.md
+[10]: 21.RPKI.CA.Configuration.autoconf.md
+[11]: 19.RPKI.CA.Configuration.CreatingRoot.md
+[12]: 23.RPKI.CA.Configuration.DifferentServer.md
+[13]: 22.RPKI.CA.Configuration.Tests.md
+[14]: 24.RPKI.CA.MySQLSetup.md
diff --git a/doc/manual/12.RPKI.CA.Configuration.wiki b/doc/manual/12.RPKI.CA.Configuration.wiki
new file mode 100644
index 00000000..410215d8
--- /dev/null
+++ b/doc/manual/12.RPKI.CA.Configuration.wiki
@@ -0,0 +1,263 @@
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= Configuring the RPKI CA tools: `rpki.conf` =
+
+This section describes `rpki.conf`, the the configuration file for the
+RPKI CA tools.
+
+The first subsection is a quick summary of the options you're most
+likely to need to configure (or at least check) for a basic setup.
+
+The rest of this section contains a more complete reference to the
+configuration file and some of the things you might need to do with it
+if your needs are more complex.
+
+There are a lot of configuration options, but in most cases you will
+never have to touch more than a few of them. Keep reading, and don't
+panic.
+
+== Quick guide to the most common configuration options ==
+
+This subsection describes only a handful of `rpki.conf` configuration
+options. These are the ones you'll need to set, or at least check, as
+part of initial installation. In general, the installation process
+will have already set sane values for these, but you may need to a few
+of them depending on exactly what you're doing.
+
+The location of `rpki.conf` varies depending on the operating system
+you're running and how you installed the software. Unless you did
+something unusual during installation, it's either `/etc/rpki.conf` or
+`/usr/local/etc/rpki.conf`.
+
+{{{
+#!comment
+
+Should we even discuss `handle` here? We no longer create any
+ResourceHolderCA automatically, so it's almost irrelevant at this
+point, and we'd like to get rid of it eventually. Leave it out for
+now and see if anybody complains, I guess.
+
+}}}
+
+* All of the configuration options you're most likely to need to change
+ are in the `[myrpki]` section of `rpki.conf`.
+
+ {{{
+ #!ini
+ [myrpki]
+ }}}
+
+* You need to check the setting of `rpkid_server_host`. The
+ installation process sets this to the fully-qualified DNS hostname
+ of the server on which you installed the code, but if you use a
+ service-specific DNS name for RPKI service you will need to change
+ this option to match that service name.
+
+ {{{
+ #!ini
+ rpkid_server_host = rpkid.example.org
+ }}}
+
+* You need to set the value of `run_pubd` to reflect whether you
+ intend to run your own RPKI publication server and rsync server.
+
+ {{{
+ #!ini
+ run_pubd = yes
+ }}}
+
+ or
+
+ {{{
+ #!ini
+ run_pubd = no
+ }}}
+
+* If you are running your own RPKI publication server, you need to
+ check the setting of `pubd_server_host`. The installation process
+ sets this to the fully-qualified DNS hostname of the server on which
+ you installed the code, but if you use a service-specific DNS name
+ for RPKI publication service you will need to change this option to
+ match that service name.
+
+ {{{
+ #!ini
+ pubd_server_host = pubd.example.org
+ }}}
+
+
+There are //many// other configuration options, but setting the above
+correctly should suffice to get you started with the default
+configuration. Read on for details if you need to know more,
+otherwise go to [[#nextsteps|next steps]].
+
+
+== Configuration file syntax == #syntax
+
+The general format of `rpki.conf` is the same as the configuration
+language used by many other programs, including the OpenSSL package.
+The file is divided into "sections", labeled with square brackets;
+individual options within a section look like variable assignments,
+with the option name on the left and the option value on the right.
+
+{{{
+#!ini
+[foo]
+
+bar = fred
+baz = 42
+}}}
+
+The configuration file parser supports a limited version of the macro
+facility used in OpenSSL's configuration parser. An expression such
+as
+
+{{{
+#!ini
+foo = ${bar::baz}
+}}}
+
+sets foo to the value of the baz variable from section
+bar.
+
+The section name `ENV` is special: it refers to environment variables.
+
+{{{
+#!ini
+home = ${ENV::HOME}
+}}}
+
+Each of the programs that make up the RPKI tookit can potentially take
+its own configuration file, but for most uses this is unnecessarily
+complicated. The recommended approach is to use a single
+configuration file, and to put all of the parameters that a normal
+user might need to change into a single section of that configuration
+file, then reference these common settings from the program-specific
+sections of the configuration file via macro expansion.
+
+The default name for the shared configuration file is `rpki.conf`.
+The location of the system-wide `rpki.conf` file is selected by
+`./configure` during installation. The default location is
+`/usr/local/etc/rpki.conf` when building from source or on platforms
+like FreeBSD or MacOSX where packaged software goes in the
+`/usr/local` tree; on GNU/Linux platforms, binary packages will use
+`/etc/rpki.conf` per GNU/Linux convention.
+
+Regardless of the default location, you can override the build-time
+default filename at runtime if necessary by setting the `RPKI_CONF`
+environment variable to the name of the configuration file you want to
+use. Most of the programs also take a command-line option (generally
+"`-c`") specifying the name of the configuration file; if both the
+command line option and the environment variable are set, the command
+line option wins.
+
+The installation process builds a sample configuration file
+`rpki.conf.sample` and installs it alongside of `rpki.conf`. If you
+have no `rpki.conf` installed, the installation process will copy
+`rpki.conf.sample` to `rpki.conf`, but it will not overwrite an
+existing `rpki.conf` file.
+
+== Too much information about `rpki.conf` options ==
+
+The list of options that you can set in `rpki.conf` is ridiculously
+long. The default configuration includes what we hope are reasonable
+default settings for all of them, so in many cases you will never need
+to know about most of these options. A number of the options for
+individual programs are specified in terms of other options, using the
+macro facility [[#syntax|described above]].
+
+In general, if you don't understand what an option does, you probably
+should leave it alone.
+
+Detailed information about individual options is listed in separate
+sections, one per section of `rpki.conf`. These documentation
+sections are generated from the same source file as the sample
+configuration file.
+
+{{{
+#!comment
+
+See notes in doc/RPKI/TOC about the format of link labels containing
+square brackets like rpki.conf section names, and be careful here,
+because the syntax is somewhat finicky.
+
+}}}
+
+* [[wiki:doc/RPKI/CA/Configuration/Common| Common Options ]]
+* [[wiki:doc/RPKI/CA/Configuration/myrpki| [myrpki] section ]]
+* [[wiki:doc/RPKI/CA/Configuration/rpkid| [rpkid] section ]]
+* [[wiki:doc/RPKI/CA/Configuration/irdbd| [irdbd] section ]]
+* [[wiki:doc/RPKI/CA/Configuration/pubd| [pubd] section ]]
+* [[wiki:doc/RPKI/CA/Configuration/rootd| [rootd] section ]]
+* [[wiki:doc/RPKI/CA/Configuration/web_portal| [web_portal] section ]]
+* [[wiki:doc/RPKI/CA/Configuration/autoconf| [autoconf] section ]]
+
+{{{
+#!comment
+
+Still have to write subsections linking to:
+
+ * [wiki:doc/RPKI/CA/Configuration/CreatingRoot Creating a RPKI Root Certificate]
+ * [wiki:doc/RPKI/CA/Configuration/Tests Test configuration]
+ * [wiki:doc/RPKI/CA/Configuration/DifferentServer Using Different Servers]
+
+}}}
+
+== rsyncd.conf ==
+
+If you're running pubd, you'll also need to run rsyncd. Your rsyncd
+configuration will need to match your pubd configuration in order for
+relying parties to find the RPKI objects managed by pubd.
+
+Here's a sample rsyncd.conf file:
+
+{{{
+#!ini
+pid file = /var/run/rsyncd.pid
+uid = nobody
+gid = nobody
+
+[rpki]
+ use chroot = no
+ read only = yes
+ transfer logging = yes
+ path = /some/where/publication
+ comment = RPKI publication
+}}}
+
+You may need to adapt this to your system. In particular, you will
+need to set the `path` option to match the directory you named as
+`publication_base_directory` in `rpki.conf`.
+
+You may need to do something more complicated if you are already
+running rsyncd for other purposes. See the `rsync(1)` and
+`rsyncd.conf(5)` manual pages for more details.
+
+== Running your own RPKI root ==
+
+In general, we do not recommend running your own RPKI root
+environment, for various reasons. If, however, you need to do so, you
+should read
+[[wiki:doc/RPKI/CA/Configuration/rootd| the documentation for the [rootd] section ]],
+and
+[[wiki:doc/RPKI/CA/Configuration/CreatingRoot| the instructions for creating a RPKI root certificate ]].
+
+== Running rpkid or pubd on a different server ==
+
+The default configuration runs rpkid, pubd (if enabled) and the back
+end code all on the same server. For most purposes, this is fine, but
+in some cases you might want to split these functions up among
+different servers. If you need to do this, see
+[wiki:doc/RPKI/CA/Configuration/DifferentServer these instructions].
+
+== Configuring the test harness ==
+
+We expect the test harness to be of interest primarily to developers,
+but if you need to understand how it works, you will probably want to read
+[wiki:doc/RPKI/CA/Configuration/Tests these instructions].
+
+== Next steps == #nextsteps
+
+Once you've finished with configuration, the next thing you should
+read is the [[MySQLSetup|MySQL setup instructions]].
diff --git a/doc/manual/13.RPKI.CA.Configuration.Common.md b/doc/manual/13.RPKI.CA.Configuration.Common.md
new file mode 100644
index 00000000..da22b8f2
--- /dev/null
+++ b/doc/manual/13.RPKI.CA.Configuration.Common.md
@@ -0,0 +1,71 @@
+# RPKI Engine Common Configuration Options
+
+Some of the configuration options are common to all of the daemons. Which
+daemon they affect depends only on which sections of which configuration file
+they are in.
+
+The first group of options are boolean flags, which can be set to "true" or
+"false". If not specified, default values will be chosen (generally false).
+Many of these flags controll debugging code that is probably of interest only
+to the developers.
+
+debug_http::
+
+> Enable verbose http debug logging.
+
+want_persistent_client::
+
+> Enable http 1.1 persistence, client side.
+
+want_persistent_server::
+
+> Enable http 1.1 persistence, server side.
+
+use_adns::
+
+> Use asynchronous DNS code. Enabling this will raise an exception if the
+dnspython toolkit is not installed. Asynchronous DNS is an experimental
+feature intended to allow higher throughput on busy servers; if you don't know
+why you need it, you probably don't.
+
+enable_ipv6_clients::
+
+> Enable IPv6 HTTP client code.
+
+enable_ipv6_servers::
+
+> Enable IPv6 HTTP server code. On by default, since listening for IPv6
+connections is usually harmless.
+
+debug_cms_certs::
+
+> Enable verbose logging about CMS certificates.
+
+sql_debug::
+
+> Enable verbose logging about sql operations.
+
+gc_debug::
+
+> Enable scary garbage collector debugging.
+
+timer_debug::
+
+> Enable verbose logging of timer system.
+
+enable_tracebacks::
+
+> Enable Python tracebacks in logs.
+
+There are also a few options which allow you to save CMS messages for audit or
+debugging. The save format is a simple MIME encoding in a
+{{<http://en.wikipedia.org/wiki/Maildir|Maildir}-format> mailbox. The current
+options are very crude, at some point we may provide finer grain controls.
+
+dump_outbound_cms::
+
+> Dump verbatim copies of CMS messages we send to this mailbox.
+
+dump_inbound_cms::
+
+> Dump verbatim copies of CMS messages we receive to this mailbox.
diff --git a/doc/manual/13.RPKI.CA.Configuration.Common.wiki b/doc/manual/13.RPKI.CA.Configuration.Common.wiki
new file mode 100644
index 00000000..2b1d3163
--- /dev/null
+++ b/doc/manual/13.RPKI.CA.Configuration.Common.wiki
@@ -0,0 +1,63 @@
+= RPKI Engine Common Configuration Options =
+
+[[TracNav(doc/RPKI/TOC)]]
+
+Some of the configuration options are common to all of the daemons.
+Which daemon they affect depends only on which sections of which
+configuration file they are in.
+
+The first group of options are boolean flags, which can be set to
+"true" or "false". If not specified, default values will be chosen
+(generally false). Many of these flags controll debugging code that
+is probably of interest only to the developers.
+
+debug_http::
+ Enable verbose http debug logging.
+
+want_persistent_client::
+ Enable http 1.1 persistence, client side.
+
+want_persistent_server::
+ Enable http 1.1 persistence, server side.
+
+use_adns::
+ Use asynchronous DNS code. Enabling this will raise an
+ exception if the dnspython toolkit is not installed.
+ Asynchronous DNS is an experimental feature intended to allow
+ higher throughput on busy servers; if you don't know why you
+ need it, you probably don't.
+
+enable_ipv6_clients::
+ Enable IPv6 HTTP client code.
+
+enable_ipv6_servers::
+ Enable IPv6 HTTP server code. On by default, since listening
+ for IPv6 connections is usually harmless.
+
+debug_cms_certs::
+ Enable verbose logging about CMS certificates.
+
+sql_debug::
+ Enable verbose logging about sql operations.
+
+gc_debug::
+ Enable scary garbage collector debugging.
+
+timer_debug::
+ Enable verbose logging of timer system.
+
+enable_tracebacks::
+ Enable Python tracebacks in logs.
+
+
+There are also a few options which allow you to save CMS messages for
+audit or debugging. The save format is a simple MIME encoding in a
+{{http://en.wikipedia.org/wiki/Maildir|Maildir}-format mailbox. The
+current options are very crude, at some point we may provide finer
+grain controls.
+
+dump_outbound_cms::
+ Dump verbatim copies of CMS messages we send to this mailbox.
+
+dump_inbound_cms::
+ Dump verbatim copies of CMS messages we receive to this mailbox.
diff --git a/doc/manual/14.RPKI.CA.Configuration.myrpki.md b/doc/manual/14.RPKI.CA.Configuration.myrpki.md
new file mode 100644
index 00000000..bf798d65
--- /dev/null
+++ b/doc/manual/14.RPKI.CA.Configuration.myrpki.md
@@ -0,0 +1,295 @@
+# [myrpki] section
+
+The "`[myrpki]`" section contains all the parameters that you really need to
+configure. The name "`myrpki`" is historical and may change in the future.
+
+## handle
+
+Every resource-holding or server-operating entity needs a "handle", which is
+just an identifier by which the entity calls itself. Handles do not need to be
+globally unique, but should be chosen with an eye towards debugging
+operational problems: it's best if you use a handle that your parents and
+children will recognize as being you.
+
+The "`handle`" option in the "`[myrpki]`" section specifies the default handle
+for this installation. Previous versions of the CA tools required a separate
+configuration file, each with its own handle setting, for each hosted entity.
+The current code allows the current handle to be selected at runtime in both
+the GUI and command line user interface tools, so the handle setting here is
+just the default when you don't set one explictly. In the long run, this
+option may go away entirely, but for now you need to set this.
+
+Syntax is an identifier (ASCII letters, digits, hyphen, underscore -- no
+whitespace, non-ASCII characters, or other punctuation).
+
+No default value.
+
+## bpki_servers_directory
+
+Directory for BPKI files generated by rpkic and used by rpkid and pubd. You
+will not normally need to change this.
+
+ bpki_servers_directory = ${autoconf::datarootdir}/rpki
+
+## run_rpkid
+
+Whether you want to run your own copy of rpkid (and irdbd). Leave this alone
+unless you're doing something unusual like running a pubd-only installation.
+
+ run_rpkid = yes
+
+## rpkid_server_host
+
+DNS hostname for rpkid. In most cases, this must resolve to a publicly-
+reachable address to be useful, as your RPKI children will need to contact
+your rpkid at this address.
+
+No default value.
+
+## rpkid_server_port
+
+Server port number for rpkid. This can be any legal TCP port number that
+you're not using for something else.
+
+ rpkid_server_port = 4404
+
+## irdbd_server_host
+
+DNS hostname for irdbd, or "`localhost`". This should be "`localhost`" unless
+you really know what you are doing.
+
+ irdbd_server_host = localhost
+
+## irdbd_server_port
+
+Server port number for irdbd. This can be any legal TCP port number that
+you're not using for something else.
+
+ irdbd_server_port = 4403
+
+## run_pubd
+
+Whether you want to run your own copy of pubd. In general, it's best to use
+your parent's pubd if your parent allows you to do so, because this will
+reduce the overall number of publication sites from which relying parties will
+need to retrieve data. However, not all parents offer publication service, or
+you may need to run pubd yourself for reliability reasons, or because you're
+certifying private address space or private Autonomous System Numbers.
+
+The out of band setup protocol will attempt to negotiate publication service
+for you with whatever publication service your parent is using, if it can and
+if you let it.
+
+ run_pubd = yes
+
+## pubd_server_host
+
+DNS hostname for pubd, if you're running it. This must resolve to a publicly
+reachable address to be useful.
+
+No default value.
+
+## pubd_server_port
+
+Server port number for pubd. This can be any legal TCP port number that you're
+not using for something else.
+
+ pubd_server_port = 4402
+
+## pubd_contact_info
+
+Contact information to include in offers of repository service. This only
+matters when you're running pubd. This should be a human readable string,
+perhaps containing an email address or URL.
+
+No default value.
+
+## run_rootd
+
+Whether you want to run your very own copy of rootd. Don't enable this unless
+you really know what you're doing.
+
+ run_rootd = no
+
+## rootd_server_host
+
+DNS hostname for rootd, if you're running it. This should be localhost unless
+you really know what you are doing.
+
+ rootd_server_host = localhost
+
+## rootd_server_port
+
+Server port number for rootd, if you're running it. This can be any legal TCP
+port number that you're not using for something else.
+
+ rootd_server_port = 4401
+
+## publication_base_directory
+
+Root of local directory tree where pubd should write out published data. You
+need to configure this, and the configuration should match up with the
+directory where you point rsyncd. Neither pubd nor rsyncd much cares _where_
+you tell it to put this stuff, the important thing is that the rsync URIs in
+generated certificates match up with the published objects so that relying
+parties can find and verify rpkid's published outputs.
+
+ publication_base_directory = ${autoconf::datarootdir}/rpki/publication
+
+## publication_root_cert_directory
+
+Root of local directory tree where rootd (sigh) should write out published
+data. This is just like publication_base_directory, but rootd is too dumb to
+use pubd and needs its own directory in which to write one certificate, one
+CRL, and one manifest. Neither rootd nor rsyncd much cares _where_ you tell
+them to put this stuff, the important thing is that the rsync URIs in
+generated certificates match up with the published objects so that relying
+parties can find and verify rootd's published outputs.
+
+ publication_root_cert_directory = ${myrpki::publication_base_directory}.root
+
+## publication_rsync_module
+
+rsyncd module name corresponding to publication_base_directory. This has to
+match the module you configured into `rsyncd.conf`. Leave this alone unless
+you have some need to change it.
+
+ publication_rsync_module = rpki
+
+## publication_root_module
+
+rsyncd module name corresponding to publication_root_cert_directory. This has
+to match the module you configured into `rsyncd.conf`. Leave this alone unless
+you have some need to change it.
+
+ publication_root_module = root
+
+## publication_rsync_server
+
+Hostname and optional port number for rsync URIs. In most cases this should
+just be the same value as pubd_server_host.
+
+ publication_rsync_server = ${myrpki::pubd_server_host}
+
+## start_rpkid
+
+rpkid startup control. This should usually have the same value as run_rpkid:
+the only case where you would want to change this is when you are running the
+back-end code on a different machine from one or more of the daemons, in which
+case you need finer control over which daemons to start on which machines. In
+such cases, run_rpkid controls whether the back-end code is doing things to
+manage rpkid, while start_rpkid controls whether rpki-start-servers attempts
+to start rpkid on this machine.
+
+ start_rpkid = ${myrpki::run_rpkid}
+
+## start_irdbd
+
+irdbd startup control. This should usually have the same value as run_rpkid:
+the only case where you would want to change this is when you are running the
+back-end code on a different machine from one or more of the daemons, in which
+case you need finer control over which daemons to start on which machines. In
+such cases, run_rpkid controls whether the back-end code is doing things to
+manage rpkid, while start_irdbd controls whether rpki-start-servers attempts
+to start irdbd on this machine.
+
+ start_irdbd = ${myrpki::run_rpkid}
+
+## start_pubd
+
+pubd startup control. This should usually have the same value as run_pubd: the
+only case where you would want to change this is when you are running the
+back-end code on a different machine from one or more of the daemons, in which
+case you need finer control over which daemons to start on which machines. In
+such cases, run_pubd controls whether the back-end code is doing things to
+manage pubd, while start_pubd controls whether rpki-start-servers attempts to
+start pubd on this machine.
+
+ start_pubd = ${myrpki::run_pubd}
+
+## start_rootd
+
+rootd startup control. This should usually have the same value as run_rootd:
+the only case where you would want to change this is when you are running the
+back-end code on a different machine from one or more of the daemons, in which
+case you need finer control over which daemons to start on which machines. In
+such cases, run_rootd controls whether the back-end code is doing things to
+manage rootd, while start_rootd controls whether rpki-start-servers attempts
+to start rootd on this machine.
+
+ start_rootd = ${myrpki::run_rootd}
+
+## shared_sql_username
+
+If you're comfortable with having all of the databases use the same MySQL
+username, set that value here. The default setting of this variable should be
+fine.
+
+ shared_sql_username = rpki
+
+## shared_sql_password
+
+If you're comfortable with having all of the databases use the same MySQL
+password, set that value here. You should use a locally generated password
+either here or in the individual settings below. The installation process
+generates a random value for this option, which satisfies this requirement, so
+ordinarily you should have no need to change this option.
+
+No default value.
+
+## rpkid_sql_database
+
+SQL database name for rpkid's database. The default setting of this variable
+should be fine.
+
+ rpkid_sql_database = rpkid
+
+## rpkid_sql_username
+
+If you want to use a separate SQL username for rpkid's database, set it here.
+
+ rpkid_sql_username = ${myrpki::shared_sql_username}
+
+## rpkid_sql_password
+
+If you want to use a separate SQL password for rpkid's database, set it here.
+
+ rpkid_sql_password = ${myrpki::shared_sql_password}
+
+## irdbd_sql_database
+
+SQL database for irdbd's database. The default setting of this variable should
+be fine.
+
+ irdbd_sql_database = irdbd
+
+## irdbd_sql_username
+
+If you want to use a separate SQL username for irdbd's database, set it here.
+
+ irdbd_sql_username = ${myrpki::shared_sql_username}
+
+## irdbd_sql_password
+
+If you want to use a separate SQL password for irdbd's database, set it here.
+
+ irdbd_sql_password = ${myrpki::shared_sql_password}
+
+## pubd_sql_database
+
+SQL database name for pubd's database. The default setting of this variable
+should be fine.
+
+ pubd_sql_database = pubd
+
+## pubd_sql_username
+
+If you want to use a separate SQL username for pubd's database, set it here.
+
+ pubd_sql_username = ${myrpki::shared_sql_username}
+
+## pubd_sql_password
+
+If you want to use a separate SQL password for pubd's database, set it here.
+
+ pubd_sql_password = ${myrpki::shared_sql_password}
diff --git a/doc/manual/14.RPKI.CA.Configuration.myrpki.wiki b/doc/manual/14.RPKI.CA.Configuration.myrpki.wiki
new file mode 100644
index 00000000..d5611841
--- /dev/null
+++ b/doc/manual/14.RPKI.CA.Configuration.myrpki.wiki
@@ -0,0 +1,413 @@
+{{{
+#!comment
+
+******************************************************************************
+THIS PAGE WAS GENERATED AUTOMATICALLY, DO NOT EDIT.
+
+Generated from $Id: rpki-confgen.xml 6070 2015-03-23 18:04:06Z melkins $
+ by $Id: rpki-confgen 5856 2014-05-31 18:32:19Z sra $
+******************************************************************************
+
+}}}
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= [myrpki] section = #myrpki
+
+The "`[myrpki]`" section contains all the parameters that you really
+need to configure. The name "`myrpki`" is historical and may change in
+the future.
+
+== handle == #handle
+
+Every resource-holding or server-operating entity needs a "handle",
+which is just an identifier by which the entity calls itself. Handles
+do not need to be globally unique, but should be chosen with an eye
+towards debugging operational problems: it's best if you use a handle
+that your parents and children will recognize as being you.
+
+The "`handle`" option in the "`[myrpki]`" section specifies the
+default handle for this installation. Previous versions of the CA
+tools required a separate configuration file, each with its own handle
+setting, for each hosted entity. The current code allows the current
+handle to be selected at runtime in both the GUI and command line user
+interface tools, so the handle setting here is just the default when
+you don't set one explictly. In the long run, this option may go away
+entirely, but for now you need to set this.
+
+Syntax is an identifier (ASCII letters, digits, hyphen, underscore --
+no whitespace, non-ASCII characters, or other punctuation).
+
+No default value.
+
+== bpki_servers_directory == #bpki_servers_directory
+
+Directory for BPKI files generated by rpkic and used by rpkid and
+pubd. You will not normally need to change this.
+
+{{{
+#!ini
+bpki_servers_directory = ${autoconf::datarootdir}/rpki
+}}}
+
+== run_rpkid == #run_rpkid
+
+Whether you want to run your own copy of rpkid (and irdbd). Leave this
+alone unless you're doing something unusual like running a pubd-only
+installation.
+
+{{{
+#!ini
+run_rpkid = yes
+}}}
+
+== rpkid_server_host == #rpkid_server_host
+
+DNS hostname for rpkid. In most cases, this must resolve to a
+publicly-reachable address to be useful, as your RPKI children will
+need to contact your rpkid at this address.
+
+No default value.
+
+== rpkid_server_port == #rpkid_server_port
+
+Server port number for rpkid. This can be any legal TCP port number
+that you're not using for something else.
+
+{{{
+#!ini
+rpkid_server_port = 4404
+}}}
+
+== irdbd_server_host == #irdbd_server_host
+
+DNS hostname for irdbd, or "`localhost`". This should be "`localhost`"
+unless you really know what you are doing.
+
+{{{
+#!ini
+irdbd_server_host = localhost
+}}}
+
+== irdbd_server_port == #irdbd_server_port
+
+Server port number for irdbd. This can be any legal TCP port number
+that you're not using for something else.
+
+{{{
+#!ini
+irdbd_server_port = 4403
+}}}
+
+== run_pubd == #run_pubd
+
+Whether you want to run your own copy of pubd. In general, it's best
+to use your parent's pubd if your parent allows you to do so, because
+this will reduce the overall number of publication sites from which
+relying parties will need to retrieve data. However, not all parents
+offer publication service, or you may need to run pubd yourself for
+reliability reasons, or because you're certifying private address
+space or private Autonomous System Numbers.
+
+The out of band setup protocol will attempt to negotiate publication
+service for you with whatever publication service your parent is
+using, if it can and if you let it.
+
+{{{
+#!ini
+run_pubd = yes
+}}}
+
+== pubd_server_host == #pubd_server_host
+
+DNS hostname for pubd, if you're running it. This must resolve to a
+publicly reachable address to be useful.
+
+No default value.
+
+== pubd_server_port == #pubd_server_port
+
+Server port number for pubd. This can be any legal TCP port number
+that you're not using for something else.
+
+{{{
+#!ini
+pubd_server_port = 4402
+}}}
+
+== pubd_contact_info == #pubd_contact_info
+
+Contact information to include in offers of repository service. This
+only matters when you're running pubd. This should be a human readable
+string, perhaps containing an email address or URL.
+
+No default value.
+
+== run_rootd == #run_rootd
+
+Whether you want to run your very own copy of rootd. Don't enable this
+unless you really know what you're doing.
+
+{{{
+#!ini
+run_rootd = no
+}}}
+
+== rootd_server_host == #rootd_server_host
+
+DNS hostname for rootd, if you're running it. This should be localhost
+unless you really know what you are doing.
+
+{{{
+#!ini
+rootd_server_host = localhost
+}}}
+
+== rootd_server_port == #rootd_server_port
+
+Server port number for rootd, if you're running it. This can be any
+legal TCP port number that you're not using for something else.
+
+{{{
+#!ini
+rootd_server_port = 4401
+}}}
+
+== publication_base_directory == #publication_base_directory
+
+Root of local directory tree where pubd should write out published
+data. You need to configure this, and the configuration should match
+up with the directory where you point rsyncd. Neither pubd nor rsyncd
+much cares //where// you tell it to put this stuff, the important
+thing is that the rsync URIs in generated certificates match up with
+the published objects so that relying parties can find and verify
+rpkid's published outputs.
+
+{{{
+#!ini
+publication_base_directory = ${autoconf::datarootdir}/rpki/publication
+}}}
+
+== publication_root_cert_directory == #publication_root_cert_directory
+
+Root of local directory tree where rootd (sigh) should write out
+published data. This is just like publication_base_directory, but
+rootd is too dumb to use pubd and needs its own directory in which to
+write one certificate, one CRL, and one manifest. Neither rootd nor
+rsyncd much cares //where// you tell them to put this stuff, the
+important thing is that the rsync URIs in generated certificates match
+up with the published objects so that relying parties can find and
+verify rootd's published outputs.
+
+{{{
+#!ini
+publication_root_cert_directory = ${myrpki::publication_base_directory}.root
+}}}
+
+== publication_rsync_module == #publication_rsync_module
+
+rsyncd module name corresponding to publication_base_directory. This
+has to match the module you configured into `rsyncd.conf`. Leave this
+alone unless you have some need to change it.
+
+{{{
+#!ini
+publication_rsync_module = rpki
+}}}
+
+== publication_root_module == #publication_root_module
+
+rsyncd module name corresponding to publication_root_cert_directory.
+This has to match the module you configured into `rsyncd.conf`. Leave
+this alone unless you have some need to change it.
+
+{{{
+#!ini
+publication_root_module = root
+}}}
+
+== publication_rsync_server == #publication_rsync_server
+
+Hostname and optional port number for rsync URIs. In most cases this
+should just be the same value as pubd_server_host.
+
+{{{
+#!ini
+publication_rsync_server = ${myrpki::pubd_server_host}
+}}}
+
+== start_rpkid == #start_rpkid
+
+rpkid startup control. This should usually have the same value as
+run_rpkid: the only case where you would want to change this is when
+you are running the back-end code on a different machine from one or
+more of the daemons, in which case you need finer control over which
+daemons to start on which machines. In such cases, run_rpkid controls
+whether the back-end code is doing things to manage rpkid, while
+start_rpkid controls whether rpki-start-servers attempts to start
+rpkid on this machine.
+
+{{{
+#!ini
+start_rpkid = ${myrpki::run_rpkid}
+}}}
+
+== start_irdbd == #start_irdbd
+
+irdbd startup control. This should usually have the same value as
+run_rpkid: the only case where you would want to change this is when
+you are running the back-end code on a different machine from one or
+more of the daemons, in which case you need finer control over which
+daemons to start on which machines. In such cases, run_rpkid controls
+whether the back-end code is doing things to manage rpkid, while
+start_irdbd controls whether rpki-start-servers attempts to start
+irdbd on this machine.
+
+{{{
+#!ini
+start_irdbd = ${myrpki::run_rpkid}
+}}}
+
+== start_pubd == #start_pubd
+
+pubd startup control. This should usually have the same value as
+run_pubd: the only case where you would want to change this is when
+you are running the back-end code on a different machine from one or
+more of the daemons, in which case you need finer control over which
+daemons to start on which machines. In such cases, run_pubd controls
+whether the back-end code is doing things to manage pubd, while
+start_pubd controls whether rpki-start-servers attempts to start pubd
+on this machine.
+
+{{{
+#!ini
+start_pubd = ${myrpki::run_pubd}
+}}}
+
+== start_rootd == #start_rootd
+
+rootd startup control. This should usually have the same value as
+run_rootd: the only case where you would want to change this is when
+you are running the back-end code on a different machine from one or
+more of the daemons, in which case you need finer control over which
+daemons to start on which machines. In such cases, run_rootd controls
+whether the back-end code is doing things to manage rootd, while
+start_rootd controls whether rpki-start-servers attempts to start
+rootd on this machine.
+
+{{{
+#!ini
+start_rootd = ${myrpki::run_rootd}
+}}}
+
+== shared_sql_username == #shared_sql_username
+
+If you're comfortable with having all of the databases use the same
+MySQL username, set that value here. The default setting of this
+variable should be fine.
+
+{{{
+#!ini
+shared_sql_username = rpki
+}}}
+
+== shared_sql_password == #shared_sql_password
+
+If you're comfortable with having all of the databases use the same
+MySQL password, set that value here. You should use a locally
+generated password either here or in the individual settings below.
+The installation process generates a random value for this option,
+which satisfies this requirement, so ordinarily you should have no
+need to change this option.
+
+No default value.
+
+== rpkid_sql_database == #rpkid_sql_database
+
+SQL database name for rpkid's database. The default setting of this
+variable should be fine.
+
+{{{
+#!ini
+rpkid_sql_database = rpkid
+}}}
+
+== rpkid_sql_username == #rpkid_sql_username
+
+If you want to use a separate SQL username for rpkid's database, set
+it here.
+
+{{{
+#!ini
+rpkid_sql_username = ${myrpki::shared_sql_username}
+}}}
+
+== rpkid_sql_password == #rpkid_sql_password
+
+If you want to use a separate SQL password for rpkid's database, set
+it here.
+
+{{{
+#!ini
+rpkid_sql_password = ${myrpki::shared_sql_password}
+}}}
+
+== irdbd_sql_database == #irdbd_sql_database
+
+SQL database for irdbd's database. The default setting of this
+variable should be fine.
+
+{{{
+#!ini
+irdbd_sql_database = irdbd
+}}}
+
+== irdbd_sql_username == #irdbd_sql_username
+
+If you want to use a separate SQL username for irdbd's database, set
+it here.
+
+{{{
+#!ini
+irdbd_sql_username = ${myrpki::shared_sql_username}
+}}}
+
+== irdbd_sql_password == #irdbd_sql_password
+
+If you want to use a separate SQL password for irdbd's database, set
+it here.
+
+{{{
+#!ini
+irdbd_sql_password = ${myrpki::shared_sql_password}
+}}}
+
+== pubd_sql_database == #pubd_sql_database
+
+SQL database name for pubd's database. The default setting of this
+variable should be fine.
+
+{{{
+#!ini
+pubd_sql_database = pubd
+}}}
+
+== pubd_sql_username == #pubd_sql_username
+
+If you want to use a separate SQL username for pubd's database, set it
+here.
+
+{{{
+#!ini
+pubd_sql_username = ${myrpki::shared_sql_username}
+}}}
+
+== pubd_sql_password == #pubd_sql_password
+
+If you want to use a separate SQL password for pubd's database, set it
+here.
+
+{{{
+#!ini
+pubd_sql_password = ${myrpki::shared_sql_password}
+}}}
diff --git a/doc/manual/15.RPKI.CA.Configuration.rpkid.md b/doc/manual/15.RPKI.CA.Configuration.rpkid.md
new file mode 100644
index 00000000..e3a31433
--- /dev/null
+++ b/doc/manual/15.RPKI.CA.Configuration.rpkid.md
@@ -0,0 +1,80 @@
+# [rpkid] section
+
+rpkid's default config file is the system `rpki.conf` file. Start rpkid with
+"`-c filename`" to choose a different config file. All options are in the
+"`[rpkid]`" section. BPKI Certificates and keys may be in either DER or PEM
+format.
+
+## sql-database
+
+MySQL database name for rpkid.
+
+ sql-database = ${myrpki::rpkid_sql_database}
+
+## sql-username
+
+MySQL user name for rpkid.
+
+ sql-username = ${myrpki::rpkid_sql_username}
+
+## sql-password
+
+MySQL password for rpkid.
+
+ sql-password = ${myrpki::rpkid_sql_password}
+
+## server-host
+
+Host on which rpkid should listen for HTTP service requests.
+
+ server-host = ${myrpki::rpkid_server_host}
+
+## server-port
+
+Port on which rpkid should listen for HTTP service requests.
+
+ server-port = ${myrpki::rpkid_server_port}
+
+## irdb-url
+
+HTTP service URL rpkid should use to contact irdbd. If irdbd is running on the
+same machine as rpkid, this can and probably should be a loopback URL, since
+nobody but rpkid needs to talk to irdbd.
+
+ irdb-url = http://${myrpki::irdbd_server_host}:${myrpki::irdbd_server_port}/
+
+## bpki-ta
+
+Where rpkid should look for the BPKI trust anchor. All BPKI certificate
+verification within rpkid traces back to this trust anchor. Don't change this
+unless you really know what you are doing.
+
+ bpki-ta = ${myrpki::bpki_servers_directory}/ca.cer
+
+## rpkid-cert
+
+Where rpkid should look for its own BPKI EE certificate. Don't change this
+unless you really know what you are doing.
+
+ rpkid-cert = ${myrpki::bpki_servers_directory}/rpkid.cer
+
+## rpkid-key
+
+Where rpkid should look for the private key corresponding to its own BPKI EE
+certificate. Don't change this unless you really know what you are doing.
+
+ rpkid-key = ${myrpki::bpki_servers_directory}/rpkid.key
+
+## irdb-cert
+
+Where rpkid should look for irdbd's BPKI EE certificate. Don't change this
+unless you really know what you are doing.
+
+ irdb-cert = ${myrpki::bpki_servers_directory}/irdbd.cer
+
+## irbe-cert
+
+Where rpkid should look for the back-end control client's BPKI EE certificate.
+Don't change this unless you really know what you are doing.
+
+ irbe-cert = ${myrpki::bpki_servers_directory}/irbe.cer
diff --git a/doc/manual/15.RPKI.CA.Configuration.rpkid.wiki b/doc/manual/15.RPKI.CA.Configuration.rpkid.wiki
new file mode 100644
index 00000000..211dc772
--- /dev/null
+++ b/doc/manual/15.RPKI.CA.Configuration.rpkid.wiki
@@ -0,0 +1,129 @@
+{{{
+#!comment
+
+******************************************************************************
+THIS PAGE WAS GENERATED AUTOMATICALLY, DO NOT EDIT.
+
+Generated from $Id: rpki-confgen.xml 6070 2015-03-23 18:04:06Z melkins $
+ by $Id: rpki-confgen 5856 2014-05-31 18:32:19Z sra $
+******************************************************************************
+
+}}}
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= [rpkid] section = #rpkid
+
+rpkid's default config file is the system `rpki.conf` file. Start
+rpkid with "`-c filename`" to choose a different config file. All
+options are in the "`[rpkid]`" section. BPKI Certificates and keys may
+be in either DER or PEM format.
+
+== sql-database == #sql-database
+
+MySQL database name for rpkid.
+
+{{{
+#!ini
+sql-database = ${myrpki::rpkid_sql_database}
+}}}
+
+== sql-username == #sql-username
+
+MySQL user name for rpkid.
+
+{{{
+#!ini
+sql-username = ${myrpki::rpkid_sql_username}
+}}}
+
+== sql-password == #sql-password
+
+MySQL password for rpkid.
+
+{{{
+#!ini
+sql-password = ${myrpki::rpkid_sql_password}
+}}}
+
+== server-host == #server-host
+
+Host on which rpkid should listen for HTTP service requests.
+
+{{{
+#!ini
+server-host = ${myrpki::rpkid_server_host}
+}}}
+
+== server-port == #server-port
+
+Port on which rpkid should listen for HTTP service requests.
+
+{{{
+#!ini
+server-port = ${myrpki::rpkid_server_port}
+}}}
+
+== irdb-url == #irdb-url
+
+HTTP service URL rpkid should use to contact irdbd. If irdbd is
+running on the same machine as rpkid, this can and probably should be
+a loopback URL, since nobody but rpkid needs to talk to irdbd.
+
+{{{
+#!ini
+irdb-url = http://${myrpki::irdbd_server_host}:${myrpki::irdbd_server_port}/
+}}}
+
+== bpki-ta == #bpki-ta
+
+Where rpkid should look for the BPKI trust anchor. All BPKI
+certificate verification within rpkid traces back to this trust
+anchor. Don't change this unless you really know what you are doing.
+
+{{{
+#!ini
+bpki-ta = ${myrpki::bpki_servers_directory}/ca.cer
+}}}
+
+== rpkid-cert == #rpkid-cert
+
+Where rpkid should look for its own BPKI EE certificate. Don't change
+this unless you really know what you are doing.
+
+{{{
+#!ini
+rpkid-cert = ${myrpki::bpki_servers_directory}/rpkid.cer
+}}}
+
+== rpkid-key == #rpkid-key
+
+Where rpkid should look for the private key corresponding to its own
+BPKI EE certificate. Don't change this unless you really know what you
+are doing.
+
+{{{
+#!ini
+rpkid-key = ${myrpki::bpki_servers_directory}/rpkid.key
+}}}
+
+== irdb-cert == #irdb-cert
+
+Where rpkid should look for irdbd's BPKI EE certificate. Don't change
+this unless you really know what you are doing.
+
+{{{
+#!ini
+irdb-cert = ${myrpki::bpki_servers_directory}/irdbd.cer
+}}}
+
+== irbe-cert == #irbe-cert
+
+Where rpkid should look for the back-end control client's BPKI EE
+certificate. Don't change this unless you really know what you are
+doing.
+
+{{{
+#!ini
+irbe-cert = ${myrpki::bpki_servers_directory}/irbe.cer
+}}}
diff --git a/doc/manual/16.RPKI.CA.Configuration.irdbd.md b/doc/manual/16.RPKI.CA.Configuration.irdbd.md
new file mode 100644
index 00000000..a02324e0
--- /dev/null
+++ b/doc/manual/16.RPKI.CA.Configuration.irdbd.md
@@ -0,0 +1,47 @@
+# [irdbd] section
+
+irdbd's default configuration file is the system `rpki.conf` file. Start irdbd
+with "`-c filename`" to choose a different configuration file. All options are
+in the "`[irdbd]`" section.
+
+Since irdbd is part of the back-end system, it has direct access to the back-
+end's SQL database, and thus is able to pull its own BPKI configuration
+directly from the database, and thus needs a bit less configuration than the
+other daemons.
+
+## sql-database
+
+MySQL database name for irdbd.
+
+ sql-database = ${myrpki::irdbd_sql_database}
+
+## sql-username
+
+MySQL user name for irdbd.
+
+ sql-username = ${myrpki::irdbd_sql_username}
+
+## sql-password
+
+MySQL password for irdbd.
+
+ sql-password = ${myrpki::irdbd_sql_password}
+
+## server-host
+
+Host on which irdbd should listen for HTTP service requests.
+
+ server-host = ${myrpki::irdbd_server_host}
+
+## server-port
+
+Port on which irdbd should listen for HTTP service requests.
+
+ server-port = ${myrpki::irdbd_server_port}
+
+## startup-message
+
+String to log on startup, useful when debugging a collection of irdbd
+instances at once.
+
+No default value.
diff --git a/doc/manual/16.RPKI.CA.Configuration.irdbd.wiki b/doc/manual/16.RPKI.CA.Configuration.irdbd.wiki
new file mode 100644
index 00000000..6992e48e
--- /dev/null
+++ b/doc/manual/16.RPKI.CA.Configuration.irdbd.wiki
@@ -0,0 +1,76 @@
+{{{
+#!comment
+
+******************************************************************************
+THIS PAGE WAS GENERATED AUTOMATICALLY, DO NOT EDIT.
+
+Generated from $Id: rpki-confgen.xml 6070 2015-03-23 18:04:06Z melkins $
+ by $Id: rpki-confgen 5856 2014-05-31 18:32:19Z sra $
+******************************************************************************
+
+}}}
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= [irdbd] section = #irdbd
+
+irdbd's default configuration file is the system `rpki.conf` file.
+Start irdbd with "`-c filename`" to choose a different configuration
+file. All options are in the "`[irdbd]`" section.
+
+Since irdbd is part of the back-end system, it has direct access to
+the back-end's SQL database, and thus is able to pull its own BPKI
+configuration directly from the database, and thus needs a bit less
+configuration than the other daemons.
+
+== sql-database == #sql-database
+
+MySQL database name for irdbd.
+
+{{{
+#!ini
+sql-database = ${myrpki::irdbd_sql_database}
+}}}
+
+== sql-username == #sql-username
+
+MySQL user name for irdbd.
+
+{{{
+#!ini
+sql-username = ${myrpki::irdbd_sql_username}
+}}}
+
+== sql-password == #sql-password
+
+MySQL password for irdbd.
+
+{{{
+#!ini
+sql-password = ${myrpki::irdbd_sql_password}
+}}}
+
+== server-host == #server-host
+
+Host on which irdbd should listen for HTTP service requests.
+
+{{{
+#!ini
+server-host = ${myrpki::irdbd_server_host}
+}}}
+
+== server-port == #server-port
+
+Port on which irdbd should listen for HTTP service requests.
+
+{{{
+#!ini
+server-port = ${myrpki::irdbd_server_port}
+}}}
+
+== startup-message == #startup-message
+
+String to log on startup, useful when debugging a collection of irdbd
+instances at once.
+
+No default value.
diff --git a/doc/manual/17.RPKI.CA.Configuration.pubd.md b/doc/manual/17.RPKI.CA.Configuration.pubd.md
new file mode 100644
index 00000000..14366bda
--- /dev/null
+++ b/doc/manual/17.RPKI.CA.Configuration.pubd.md
@@ -0,0 +1,76 @@
+# [pubd] section
+
+pubd's default configuration file is the system `rpki.conf` file. Start pubd
+with "`-c filename`" to choose a different configuration file. All options are
+in the "`[pubd]`" section. BPKI certificates and keys may be either DER or PEM
+format.
+
+## sql-database
+
+MySQL database name for pubd.
+
+ sql-database = ${myrpki::pubd_sql_database}
+
+## sql-username
+
+MySQL user name for pubd.
+
+ sql-username = ${myrpki::pubd_sql_username}
+
+## sql-password
+
+MySQL password for pubd.
+
+ sql-password = ${myrpki::pubd_sql_password}
+
+## publication-base
+
+Root of directory tree where pubd should write out published data. You need to
+configure this, and the configuration should match up with the directory where
+you point rsyncd. Neither pubd nor rsyncd much cares -where- you tell them to
+put this stuff, the important thing is that the rsync URIs in generated
+certificates match up with the published objects so that relying parties can
+find and verify rpkid's published outputs.
+
+ publication-base = ${myrpki::publication_base_directory}
+
+## server-host
+
+Host on which pubd should listen for HTTP service requests.
+
+ server-host = ${myrpki::pubd_server_host}
+
+## server-port
+
+Port on which pubd should listen for HTTP service requests.
+
+ server-port = ${myrpki::pubd_server_port}
+
+## bpki-ta
+
+Where pubd should look for the BPKI trust anchor. All BPKI certificate
+verification within pubd traces back to this trust anchor. Don't change this
+unless you really know what you are doing.
+
+ bpki-ta = ${myrpki::bpki_servers_directory}/ca.cer
+
+## pubd-cert
+
+Where pubd should look for its own BPKI EE certificate. Don't change this
+unless you really know what you are doing.
+
+ pubd-cert = ${myrpki::bpki_servers_directory}/pubd.cer
+
+## pubd-key
+
+Where pubd should look for the private key corresponding to its own BPKI EE
+certificate. Don't change this unless you really know what you are doing.
+
+ pubd-key = ${myrpki::bpki_servers_directory}/pubd.key
+
+## irbe-cert
+
+Where pubd should look for the back-end control client's BPKI EE certificate.
+Don't change this unless you really know what you are doing.
+
+ irbe-cert = ${myrpki::bpki_servers_directory}/irbe.cer
diff --git a/doc/manual/17.RPKI.CA.Configuration.pubd.wiki b/doc/manual/17.RPKI.CA.Configuration.pubd.wiki
new file mode 100644
index 00000000..87dbb538
--- /dev/null
+++ b/doc/manual/17.RPKI.CA.Configuration.pubd.wiki
@@ -0,0 +1,123 @@
+{{{
+#!comment
+
+******************************************************************************
+THIS PAGE WAS GENERATED AUTOMATICALLY, DO NOT EDIT.
+
+Generated from $Id: rpki-confgen.xml 6070 2015-03-23 18:04:06Z melkins $
+ by $Id: rpki-confgen 5856 2014-05-31 18:32:19Z sra $
+******************************************************************************
+
+}}}
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= [pubd] section = #pubd
+
+pubd's default configuration file is the system `rpki.conf` file.
+Start pubd with "`-c filename`" to choose a different configuration
+file. All options are in the "`[pubd]`" section. BPKI certificates and
+keys may be either DER or PEM format.
+
+== sql-database == #sql-database
+
+MySQL database name for pubd.
+
+{{{
+#!ini
+sql-database = ${myrpki::pubd_sql_database}
+}}}
+
+== sql-username == #sql-username
+
+MySQL user name for pubd.
+
+{{{
+#!ini
+sql-username = ${myrpki::pubd_sql_username}
+}}}
+
+== sql-password == #sql-password
+
+MySQL password for pubd.
+
+{{{
+#!ini
+sql-password = ${myrpki::pubd_sql_password}
+}}}
+
+== publication-base == #publication-base
+
+Root of directory tree where pubd should write out published data. You
+need to configure this, and the configuration should match up with the
+directory where you point rsyncd. Neither pubd nor rsyncd much cares
+-where- you tell them to put this stuff, the important thing is that
+the rsync URIs in generated certificates match up with the published
+objects so that relying parties can find and verify rpkid's published
+outputs.
+
+{{{
+#!ini
+publication-base = ${myrpki::publication_base_directory}
+}}}
+
+== server-host == #server-host
+
+Host on which pubd should listen for HTTP service requests.
+
+{{{
+#!ini
+server-host = ${myrpki::pubd_server_host}
+}}}
+
+== server-port == #server-port
+
+Port on which pubd should listen for HTTP service requests.
+
+{{{
+#!ini
+server-port = ${myrpki::pubd_server_port}
+}}}
+
+== bpki-ta == #bpki-ta
+
+Where pubd should look for the BPKI trust anchor. All BPKI certificate
+verification within pubd traces back to this trust anchor. Don't
+change this unless you really know what you are doing.
+
+{{{
+#!ini
+bpki-ta = ${myrpki::bpki_servers_directory}/ca.cer
+}}}
+
+== pubd-cert == #pubd-cert
+
+Where pubd should look for its own BPKI EE certificate. Don't change
+this unless you really know what you are doing.
+
+{{{
+#!ini
+pubd-cert = ${myrpki::bpki_servers_directory}/pubd.cer
+}}}
+
+== pubd-key == #pubd-key
+
+Where pubd should look for the private key corresponding to its own
+BPKI EE certificate. Don't change this unless you really know what you
+are doing.
+
+{{{
+#!ini
+pubd-key = ${myrpki::bpki_servers_directory}/pubd.key
+}}}
+
+== irbe-cert == #irbe-cert
+
+Where pubd should look for the back-end control client's BPKI EE
+certificate. Don't change this unless you really know what you are
+doing.
+
+{{{
+#!ini
+irbe-cert = ${myrpki::bpki_servers_directory}/irbe.cer
+}}}
diff --git a/doc/manual/18.RPKI.CA.Configuration.rootd.md b/doc/manual/18.RPKI.CA.Configuration.rootd.md
new file mode 100644
index 00000000..939aa0ff
--- /dev/null
+++ b/doc/manual/18.RPKI.CA.Configuration.rootd.md
@@ -0,0 +1,145 @@
+# [rootd] section
+
+You don't need to run rootd unless you're IANA, are certifying private address
+space, or are an RIR which refuses to accept IANA as the root of the public
+address hierarchy.
+
+Ok, if that wasn't enough to scare you off: rootd is a mess, and needs to be
+rewritten, or, better, merged into rpkid. It doesn't use the publication
+protocol, and it requires far too many configuration parameters.
+
+rootd was originally intended to be a very simple program which simplified
+rpkid enormously by moving one specific task (acting as the root CA of an RPKI
+certificate hierarchy) out of rpkid. As the specifications and code (mostly
+the latter) have evolved, however, this task has become more complicated, and
+rootd would have to become much more complicated to keep up.
+
+Don't run rootd unless you're sure that you need to do so.
+
+Still think you need to run rootd? OK, but remember, you have been warned....
+
+rootd's default configuration file is the system `rpki.conf` file. Start rootd
+with "`-c filename`" to choose a different configuration file. All options are
+in the "`[rootd]`" section. Certificates and keys may be in either DER or PEM
+format.
+
+## bpki-ta
+
+Where rootd should look for the BPKI trust anchor. All BPKI certificate
+verification within rootd traces back to this trust anchor. Don't change this
+unless you really know what you are doing.
+
+ bpki-ta = ${myrpki::bpki_servers_directory}/ca.cer
+
+## rootd-bpki-crl
+
+BPKI CRL. Don't change this unless you really know what you are doing.
+
+ rootd-bpki-crl = ${myrpki::bpki_servers_directory}/ca.crl
+
+## rootd-bpki-cert
+
+rootd's own BPKI EE certificate. Don't change this unless you really know what
+you are doing.
+
+ rootd-bpki-cert = ${myrpki::bpki_servers_directory}/rootd.cer
+
+## rootd-bpki-key
+
+Private key corresponding to rootd's own BPKI EE certificate. Don't change
+this unless you really know what you are doing.
+
+ rootd-bpki-key = ${myrpki::bpki_servers_directory}/rootd.key
+
+## child-bpki-cert
+
+BPKI certificate for rootd's one and only up-down child (RPKI engine to which
+rootd issues an RPKI certificate). Don't change this unless you really know
+what you are doing.
+
+ child-bpki-cert = ${myrpki::bpki_servers_directory}/child.cer
+
+## server-host
+
+Server host on which rootd should listen.
+
+ server-host = ${myrpki::rootd_server_host}
+
+## server-port
+
+Server port on which rootd should listen.
+
+ server-port = ${myrpki::rootd_server_port}
+
+## rpki-root-dir
+
+Where rootd should write its output. Yes, rootd should be using pubd instead
+of publishing directly, but it doesn't. This needs to match pubd's
+configuration.
+
+ rpki-root-dir = ${myrpki::publication_base_directory}
+
+## rpki-base-uri
+
+rsync URI corresponding to directory containing rootd's outputs.
+
+ rpki-base-uri = rsync://${myrpki::publication_rsync_server}/${myrpki::publication_rsync_module}/
+
+## rpki-root-cert-uri
+
+rsync URI for rootd's root (self-signed) RPKI certificate.
+
+ rpki-root-cert-uri = rsync://${myrpki::publication_rsync_server}/${myrpki::publication_root_module}/root.cer
+
+## rpki-root-key
+
+Private key corresponding to rootd's root RPKI certificate.
+
+ rpki-root-key = ${myrpki::bpki_servers_directory}/root.key
+
+## rpki-root-cert
+
+Filename (as opposed to rsync URI) of rootd's root RPKI certificate.
+
+ rpki-root-cert = ${myrpki::publication_root_cert_directory}/root.cer
+
+## rpki-subject-pkcs10
+
+Where rootd should stash a copy of the PKCS #10 request it gets from its
+one (and only) child
+
+ rpki-subject-pkcs10 = ${myrpki::bpki_servers_directory}/rootd.subject.pkcs10
+
+## rpki-subject-lifetime
+
+Lifetime of the one and only RPKI certificate rootd issues.
+
+ rpki-subject-lifetime = 30d
+
+## rpki-root-crl
+
+Filename (relative to rootd-base-uri and rpki-root-dir) of the CRL for rootd's
+root RPKI certificate.
+
+ rpki-root-crl = root.crl
+
+## rpki-root-manifest
+
+Filename (relative to rootd-base-uri and rpki-root-dir) of the manifest for
+rootd's root RPKI certificate.
+
+ rpki-root-manifest = root.mft
+
+## rpki-class-name
+
+Up-down protocol class name for RPKI certificate rootd issues to its one (and
+only) child.
+
+ rpki-class-name = ${myrpki::handle}
+
+## rpki-subject-cert
+
+Filename (relative to rootd-base-uri and rpki-root-dir) of the one (and only)
+RPKI certificate rootd issues.
+
+ rpki-subject-cert = ${myrpki::handle}.cer
diff --git a/doc/manual/18.RPKI.CA.Configuration.rootd.wiki b/doc/manual/18.RPKI.CA.Configuration.rootd.wiki
new file mode 100644
index 00000000..172460cf
--- /dev/null
+++ b/doc/manual/18.RPKI.CA.Configuration.rootd.wiki
@@ -0,0 +1,216 @@
+{{{
+#!comment
+
+******************************************************************************
+THIS PAGE WAS GENERATED AUTOMATICALLY, DO NOT EDIT.
+
+Generated from $Id: rpki-confgen.xml 6070 2015-03-23 18:04:06Z melkins $
+ by $Id: rpki-confgen 5856 2014-05-31 18:32:19Z sra $
+******************************************************************************
+
+}}}
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= [rootd] section = #rootd
+
+You don't need to run rootd unless you're IANA, are certifying private
+address space, or are an RIR which refuses to accept IANA as the root
+of the public address hierarchy.
+
+Ok, if that wasn't enough to scare you off: rootd is a mess, and needs
+to be rewritten, or, better, merged into rpkid. It doesn't use the
+publication protocol, and it requires far too many configuration
+parameters.
+
+rootd was originally intended to be a very simple program which
+simplified rpkid enormously by moving one specific task (acting as the
+root CA of an RPKI certificate hierarchy) out of rpkid. As the
+specifications and code (mostly the latter) have evolved, however,
+this task has become more complicated, and rootd would have to become
+much more complicated to keep up.
+
+Don't run rootd unless you're sure that you need to do so.
+
+Still think you need to run rootd? OK, but remember, you have been
+warned....
+
+rootd's default configuration file is the system `rpki.conf` file.
+Start rootd with "`-c filename`" to choose a different configuration
+file. All options are in the "`[rootd]`" section. Certificates and
+keys may be in either DER or PEM format.
+
+== bpki-ta == #bpki-ta
+
+Where rootd should look for the BPKI trust anchor. All BPKI
+certificate verification within rootd traces back to this trust
+anchor. Don't change this unless you really know what you are doing.
+
+{{{
+#!ini
+bpki-ta = ${myrpki::bpki_servers_directory}/ca.cer
+}}}
+
+== rootd-bpki-crl == #rootd-bpki-crl
+
+BPKI CRL. Don't change this unless you really know what you are doing.
+
+{{{
+#!ini
+rootd-bpki-crl = ${myrpki::bpki_servers_directory}/ca.crl
+}}}
+
+== rootd-bpki-cert == #rootd-bpki-cert
+
+rootd's own BPKI EE certificate. Don't change this unless you really
+know what you are doing.
+
+{{{
+#!ini
+rootd-bpki-cert = ${myrpki::bpki_servers_directory}/rootd.cer
+}}}
+
+== rootd-bpki-key == #rootd-bpki-key
+
+Private key corresponding to rootd's own BPKI EE certificate. Don't
+change this unless you really know what you are doing.
+
+{{{
+#!ini
+rootd-bpki-key = ${myrpki::bpki_servers_directory}/rootd.key
+}}}
+
+== child-bpki-cert == #child-bpki-cert
+
+BPKI certificate for rootd's one and only up-down child (RPKI engine
+to which rootd issues an RPKI certificate). Don't change this unless
+you really know what you are doing.
+
+{{{
+#!ini
+child-bpki-cert = ${myrpki::bpki_servers_directory}/child.cer
+}}}
+
+== server-host == #server-host
+
+Server host on which rootd should listen.
+
+{{{
+#!ini
+server-host = ${myrpki::rootd_server_host}
+}}}
+
+== server-port == #server-port
+
+Server port on which rootd should listen.
+
+{{{
+#!ini
+server-port = ${myrpki::rootd_server_port}
+}}}
+
+== rpki-root-dir == #rpki-root-dir
+
+Where rootd should write its output. Yes, rootd should be using pubd
+instead of publishing directly, but it doesn't. This needs to match
+pubd's configuration.
+
+{{{
+#!ini
+rpki-root-dir = ${myrpki::publication_base_directory}
+}}}
+
+== rpki-base-uri == #rpki-base-uri
+
+rsync URI corresponding to directory containing rootd's outputs.
+
+{{{
+#!ini
+rpki-base-uri = rsync://${myrpki::publication_rsync_server}/${myrpki::publication_rsync_module}/
+}}}
+
+== rpki-root-cert-uri == #rpki-root-cert-uri
+
+rsync URI for rootd's root (self-signed) RPKI certificate.
+
+{{{
+#!ini
+rpki-root-cert-uri = rsync://${myrpki::publication_rsync_server}/${myrpki::publication_root_module}/root.cer
+}}}
+
+== rpki-root-key == #rpki-root-key
+
+Private key corresponding to rootd's root RPKI certificate.
+
+{{{
+#!ini
+rpki-root-key = ${myrpki::bpki_servers_directory}/root.key
+}}}
+
+== rpki-root-cert == #rpki-root-cert
+
+Filename (as opposed to rsync URI) of rootd's root RPKI certificate.
+
+{{{
+#!ini
+rpki-root-cert = ${myrpki::publication_root_cert_directory}/root.cer
+}}}
+
+== rpki-subject-pkcs10 == #rpki-subject-pkcs10
+
+Where rootd should stash a copy of the PKCS #10 request it gets from
+its one (and only) child
+
+{{{
+#!ini
+rpki-subject-pkcs10 = ${myrpki::bpki_servers_directory}/rootd.subject.pkcs10
+}}}
+
+== rpki-subject-lifetime == #rpki-subject-lifetime
+
+Lifetime of the one and only RPKI certificate rootd issues.
+
+{{{
+#!ini
+rpki-subject-lifetime = 30d
+}}}
+
+== rpki-root-crl == #rpki-root-crl
+
+Filename (relative to rootd-base-uri and rpki-root-dir) of the CRL for
+rootd's root RPKI certificate.
+
+{{{
+#!ini
+rpki-root-crl = root.crl
+}}}
+
+== rpki-root-manifest == #rpki-root-manifest
+
+Filename (relative to rootd-base-uri and rpki-root-dir) of the
+manifest for rootd's root RPKI certificate.
+
+{{{
+#!ini
+rpki-root-manifest = root.mft
+}}}
+
+== rpki-class-name == #rpki-class-name
+
+Up-down protocol class name for RPKI certificate rootd issues to its
+one (and only) child.
+
+{{{
+#!ini
+rpki-class-name = ${myrpki::handle}
+}}}
+
+== rpki-subject-cert == #rpki-subject-cert
+
+Filename (relative to rootd-base-uri and rpki-root-dir) of the one
+(and only) RPKI certificate rootd issues.
+
+{{{
+#!ini
+rpki-subject-cert = ${myrpki::handle}.cer
+}}}
diff --git a/doc/manual/19.RPKI.CA.Configuration.CreatingRoot.md b/doc/manual/19.RPKI.CA.Configuration.CreatingRoot.md
new file mode 100644
index 00000000..777cf6e0
--- /dev/null
+++ b/doc/manual/19.RPKI.CA.Configuration.CreatingRoot.md
@@ -0,0 +1,123 @@
+# Creating an RPKI Root Certificate
+
+[rootd][] does not create RPKI root certificates automatically. If you're
+running your own root, you have to do this yourself. The usual method of doing
+this is to use the OpenSSL command line tool. The exact details will depend on
+which resources you need to put in the root certificate, the URIs for your
+publication server, and so forth, but the general form looks something like
+this:
+
+ [req]
+ default_bits = 2048
+ default_md = sha256
+ distinguished_name = req_dn
+ prompt = no
+ encrypt_key = no
+
+ [req_dn]
+ CN = Testbed RPKI root certificate
+
+ [x509v3_extensions]
+ basicConstraints = critical,CA:true
+ subjectKeyIdentifier = hash
+ keyUsage = critical,keyCertSign,cRLSign
+ subjectInfoAccess = @sia
+ certificatePolicies = critical,1.3.6.1.5.5.7.14.2
+ sbgp-autonomousSysNum = critical,@rfc3779_asns
+ sbgp-ipAddrBlock = critical,@rfc3997_addrs
+
+ [sia]
+ 1.3.6.1.5.5.7.48.5;URI = rsync://example.org/rpki/root/
+ 1.3.6.1.5.5.7.48.10;URI = rsync://example.org/rpki/root/root.mft
+
+ [rfc3779_asns]
+ AS.0 = 64496-64511
+ AS.1 = 65536-65551
+
+ [rfc3997_addrs]
+ IPv4.0 = 192.0.2.0/24
+ IPv4.1 = 198.51.100.0/24
+ IPv4.2 = 203.0.113.0/24
+ IPv6.0 = 2001:0DB8::/32
+
+Assuming you save this configuration in a file `root.conf`, you can use it to
+generate a root certificate as follows:
+
+ #!/bin/sh -
+
+ # Generate the root key if it doesn't already exist.
+ test -f root.key ||
+ openssl genrsa -out root.key 2048
+
+ # Generate the root certificate.
+ openssl req \
+ -new \
+ -x509 \
+ -config root.conf \
+ -key root.key \
+ -out root.cer \
+ -outform DER \
+ -days 1825 \
+ -set_serial 1 \
+ -extensions x509v3_extensions
+
+You may want to shorten the five year expiration time (1825 days), which is a
+bit long. It is a root certificate, so a long expiration is not unusual.
+
+When regenerating a certificate using the same key, just skip the `openssl
+genrsa` step above.
+
+You must copy the generated root.cer to the publication directory as defined
+in rpki.conf:
+
+ rpki-root-cert = ${myrpki::publication_base_directory}/root.cer
+
+You must place the generated root.key in a safe location where it is readable
+by rootd but not accessible to the outside world, then you need to tell rootd
+where to find it by setting the appropriate variable in rpki.conf. The
+directory where the daemons keep their BPKI keys and certificates should be
+suitable for this:
+
+ rpki-root-key = ${myrpki::bpki_servers_directory}/root.key
+
+To create a TAL format trust anchor locator use the `make-tal.sh` script from
+`$top/rp/rcynic`:
+
+ $top/rp/rcynic/make-tal.sh rsync://example.org/rpki/root/root.cer root.cer
+
+Note that, like any certificate, the root.cer you just generated will expire
+eventually. Either you need to remember to regenerate it before that happens,
+or you need to set up a cron job to do that for you automatically. Running the
+above shell script (really, just the `openssl req` command) should suffice to
+regenerate `root.cer`; remember to copy the updated `root.cer` to the
+publication directory.
+
+Regenerating the certificate does not require regenerating the TAL unless you
+change the key or URL.
+
+## Converting an existing RSA key from PKCS #8 format
+
+If you previously generated a certificate using `openssl req` with the
+`-newkey` option and are having difficulty getting `rootd` to accept the
+resulting private key, the problem may be that OpenSSL saved the private key
+file in PKCS #8 format. OpenSSL's behavior changed here, the `-newkey` option
+saved the key in PKCS #1 format, but newer versions use PKCS #8. While PKCS #8
+is indeed likely an improvement, the change confuses some programs, including
+versions of `rootd` from before we discovered this problem.
+
+If you think this might be your problem, you can convert the existing private
+key to PKCS #1 format with a script like this:
+
+ if ! openssl rsa -in root.key -out root.key.new
+ then
+ echo Conversion failed
+ rm root.key.new
+ elif cmp -s root.key root.key.new
+ echo No change
+ rm root.key.new
+ else
+ echo Converted
+ mv root.key.new root.key
+ fi
+
+[rootd]: 18.RPKI.CA.Configuration.rootd.md
diff --git a/doc/manual/19.RPKI.CA.Configuration.CreatingRoot.wiki b/doc/manual/19.RPKI.CA.Configuration.CreatingRoot.wiki
new file mode 100644
index 00000000..2661a111
--- /dev/null
+++ b/doc/manual/19.RPKI.CA.Configuration.CreatingRoot.wiki
@@ -0,0 +1,143 @@
+[[TracNav(doc/RPKI/TOC)]]
+
+= Creating an RPKI Root Certificate =
+
+[wiki:doc/RPKI/CA/Configuration/rootd rootd] does not create RPKI root
+certificates automatically. If you're running your own root, you have
+to do this yourself. The usual method of doing this is to use the
+OpenSSL command line tool. The exact details will depend on which
+resources you need to put in the root certificate, the URIs for your
+publication server, and so forth, but the general form looks something
+like this:
+
+{{{
+#!ini
+[req]
+default_bits = 2048
+default_md = sha256
+distinguished_name = req_dn
+prompt = no
+encrypt_key = no
+
+[req_dn]
+CN = Testbed RPKI root certificate
+
+[x509v3_extensions]
+basicConstraints = critical,CA:true
+subjectKeyIdentifier = hash
+keyUsage = critical,keyCertSign,cRLSign
+subjectInfoAccess = @sia
+certificatePolicies = critical,1.3.6.1.5.5.7.14.2
+sbgp-autonomousSysNum = critical,@rfc3779_asns
+sbgp-ipAddrBlock = critical,@rfc3997_addrs
+
+[sia]
+1.3.6.1.5.5.7.48.5;URI = rsync://example.org/rpki/root/
+1.3.6.1.5.5.7.48.10;URI = rsync://example.org/rpki/root/root.mft
+
+[rfc3779_asns]
+AS.0 = 64496-64511
+AS.1 = 65536-65551
+
+[rfc3997_addrs]
+IPv4.0 = 192.0.2.0/24
+IPv4.1 = 198.51.100.0/24
+IPv4.2 = 203.0.113.0/24
+IPv6.0 = 2001:0DB8::/32
+}}}
+
+Assuming you save this configuration in a file `root.conf`, you can
+use it to generate a root certificate as follows:
+
+{{{
+#!sh
+#!/bin/sh -
+
+# Generate the root key if it doesn't already exist.
+test -f root.key ||
+openssl genrsa -out root.key 2048
+
+# Generate the root certificate.
+openssl req \
+ -new \
+ -x509 \
+ -config root.conf \
+ -key root.key \
+ -out root.cer \
+ -outform DER \
+ -days 1825 \
+ -set_serial 1 \
+ -extensions x509v3_extensions
+}}}
+
+You may want to shorten the five year expiration time (1825 days),
+which is a bit long. It is a root certificate, so a long expiration
+is not unusual.
+
+When regenerating a certificate using the same key, just skip the
+`openssl genrsa` step above.
+
+You must copy the generated root.cer to the publication directory as
+defined in rpki.conf:
+
+{{{
+rpki-root-cert = ${myrpki::publication_base_directory}/root.cer
+}}}
+
+You must place the generated root.key in a safe location where it is
+readable by rootd but not accessible to the outside world, then you
+need to tell rootd where to find it by setting the appropriate
+variable in rpki.conf. The directory where the daemons keep their
+BPKI keys and certificates should be suitable for this:
+
+{{{
+rpki-root-key = ${myrpki::bpki_servers_directory}/root.key
+}}}
+
+To create a TAL format trust anchor locator use the `make-tal.sh`
+script from `$top/rp/rcynic`:
+
+{{{
+#!sh
+$top/rp/rcynic/make-tal.sh rsync://example.org/rpki/root/root.cer root.cer
+}}}
+
+Note that, like any certificate, the root.cer you just generated will
+expire eventually. Either you need to remember to regenerate it
+before that happens, or you need to set up a cron job to do that for
+you automatically. Running the above shell script (really, just the
+`openssl req` command) should suffice to regenerate `root.cer`;
+remember to copy the updated `root.cer` to the publication directory.
+
+Regenerating the certificate does not require regenerating the TAL
+unless you change the key or URL.
+
+
+== Converting an existing RSA key from PKCS !#8 format ==
+
+If you previously generated a certificate using `openssl req` with the
+`-newkey` option and are having difficulty getting `rootd` to accept
+the resulting private key, the problem may be that OpenSSL saved the
+private key file in PKCS !#8 format. OpenSSL's behavior changed here,
+the `-newkey` option saved the key in PKCS !#1 format, but newer
+versions use PKCS !#8. While PKCS !#8 is indeed likely an
+improvement, the change confuses some programs, including versions
+of `rootd` from before we discovered this problem.
+
+If you think this might be your problem, you can convert the existing
+private key to PKCS !#1 format with a script like this:
+
+{{{
+#!sh
+if ! openssl rsa -in root.key -out root.key.new
+then
+ echo Conversion failed
+ rm root.key.new
+elif cmp -s root.key root.key.new
+ echo No change
+ rm root.key.new
+else
+ echo Converted
+ mv root.key.new root.key
+fi
+}}}
diff --git a/doc/manual/20.RPKI.CA.Configuration.web_portal.md b/doc/manual/20.RPKI.CA.Configuration.web_portal.md
new file mode 100644
index 00000000..d04bd65e
--- /dev/null
+++ b/doc/manual/20.RPKI.CA.Configuration.web_portal.md
@@ -0,0 +1,47 @@
+# [web_portal] section
+
+Glue to allow the Django application to pull user configuration from this file
+rather than directly editing settings.py.
+
+## sql-database
+
+SQL database name the web portal should use.
+
+ sql-database = ${myrpki::irdbd_sql_database}
+
+## sql-username
+
+SQL user name the web portal should use.
+
+ sql-username = ${myrpki::irdbd_sql_username}
+
+## sql-password
+
+SQL password the web portal should use.
+
+ sql-password = ${myrpki::irdbd_sql_password}
+
+## secret-key
+
+Site-specific secret key for Django.
+
+No default value.
+
+## allowed-hosts
+
+Name of virtual host that runs the Django GUI, if this is not the same as the
+system hostname. Django's security code wants to know the name of the virtual
+host on which Django is running, and will fail when it thinks it's running on
+a disallowed host.
+
+If you get an error like "Invalid HTTP_HOST header (you may need to set
+ALLOWED_HOSTS)", you will need to set this option.
+
+No default value.
+
+## download-directory
+
+A directory large enough to hold the RouteViews?.org routing table dump
+fetched by the rpkigui-import-routes script.
+
+ download-directory = /var/tmp
diff --git a/doc/manual/20.RPKI.CA.Configuration.web_portal.wiki b/doc/manual/20.RPKI.CA.Configuration.web_portal.wiki
new file mode 100644
index 00000000..9df6487f
--- /dev/null
+++ b/doc/manual/20.RPKI.CA.Configuration.web_portal.wiki
@@ -0,0 +1,73 @@
+{{{
+#!comment
+
+******************************************************************************
+THIS PAGE WAS GENERATED AUTOMATICALLY, DO NOT EDIT.
+
+Generated from $Id: rpki-confgen.xml 6070 2015-03-23 18:04:06Z melkins $
+ by $Id: rpki-confgen 5856 2014-05-31 18:32:19Z sra $
+******************************************************************************
+
+}}}
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= [web_portal] section = #web_portal
+
+Glue to allow the Django application to pull user configuration from
+this file rather than directly editing settings.py.
+
+== sql-database == #sql-database
+
+SQL database name the web portal should use.
+
+{{{
+#!ini
+sql-database = ${myrpki::irdbd_sql_database}
+}}}
+
+== sql-username == #sql-username
+
+SQL user name the web portal should use.
+
+{{{
+#!ini
+sql-username = ${myrpki::irdbd_sql_username}
+}}}
+
+== sql-password == #sql-password
+
+SQL password the web portal should use.
+
+{{{
+#!ini
+sql-password = ${myrpki::irdbd_sql_password}
+}}}
+
+== secret-key == #secret-key
+
+Site-specific secret key for Django.
+
+No default value.
+
+== allowed-hosts == #allowed-hosts
+
+Name of virtual host that runs the Django GUI, if this is not the same
+as the system hostname. Django's security code wants to know the name
+of the virtual host on which Django is running, and will fail when it
+thinks it's running on a disallowed host.
+
+If you get an error like "Invalid HTTP_HOST header (you may need to
+set ALLOWED_HOSTS)", you will need to set this option.
+
+No default value.
+
+== download-directory == #download-directory
+
+A directory large enough to hold the RouteViews.org routing table dump
+fetched by the rpkigui-import-routes script.
+
+{{{
+#!ini
+download-directory = /var/tmp
+}}}
diff --git a/doc/manual/21.RPKI.CA.Configuration.autoconf.md b/doc/manual/21.RPKI.CA.Configuration.autoconf.md
new file mode 100644
index 00000000..0d803786
--- /dev/null
+++ b/doc/manual/21.RPKI.CA.Configuration.autoconf.md
@@ -0,0 +1,29 @@
+# [autoconf] section
+
+rpki-confgen --autoconf records the current autoconf settings here, so that
+other options can refer to them. The section name "autoconf" is magic, don't
+change it.
+
+## bindir
+
+Usually /usr/bin or /usr/local/bin.
+
+No default value.
+
+## datarootdir
+
+Usually /usr/share or /usr/local/share.
+
+No default value.
+
+## sbindir
+
+Usually /usr/sbin or /usr/local/sbin.
+
+No default value.
+
+## sysconfdir
+
+Usually /etc or /usr/local/etc.
+
+No default value.
diff --git a/doc/manual/21.RPKI.CA.Configuration.autoconf.wiki b/doc/manual/21.RPKI.CA.Configuration.autoconf.wiki
new file mode 100644
index 00000000..6a07de8c
--- /dev/null
+++ b/doc/manual/21.RPKI.CA.Configuration.autoconf.wiki
@@ -0,0 +1,43 @@
+{{{
+#!comment
+
+******************************************************************************
+THIS PAGE WAS GENERATED AUTOMATICALLY, DO NOT EDIT.
+
+Generated from $Id: rpki-confgen.xml 6070 2015-03-23 18:04:06Z melkins $
+ by $Id: rpki-confgen 5856 2014-05-31 18:32:19Z sra $
+******************************************************************************
+
+}}}
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= [autoconf] section = #autoconf
+
+rpki-confgen --autoconf records the current autoconf settings here, so
+that other options can refer to them. The section name "autoconf" is
+magic, don't change it.
+
+== bindir == #bindir
+
+Usually /usr/bin or /usr/local/bin.
+
+No default value.
+
+== datarootdir == #datarootdir
+
+Usually /usr/share or /usr/local/share.
+
+No default value.
+
+== sbindir == #sbindir
+
+Usually /usr/sbin or /usr/local/sbin.
+
+No default value.
+
+== sysconfdir == #sysconfdir
+
+Usually /etc or /usr/local/etc.
+
+No default value.
diff --git a/doc/manual/22.RPKI.CA.Configuration.Tests.md b/doc/manual/22.RPKI.CA.Configuration.Tests.md
new file mode 100644
index 00000000..6003788a
--- /dev/null
+++ b/doc/manual/22.RPKI.CA.Configuration.Tests.md
@@ -0,0 +1,108 @@
+# smoketest.yaml
+
+smoketest test description file is named smoketest.yaml by default. Run
+smoketest with "-y filename" to change it. The YAML file contains multiple
+YAML "documents". The first document describes the initial test layout and
+resource allocations, subsequent documents describe modifications to the
+initial allocations and other parameters. Resources listed in the initial
+layout are aggregated automatically, so that a node in the resource hierarchy
+automatically receives the resources it needs to issue whatever its children
+are listed as holding. Actions in the subsequent documents are modifications
+to the current resource set, modifications to validity dates or other non-
+resource parameters, or special commands like "sleep".
+
+Here's an example of current usage:
+
+ name: Alice
+ valid_for: 2d
+ sia_base: "rsync://alice.example/rpki/"
+ kids:
+ - name: Bob
+ kids:
+ - name: Carol
+ ipv4: 192.0.2.1-192.0.2.33
+ asn: 64533
+ ---
+ - name: Carol
+ valid_add: 10
+ ---
+ - name: Carol
+ add_as: 33
+ valid_add: 2d
+ ---
+ - name: Carol
+ valid_sub: 2d
+ ---
+ - name: Carol
+ valid_for: 10d
+
+This specifies an initial layout consisting of an RPKI engine named "Alice",
+with one child "Bob", which in turn has one child "Carol". Carol has a set of
+assigned resources, and all resources in the system are initially set to be
+valid for two days from the time at which the test is started. The first
+subsequent document adds ten seconds to the validity interval for Carol's
+resources and makes no other modifications. The second subsequent document
+grants Carol additional resources and adds another two days to the validity
+interval for Carol's resources. The next document subtracts two days from the
+validity interval for Carol's resources. The final document sets the validity
+interval for Carol's resources to ten days.
+
+Operators in subsequent (update) documents:
+
+add_as::
+
+> Add ASN resources.
+
+add_v4::
+
+> Add IPv4 resources.
+
+add_v6::
+
+> Add IPv6 resources.
+
+sub_as::
+
+> Subtract ASN resources.
+
+sub_v4::
+
+> Subtract IPv4 resources.
+
+sub_v6::
+
+> Subtract IPv6 resources.
+
+valid_until::
+
+> Set an absolute expiration date.
+
+valid_for::
+
+> Set a relative expiration date.
+
+valid_add::
+
+> Add to validity interval.
+
+valid_sub::
+
+> Subtract from validity interval.
+
+sleep [interval]::
+
+> Sleep for specified interval, or until smoketest receives a SIGALRM signal.
+
+shell cmd...::
+
+> Pass rest of line verbatim to /bin/sh and block until the shell returns.
+
+Absolute timestamps should be in the form shown (UTC timestamp format as used
+in XML).
+
+Intervals (`valid_add`, `valid_sub`, `valid_for`, `sleep)` are either
+integers, in which case they're interpreted as seconds, or are a string of the
+form "wD xH yM zS" where w, x, y, and z are integers and D, H, M, and S
+indicate days, hours, minutes, and seconds. In the latter case all of the
+fields are optional, but at least one must be specified. For example, "3D4H"
+means "three days plus four hours".
diff --git a/doc/manual/22.RPKI.CA.Configuration.Tests.wiki b/doc/manual/22.RPKI.CA.Configuration.Tests.wiki
new file mode 100644
index 00000000..8e349185
--- /dev/null
+++ b/doc/manual/22.RPKI.CA.Configuration.Tests.wiki
@@ -0,0 +1,102 @@
+= smoketest.yaml =
+
+[[TracNav(doc/RPKI/TOC)]]
+
+smoketest test description file is named smoketest.yaml by default.
+Run smoketest with "-y filename" to change it. The YAML file contains
+multiple YAML "documents". The first document describes the initial
+test layout and resource allocations, subsequent documents describe
+modifications to the initial allocations and other parameters.
+Resources listed in the initial layout are aggregated automatically,
+so that a node in the resource hierarchy automatically receives the
+resources it needs to issue whatever its children are listed as
+holding. Actions in the subsequent documents are modifications to the
+current resource set, modifications to validity dates or other
+non-resource parameters, or special commands like "sleep".
+
+Here's an example of current usage:
+
+{{{
+ name: Alice
+ valid_for: 2d
+ sia_base: "rsync://alice.example/rpki/"
+ kids:
+ - name: Bob
+ kids:
+ - name: Carol
+ ipv4: 192.0.2.1-192.0.2.33
+ asn: 64533
+ ---
+ - name: Carol
+ valid_add: 10
+ ---
+ - name: Carol
+ add_as: 33
+ valid_add: 2d
+ ---
+ - name: Carol
+ valid_sub: 2d
+ ---
+ - name: Carol
+ valid_for: 10d
+}}}
+
+This specifies an initial layout consisting of an RPKI engine named
+"Alice", with one child "Bob", which in turn has one child "Carol".
+Carol has a set of assigned resources, and all resources in the system
+are initially set to be valid for two days from the time at which the
+test is started. The first subsequent document adds ten seconds to
+the validity interval for Carol's resources and makes no other
+modifications. The second subsequent document grants Carol additional
+resources and adds another two days to the validity interval for
+Carol's resources. The next document subtracts two days from the
+validity interval for Carol's resources. The final document sets the
+validity interval for Carol's resources to ten days.
+
+Operators in subsequent (update) documents:
+
+add_as::
+ Add ASN resources.
+
+add_v4::
+ Add IPv4 resources.
+
+add_v6::
+ Add IPv6 resources.
+
+sub_as::
+ Subtract ASN resources.
+
+sub_v4::
+ Subtract IPv4 resources.
+
+sub_v6::
+ Subtract IPv6 resources.
+
+valid_until::
+ Set an absolute expiration date.
+
+valid_for::
+ Set a relative expiration date.
+
+valid_add::
+ Add to validity interval.
+
+valid_sub::
+ Subtract from validity interval.
+
+sleep [interval]::
+ Sleep for specified interval, or until smoketest receives a SIGALRM signal.
+
+shell cmd...::
+ Pass rest of line verbatim to /bin/sh and block until the shell returns.
+
+Absolute timestamps should be in the form shown (UTC timestamp format
+as used in XML).
+
+Intervals ({{{valid_add}}}, {{{valid_sub}}}, {{{valid_for}}}, {{{sleep)}}} are either
+integers, in which case they're interpreted as seconds, or are a
+string of the form "wD xH yM zS" where w, x, y, and z are integers and
+D, H, M, and S indicate days, hours, minutes, and seconds. In the
+latter case all of the fields are optional, but at least one must be
+specified. For example, "3D4H" means "three days plus four hours".
diff --git a/doc/manual/23.RPKI.CA.Configuration.DifferentServer.md b/doc/manual/23.RPKI.CA.Configuration.DifferentServer.md
new file mode 100644
index 00000000..a3f3e794
--- /dev/null
+++ b/doc/manual/23.RPKI.CA.Configuration.DifferentServer.md
@@ -0,0 +1,37 @@
+# Running rpkid or pubd on a different server
+
+The default configuration runs rpkid, pubd (if enabled) and the back end code
+all on the same server. For many purposes, this is fine, but in some cases you
+might want to split these functions up among different servers.
+
+As noted briefly above, there are two separate sets of rpki.conf options which
+control the necessary behavior: the `run_*` options and the `start_*` options.
+The latter are usually tied to the former, but you can set them separately,
+and they control slightly different things: the `run_*` options control
+whether the back end code attempts to manage the servers in question, while
+the `start_*` flags control whether the startup scripts should start the
+servers in question.
+
+Here's a guideline to how to set up the servers on different machines. For
+purposes of this description we'll assume that you're running both rpkid and
+pubd, and that you want rpkid and pubd each on their own server, separate from
+the back end code. We'll call these servers rpkid.example.org,
+pubd.example.org, and backend.example.org.
+
+Most of the configuration is the same as in the normal case, but there are a
+few extra steps. The following supplements but does not replace the normal
+instructions.
+
+**WARNING**: These setup directions have not (yet) been tested extensively.
+
+ * Create rpki.conf as usual on backend.example.org, but pay particular attention to the settings of `rpkid_server_host`, `irbe_server_host`, and `pubd_server_host`: these should name rpkid.example.org, backend.example.org, and pubd.example.org, respectively.
+ * This example assumes that you're running pubd, so make sure that both `run_rpkid` and `run_pubd` are enabled in rpki.conf.
+ * Copy the rpki.conf to the other machines, and customize each copy to that machine's role:
+ * `start_rpkid` should be enabled on rpkid.example.org and disabled on the others.
+ * `start_pubd` should be enabled on pubd.example.org and disabled on the others.
+ * `start_irdbd` should be enabled on backend.example.org and disabled on the others.
+ * Make sure that you set up SQL databases on all three servers; the `rpki-sql-setup` script should do the right thing in each case based on the setting of the `start_*` options.
+ * Run "rpkic initialize" on the back end host. This will create the BPKI and write out all of the necessary keys and certificates.
+ * "rpkic initialize" should have created the BPKI files (.cer, .key, and .crl files for the several servers). Copy the .cer and .crl files to the pubd and rpkid hosts, along with the appropriate private key: rpkid.example.org should get a copy of the rpkid.key file but not the pubd.key file, while pubd.example.org should get a copy of the pubd.key file but not the rpkid.key file.
+ * Run `rpki-start-servers` on each of the three hosts when it's time to start the servers.
+ * Do the usual setup dance, but keep in mind that the the back end controlling all of these servers lives on backend.example.org, so that's where you issue the rpkic or GUI commands to manage them. rpkic and the GUI both know how to talk to rpkid and pubd over the network, so managing them remotely is fine.
diff --git a/doc/manual/23.RPKI.CA.Configuration.DifferentServer.wiki b/doc/manual/23.RPKI.CA.Configuration.DifferentServer.wiki
new file mode 100644
index 00000000..3e31bc2b
--- /dev/null
+++ b/doc/manual/23.RPKI.CA.Configuration.DifferentServer.wiki
@@ -0,0 +1,69 @@
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= Running rpkid or pubd on a different server =
+
+The default configuration runs rpkid, pubd (if enabled) and the back
+end code all on the same server. For many purposes, this is fine, but
+in some cases you might want to split these functions up among
+different servers.
+
+As noted briefly above, there are two separate sets of rpki.conf
+options which control the necessary behavior: the `run_*` options
+and the `start_*` options. The latter are usually tied to the
+former, but you can set them separately, and they control slightly
+different things: the `run_*` options control whether the back end
+code attempts to manage the servers in question, while the
+`start_*` flags control whether the startup scripts should start
+the servers in question.
+
+Here's a guideline to how to set up the servers on different machines.
+For purposes of this description we'll assume that you're running both
+rpkid and pubd, and that you want rpkid and pubd each on their own
+server, separate from the back end code. We'll call these servers
+rpkid.example.org, pubd.example.org, and backend.example.org.
+
+Most of the configuration is the same as in the normal case, but there
+are a few extra steps. The following supplements but does not replace
+the normal instructions.
+
+**WARNING**: These setup directions have not (yet) been tested
+extensively.
+
+* Create rpki.conf as usual on backend.example.org, but pay particular
+ attention to the settings of `rpkid_server_host`,
+ `irbe_server_host`, and `pubd_server_host`: these should
+ name rpkid.example.org, backend.example.org, and pubd.example.org,
+ respectively.
+
+* This example assumes that you're running pubd, so make sure that
+ both `run_rpkid` and `run_pubd` are enabled in rpki.conf.
+
+* Copy the rpki.conf to the other machines, and customize each copy to
+ that machine's role:
+ * `start_rpkid` should be enabled on rpkid.example.org and disabled on the others.
+ * `start_pubd` should be enabled on pubd.example.org and disabled on the others.
+ * `start_irdbd` should be enabled on backend.example.org and disabled on the others.
+
+* Make sure that you set up SQL databases on all three servers; the
+ `rpki-sql-setup` script should do the right thing in each case
+ based on the setting of the `start_*` options.
+
+* Run "rpkic initialize" on the back end host. This will create the
+ BPKI and write out all of the necessary keys and certificates.
+
+* "rpkic initialize" should have created the BPKI files (.cer, .key,
+ and .crl files for the several servers). Copy the .cer and .crl
+ files to the pubd and rpkid hosts, along with the appropriate
+ private key: rpkid.example.org should get a copy of the rpkid.key
+ file but not the pubd.key file, while pubd.example.org should get a
+ copy of the pubd.key file but not the rpkid.key file.
+
+* Run `rpki-start-servers` on each of the three hosts when it's
+ time to start the servers.
+
+* Do the usual setup dance, but keep in mind that the the back end
+ controlling all of these servers lives on backend.example.org, so
+ that's where you issue the rpkic or GUI commands to manage them.
+ rpkic and the GUI both know how to talk to rpkid and pubd over the
+ network, so managing them remotely is fine.
diff --git a/doc/manual/24.RPKI.CA.MySQLSetup.md b/doc/manual/24.RPKI.CA.MySQLSetup.md
new file mode 100644
index 00000000..bad9dd8e
--- /dev/null
+++ b/doc/manual/24.RPKI.CA.MySQLSetup.md
@@ -0,0 +1,65 @@
+# RPKI Engine MySQL Setup
+
+You need to install MySQL and set up the relevant databases before starting
+rpkid, irdbd, or pubd.
+
+See the [Installation Guide][Installation] for details on where to download MySQL and
+find documentation on installing it.
+
+See the [Configuration Guide][Configuration] for details on the configuration file
+settings the daemons will use to find and authenticate themselves to their
+respective databases.
+
+Before you can (usefully) start any of the daemons, you will need to set up
+the MySQL databases they use. You can do this by hand, or you can use the
+`rpki-sql-setup` script, which prompts you for your MySQL root password then
+attempts to do everything else automatically using values from rpki.conf.
+
+Using the script is simple:
+
+ $ rpki-sql-setup
+ Please enter your MySQL root password:
+
+The script should tell you what databases it creates. You can use the -v
+option if you want to see more details about what it's doing.
+
+If you'd prefer to do the SQL setup manually, perhaps because you have
+valuable data in other MySQL databases and you don't want to trust some random
+setup script with your MySQL root password, you'll need to use the MySQL
+command line tool, as follows:
+
+ $ mysql -u root -p
+
+ mysql> CREATE DATABASE irdb_database;
+ mysql> GRANT all ON irdb_database.* TO irdb_user@localhost IDENTIFIED BY 'irdb_password';
+ mysql> CREATE DATABASE rpki_database;
+ mysql> GRANT all ON rpki_database.* TO rpki_user@localhost IDENTIFIED BY 'rpki_password';
+ mysql> USE rpki_database;
+ mysql> SOURCE $top/schemas/sql/rpkid.sql;
+ mysql> COMMIT;
+ mysql> quit
+
+where `irdb_database`, `irdb_user`, `irdb_password`, `rpki_database`,
+`rpki_user`, and `rpki_password` match the values you used in your
+configuration file.
+
+If you are running pubd and are doing manual SQL setup, you'll also have to
+do:
+
+ $ mysql -u root -p
+ mysql> CREATE DATABASE pubd_database;
+ mysql> GRANT all ON pubd_database.* TO pubd_user@localhost IDENTIFIED BY 'pubd_password';
+ mysql> USE pubd_database;
+ mysql> SOURCE $top/schemas/sql/pubd.sql;
+ mysql> COMMIT;
+ mysql> quit
+
+where `pubd_database`, `pubd_user` `pubd_password` match the values you used
+in your configuration file.
+
+Once you've finished configuring MySQL, the next thing you should read is the
+instructions for the [user interface tools][UI].
+
+[Installation]: 01.RPKI.Installation.md
+[Configuration]: 12.RPKI.CA.Configuration.md
+[UI]: 26.RPKI.CA.UI.md
diff --git a/doc/manual/24.RPKI.CA.MySQLSetup.wiki b/doc/manual/24.RPKI.CA.MySQLSetup.wiki
new file mode 100644
index 00000000..13d88be1
--- /dev/null
+++ b/doc/manual/24.RPKI.CA.MySQLSetup.wiki
@@ -0,0 +1,73 @@
+= RPKI Engine MySQL Setup =
+
+[[TracNav(doc/RPKI/TOC)]]
+
+You need to install MySQL and set up the relevant databases before
+starting rpkid, irdbd, or pubd.
+
+See the [[Installation|Installation Guide]] for details on
+where to download MySQL and find documentation on installing it.
+
+See the [[Configuration|Configuration Guide]] for details on
+the configuration file settings the daemons will use to find and
+authenticate themselves to their respective databases.
+
+Before you can (usefully) start any of the daemons, you will need to
+set up the MySQL databases they use. You can do this by hand, or
+you can use the {{{rpki-sql-setup}}} script, which prompts you for your
+MySQL root password then attempts to do everything else
+automatically using values from rpki.conf.
+
+Using the script is simple:
+
+{{{
+#!sh
+$ rpki-sql-setup
+Please enter your MySQL root password:
+}}}
+
+The script should tell you what databases it creates. You can use
+the -v option if you want to see more details about what it's doing.
+
+If you'd prefer to do the SQL setup manually, perhaps because you
+have valuable data in other MySQL databases and you don't want to
+trust some random setup script with your MySQL root password, you'll
+need to use the MySQL command line tool, as follows:
+
+{{{
+#!sh
+$ mysql -u root -p
+
+mysql> CREATE DATABASE irdb_database;
+mysql> GRANT all ON irdb_database.* TO irdb_user@localhost IDENTIFIED BY 'irdb_password';
+mysql> CREATE DATABASE rpki_database;
+mysql> GRANT all ON rpki_database.* TO rpki_user@localhost IDENTIFIED BY 'rpki_password';
+mysql> USE rpki_database;
+mysql> SOURCE $top/schemas/sql/rpkid.sql;
+mysql> COMMIT;
+mysql> quit
+}}}
+
+where {{{irdb_database}}}, {{{irdb_user}}}, {{{irdb_password}}},
+{{{rpki_database}}}, {{{rpki_user}}}, and {{{rpki_password}}} match
+the values you used in your configuration file.
+
+If you are running pubd and are doing manual SQL setup, you'll also
+have to do:
+
+{{{
+#!sh
+$ mysql -u root -p
+mysql> CREATE DATABASE pubd_database;
+mysql> GRANT all ON pubd_database.* TO pubd_user@localhost IDENTIFIED BY 'pubd_password';
+mysql> USE pubd_database;
+mysql> SOURCE $top/schemas/sql/pubd.sql;
+mysql> COMMIT;
+mysql> quit
+}}}
+
+where {{{pubd_database}}}, {{{pubd_user}}} {{{pubd_password}}} match the
+values you used in your configuration file.
+
+Once you've finished configuring MySQL, the next thing you should
+read is the instructions for the [[UI|user interface tools]].
diff --git a/doc/manual/25.RPKI.CA.OOBSetup.md b/doc/manual/25.RPKI.CA.OOBSetup.md
new file mode 100644
index 00000000..b0754f07
--- /dev/null
+++ b/doc/manual/25.RPKI.CA.OOBSetup.md
@@ -0,0 +1,4 @@
+# RPKI CA Out-Of-Band Setup Protocol
+
+Not documented yet. Eventually this will be a readable explanation of the out-
+of-band setup protocol.
diff --git a/doc/manual/25.RPKI.CA.OOBSetup.wiki b/doc/manual/25.RPKI.CA.OOBSetup.wiki
new file mode 100644
index 00000000..dde87608
--- /dev/null
+++ b/doc/manual/25.RPKI.CA.OOBSetup.wiki
@@ -0,0 +1,6 @@
+= RPKI CA Out-Of-Band Setup Protocol =
+
+[[TracNav(doc/RPKI/TOC)]]
+
+Not documented yet. Eventually this will be a readable explanation of
+the out-of-band setup protocol.
diff --git a/doc/manual/26.RPKI.CA.UI.md b/doc/manual/26.RPKI.CA.UI.md
new file mode 100644
index 00000000..8f05a518
--- /dev/null
+++ b/doc/manual/26.RPKI.CA.UI.md
@@ -0,0 +1,107 @@
+# The CA user interface tools
+
+The design of rpkid and pubd assumes that certain tasks can be thrown over the
+wall to the registry's back end operation. This was a deliberate design
+decision to allow rpkid and pubd to remain independent of existing database
+schema, business PKIs, and so forth that a registry might already have. All
+very nice, but it leaves someone who just wants to test the tools or who has
+no existing back end with a fairly large programming project. The user
+interface tools attempt to fill that gap. Together with irdbd, these tools
+consitute the "IR back-end" (IRBE) programs.
+
+[rpkic][1] is a command line interface to the the IRBE. The [web interface][2]
+is a Django-based graphical user interface to the IRBE. The two user
+interfaces are built on top of the same libraries, and can be used fairly
+interchangeably. Most users will probably prefer the GUI, but the command line
+interface may be useful for scripted control, for testing, or for environments
+where running a web server is not practical.
+
+A large registry which already has its own back-end system might want to roll
+their own replacement for the entire IRBE package. The tools are designed to
+allow this.
+
+The user interface tools support two broad classes of operations:
+
+ 1. Relationship management: setting up relationships between RPKI parent and child entities and between publication repositories and their clients. This is primarily about exchange of BPKI keys with other entities and learning the service URLs at which rpkid should contact other servers. We refer to this as the "setup phase".
+ 2. Operation of rpkid once relationships have been set up: issuing ROAs, assigning resources to children, and so forth. We refer to this as the "data maintenance" phase.
+
+During setup phase, the tools generate and processes small XML messages, which
+they expects the user to ship to and from its parents, children, etc via some
+out-of-band means (email, perhaps with PGP signatures, USB stick, we really
+don't care). During data maintenance phase, the tools control the operation of
+rpkid and pubd.
+
+While the normal way to enter data during maintenance phase is by filling out
+web forms, there's also a file-based format which can be used to upload and
+download data from the GUI; the command line tool uses the same file format.
+These files are simple whitespace-delimited text files (".csv files" -- the
+name is historical, at one point these were parsed and generated using the
+Python "csv" library, and the name stuck). The intent is that these be very
+simple files that are easy to parse or to generate as a dump from relational
+database, spreadsheet, awk script, whatever works in your environment.
+
+As with rpkid and pubd, the user interface tools use a configuration file,
+which defaults to the same system-wide rpki.conf file as the other programs.
+
+## Overview of setup phase
+
+While the specific commands one uses differ depending on whether you are using
+the command line tool or the GUI, the basic operations during setup phase are
+the same:
+
+ 1. If you haven't already done so, [install the software][3], create the [rpki.conf][4] for your installation, and [set up the MySQL database][5].
+ 2. If you haven't already done so, create the initial BPKI database for your installation by running the "rpkic initialize" command. This will also create a BPKI identity for the handle specified in your rpki.conf file. BPKI initialization is tied to creation of the initial BPKI identity for historical reasons. These operations probably ought to be handled by separate commands, and may be in the future.
+ 3. If you haven't already done so, start the servers, using the `rpki-start-servers` script.
+ 4. Send a copy of the XML identity file written out by "rpkic initialize" to each of your parents, somehow (email, USB stick, carrier pigeon, we don't care). The XML identity file will have a filename like ./${handle}.identity.xml where "." is the directory in which you ran rpkic and ${handle} is the handle set in your rpki.conf file or selected with rpkic's `select_identity` command. This XML identity file tells each of your parents what you call yourself, and supplies each parent with a trust anchor for your resource-holding BPKI.
+ 5. Each of your parents configures you as a child, using the XML identity file you supplied as input. This registers your data with the parent, including BPKI cross-registration, and generates a return message containing your parent's BPKI trust anchors, a service URL for contacting your parent via the "up-down" protocol, and (usually) either an offer of publication service (if your parent operates a repository) or a referral from your parent to whatever publication service your parent does use. Referrals include a CMS-signed authorization token that the repository operator can use to determine that your parent has given you permission to home underneath your parent in the publication tree.
+ 6. Each of your parents sends (...) back the response XML file generated by the "configure_child" command.
+ 7. You feed the response message you just got into the IRBE using rpkic's "configure_parent" command. This registers the parent's information in your database, handles BPKI cross-certification of your parent., and processes the repository offer or referral to generate a publication request message.
+ 8. You send (...) the publication request message to the repository. The `contact_info` element in the request message should (in theory) provide some clue as to where you should send this.
+ 9. The repository operator processes your request using rpkic's "configure_publication_client" command. This registers your information, including BPKI cross-certification, and generates a response message containing the repository's BPKI trust anchor and service URL.
+ 10. Repository operator sends (...) the publication confirmation message back to you.
+ 11. You process the publication confirmation message using rpkic's "configure_repository" command.
+
+At this point you should, in theory, have established relationships, exchanged
+trust anchors, and obtained service URLs from all of your parents and
+repositories.
+
+## Troubleshooting
+
+If you run into trouble setting up this package, the first thing to do is
+categorize the kind of trouble you are having. If you've gotten far enough to
+be running the daemons, check their log files. If you're seeing Python
+exceptions, read the error messages. If you're getting CMS errors, check to
+make sure that you're using all the right BPKI certificates and service
+contact URLs.
+
+If you've completed the steps above, everything appears to have gone OK, but
+nothing seems to be happening, the first thing to do is check the logs to
+confirm that nothing is actively broken. rpkid's log should include messages
+telling you when it starts and finishes its internal "cron" cycle. It can take
+several cron cycles for resources to work their way down from your parent into
+a full set of certificates and ROAs, so have a little patience. rpkid's log
+should also include messages showing every time it contacts its parent(s) or
+attempts to publish anything.
+
+rcynic in fully verbose mode provides a fairly detailed explanation of what
+it's doing and why objects that fail have failed.
+
+You can use rsync (sic) to examine the contents of a publication repository
+one directory at a time, without attempting validation, by running rsync with
+just the URI of the directory on its command line:
+
+ $ rsync rsync://rpki.example.org/where/ever/
+
+If you need to examine RPKI objects in detail, you have a few options:
+
+ * The [RPKI utilities][6] include several programs for dumping RPKI-specific objects in text form.
+ * The OpenSSL command line program can also be useful for examining and manipulating certificates and CMS messages, although the syntax of some of the commands can be a bit obscure.
+ * Peter Gutmann's excellent [dumpasn1][7] program may be useful if you are desperate enough that you need to examine raw ASN.1 objects.
+
+[1]: 26.RPKI.CA.UI.md.rpkic
+[2]: 28.RPKI.CA.UI.GUI.md
+[3]: 01.RPKI.Installation.md
+[4]: 12.RPKI.CA.Configuration.md
+[5]: 24.RPKI.CA.MySQLSetup.md
+[6]: 36.RPKI.Utils.md
+[7]: http://www.cs.auckland.ac.nz/~pgut001/dumpasn1.c
diff --git a/doc/manual/26.RPKI.CA.UI.wiki b/doc/manual/26.RPKI.CA.UI.wiki
new file mode 100644
index 00000000..6679c5ef
--- /dev/null
+++ b/doc/manual/26.RPKI.CA.UI.wiki
@@ -0,0 +1,177 @@
+= The CA user interface tools =
+
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+The design of rpkid and pubd assumes that certain tasks can be thrown
+over the wall to the registry's back end operation. This was a
+deliberate design decision to allow rpkid and pubd to remain
+independent of existing database schema, business PKIs, and so forth
+that a registry might already have. All very nice, but it leaves
+someone who just wants to test the tools or who has no existing back
+end with a fairly large programming project. The user interface tools
+attempt to fill that gap. Together with irdbd, these tools consitute
+the "IR back-end" (IRBE) programs.
+
+[[./rpkic|rpkic]] is a command line interface to the the IRBE. The
+[[./GUI|web interface]] is a Django-based graphical user interface to
+the IRBE. The two user interfaces are built on top of the same
+libraries, and can be used fairly interchangeably. Most users will
+probably prefer the GUI, but the command line interface may be useful
+for scripted control, for testing, or for environments where running a
+web server is not practical.
+
+A large registry which already has its own back-end system might want
+to roll their own replacement for the entire IRBE package. The tools
+are designed to allow this.
+
+The user interface tools support two broad classes of operations:
+
+1. Relationship management: setting up relationships between RPKI
+ parent and child entities and between publication repositories and
+ their clients. This is primarily about exchange of BPKI keys with
+ other entities and learning the service URLs at which rpkid should
+ contact other servers. We refer to this as the "setup phase".
+
+2. Operation of rpkid once relationships have been set up: issuing
+ ROAs, assigning resources to children, and so forth. We refer to
+ this as the "data maintenance" phase.
+
+During setup phase, the tools generate and processes small XML
+messages, which they expects the user to ship to and from its parents,
+children, etc via some out-of-band means (email, perhaps with PGP
+signatures, USB stick, we really don't care). During data maintenance
+phase, the tools control the operation of rpkid and pubd.
+
+While the normal way to enter data during maintenance phase is by
+filling out web forms, there's also a file-based format which can be
+used to upload and download data from the GUI; the command line tool
+uses the same file format. These files are simple
+whitespace-delimited text files (".csv files" -- the name is
+historical, at one point these were parsed and generated using the
+Python "csv" library, and the name stuck). The intent is that these
+be very simple files that are easy to parse or to generate as a dump
+from relational database, spreadsheet, awk script, whatever works in
+your environment.
+
+As with rpkid and pubd, the user interface tools use a configuration
+file, which defaults to the same system-wide rpki.conf file as the
+other programs.
+
+== Overview of setup phase == #overview
+
+While the specific commands one uses differ depending on whether you
+are using the command line tool or the GUI, the basic operations
+during setup phase are the same:
+
+1. If you haven't already done so,
+ [[Installation|install the software]], create the
+ [[Configuration|rpki.conf]] for your installation, and
+ [[MySQLSetup|set up the MySQL database]].
+
+2. If you haven't already done so, create the initial BPKI database
+ for your installation by running the "rpkic initialize" command.
+ This will also create a BPKI identity for the handle specified in
+ your rpki.conf file. BPKI initialization is tied to creation of
+ the initial BPKI identity for historical reasons. These operations
+ probably ought to be handled by separate commands, and may be in
+ the future.
+
+3. If you haven't already done so, start the servers, using the
+ {{{rpki-start-servers}}} script.
+
+4. Send a copy of the XML identity file written out by "rpkic
+ initialize" to each of your parents, somehow (email, USB stick,
+ carrier pigeon, we don't care). The XML identity file will have a
+ filename like ./${handle}.identity.xml where "." is the directory
+ in which you ran rpkic and ${handle} is the handle set in your
+ rpki.conf file or selected with rpkic's {{{select_identity}}}
+ command. This XML identity file tells each of your parents what
+ you call yourself, and supplies each parent with a trust anchor for
+ your resource-holding BPKI.
+
+5. Each of your parents configures you as a child, using the XML
+ identity file you supplied as input. This registers your data with
+ the parent, including BPKI cross-registration, and generates a
+ return message containing your parent's BPKI trust anchors, a
+ service URL for contacting your parent via the "up-down" protocol,
+ and (usually) either an offer of publication service (if your
+ parent operates a repository) or a referral from your parent to
+ whatever publication service your parent does use. Referrals
+ include a CMS-signed authorization token that the repository
+ operator can use to determine that your parent has given you
+ permission to home underneath your parent in the publication tree.
+
+6. Each of your parents sends (...) back the response XML file
+ generated by the "configure_child" command.
+
+7. You feed the response message you just got into the IRBE using
+ rpkic's "configure_parent" command. This registers the
+ parent's information in your database, handles BPKI
+ cross-certification of your parent., and processes the repository
+ offer or referral to generate a publication request message.
+
+8. You send (...) the publication request message to the repository.
+ The {{{contact_info}}} element in the request message should (in
+ theory) provide some clue as to where you should send this.
+
+9. The repository operator processes your request using rpkic's "configure_publication_client" command. This registers
+ your information, including BPKI cross-certification, and generates
+ a response message containing the repository's BPKI trust anchor
+ and service URL.
+
+10. Repository operator sends (...) the publication confirmation
+ message back to you.
+
+11. You process the publication confirmation message using rpkic's "configure_repository" command.
+
+At this point you should, in theory, have established relationships,
+exchanged trust anchors, and obtained service URLs from all of your
+parents and repositories.
+
+== Troubleshooting ==
+
+If you run into trouble setting up this package, the first thing to do
+is categorize the kind of trouble you are having. If you've gotten
+far enough to be running the daemons, check their log files. If
+you're seeing Python exceptions, read the error messages. If you're
+getting CMS errors, check to make sure that you're using all the right
+BPKI certificates and service contact URLs.
+
+If you've completed the steps above, everything appears to have gone
+OK, but nothing seems to be happening, the first thing to do is check
+the logs to confirm that nothing is actively broken. rpkid's log
+should include messages telling you when it starts and finishes its
+internal "cron" cycle. It can take several cron cycles for resources
+to work their way down from your parent into a full set of
+certificates and ROAs, so have a little patience. rpkid's log should
+also include messages showing every time it contacts its parent(s) or
+attempts to publish anything.
+
+rcynic in fully verbose mode provides a fairly detailed
+explanation of what it's doing and why objects that fail have
+failed.
+
+You can use rsync (sic) to examine the contents of a publication
+repository one directory at a time, without attempting validation,
+by running rsync with just the URI of the directory on its command
+line:
+
+{{{
+#!sh
+$ rsync rsync://rpki.example.org/where/ever/
+}}}
+
+If you need to examine RPKI objects in detail, you have a few options:
+
+* The [[../../Utils|RPKI utilities]] include several programs for dumping
+ RPKI-specific objects in text form.
+
+* The OpenSSL command line program can also be useful for examining
+ and manipulating certificates and CMS messages, although the syntax
+ of some of the commands can be a bit obscure.
+
+* Peter Gutmann's excellent
+ [[http://www.cs.auckland.ac.nz/~pgut001/dumpasn1.c|dumpasn1]]
+ program may be useful if you are desperate enough that you need to
+ examine raw ASN.1 objects.
diff --git a/doc/manual/27.RPKI.CA.UI.rpkic.md b/doc/manual/27.RPKI.CA.UI.rpkic.md
new file mode 100644
index 00000000..1a2df053
--- /dev/null
+++ b/doc/manual/27.RPKI.CA.UI.rpkic.md
@@ -0,0 +1,86 @@
+# The rpkic tool
+
+rpkic is a command line interface to rpkid and pubd. It implements largely the
+same functionality as the [web interface][GUI]. In most cases you will want to
+use the web interface for normal operation, but rpkic is available if you need
+it.
+
+rpkic can be run either in an interactive mode or by passing a single command
+on the command line when starting the program; the former mode is intended to
+be somewhat human-friendly, the latter mode is useful in scripting, cron jobs,
+and automated testing.
+
+Some rpkic commands write out data files, usually in the current directory.
+
+rpkic uses the same system-wide [rpki.conf][Configuration] file as the other CA tools as
+its default configuration file.
+
+rpkic includes a "help" command which provides inline help for its several
+commands.
+
+## Selecting an identity
+
+The _handle_ variable in rpki.conf specifies the handle of the default
+identity for an rpkic command, but this is just the default. rpkid can host an
+arbitrary number of identities, and rpkic has to be able to control all of
+them.
+
+When running rpkic interactively, use rpkic's "select_identity" command to set
+the current identity handle.
+
+When running rpkic with a single command on the command line, use the "-i" (or
+"--identity") option to set the current identity handle.
+
+## rpkic in setup phase
+
+See the [introduction to the user interfaces][UI] for an overview of how setup
+phase works. The general structure of the setup phase in rpkic is as described
+there, but here we provide the specific commands involved. The following
+assumes that you have already installed the software and started the servers.
+
+ * The rpkic "initialize" command writes out an "identity.xml" file in addition to all of its other tasks.
+ * A parent who is using rpkic runs the "configure_child" command to configure the child, giving this command the identity.xml file the child supplied as input. configure_child will write out a response XML file, which the parent sends back to the child.
+ * A child who is running rpkic runs the "configure_parent" command to process the parent's response, giving it the XML file sent back by the parent as input to this command. configure_parent will write out a publication request XML file, which the child sents to the repository operator.
+ * A repository operator who is using rpkic runs the "configure_publication_client" command to process a client's publication request. configure_publication_client generates a confirmation XML message which the repository operator sends back to the client.
+ * A publication client who is using rpkic runs the "configure_repository" command to process the repository's response.
+
+## rpkic in data maintenance phase
+
+rpkic uses whitespace-delimited text files (called ".csv files", for
+historical reasons) to control issuance of addresses and autonomous sequence
+numbers to children, and to control issuance of ROAs. See the "load_asns",
+"load_prefixes", and "load_roa_requests" commands.
+
+## Maintaining child validity data
+
+All resources issued to child entities are tagged with a validity date. If not
+updated, these resources will eventually expire. rpkic includes two commands
+for updating these validity dates:
+
+ * "renew_child" updates the validity date for a specific child.
+ * "renew_all_children" updates the validity date for all children.
+
+## BPKI maintenance
+
+Certificates and CRLs in the BPKI have expiration dates and netUpdate dates,
+so they need to be maintained. Failure to maintain these will eventually cause
+the CA software to grind to a halt, as expired certificates will cause CMS
+validation failures.
+
+rpkic's "update_bpki" command takes care of this. Usually one will want to run
+this periodically (perhaps once per month), under cron.
+
+## Forcing synchronization
+
+Most rpkic commands synchronize the back end database with the daemons
+automatically, so in general it should not be necessary to synchronize
+manually. However, since these are separate databases, it is theoretically
+possible for them to get out of synch, perhaps because something crashed at
+exactly the wrong time.
+
+rpkic's "synchronize" command runs a synchronization cycle with rpkid (if
+`run_rpkic` is set) and pubd (if `run_pubd` is set).
+
+[GUI]: 28.RPKI.CA.UI.GUI.md
+[Configuration]: 12.RPKI.CA.Configuration.md
+[UI]: 26.RPKI.CA.UI.md
diff --git a/doc/manual/27.RPKI.CA.UI.rpkic.wiki b/doc/manual/27.RPKI.CA.UI.rpkic.wiki
new file mode 100644
index 00000000..044372d3
--- /dev/null
+++ b/doc/manual/27.RPKI.CA.UI.rpkic.wiki
@@ -0,0 +1,105 @@
+= The rpkic tool =
+
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+rpkic is a command line interface to rpkid and pubd. It implements
+largely the same functionality as the [[GUI|web interface]]. In most
+cases you will want to use the web interface for normal operation, but
+rpkic is available if you need it.
+
+rpkic can be run either in an interactive mode or by passing a single
+command on the command line when starting the program; the former mode
+is intended to be somewhat human-friendly, the latter mode is useful
+in scripting, cron jobs, and automated testing.
+
+Some rpkic commands write out data files, usually in the current
+directory.
+
+rpkic uses the same system-wide [[Configuration|rpki.conf]] file as
+the other CA tools as its default configuration file.
+
+rpkic includes a "help" command which provides inline help for its
+several commands.
+
+== Selecting an identity ==
+
+The //handle// variable in rpki.conf specifies the handle of the
+default identity for an rpkic command, but this is just the default.
+rpkid can host an arbitrary number of identities, and rpkic has to be
+able to control all of them.
+
+When running rpkic interactively, use rpkic's "select_identity"
+command to set the current identity handle.
+
+When running rpkic with a single command on the command line, use the
+"-i" (or "--identity") option to set the current identity handle.
+
+== rpkic in setup phase ==
+
+See the [[..|introduction to the user interfaces]] for an overview of
+how setup phase works. The general structure of the setup phase in
+rpkic is as described there, but here we provide the specific commands
+involved. The following assumes that you have already installed the
+software and started the servers.
+
+* The rpkic "initialize" command writes out an "identity.xml" file in
+ addition to all of its other tasks.
+
+* A parent who is using rpkic runs the "configure_child" command to
+ configure the child, giving this command the identity.xml file the
+ child supplied as input. configure_child will write out a response
+ XML file, which the parent sends back to the child.
+
+* A child who is running rpkic runs the "configure_parent" command to
+ process the parent's response, giving it the XML file sent back by
+ the parent as input to this command. configure_parent will write
+ out a publication request XML file, which the child sents to the
+ repository operator.
+
+* A repository operator who is using rpkic runs the
+ "configure_publication_client" command to process a client's
+ publication request. configure_publication_client generates a
+ confirmation XML message which the repository operator sends back to
+ the client.
+
+* A publication client who is using rpkic runs the
+ "configure_repository" command to process the repository's response.
+
+== rpkic in data maintenance phase ==
+
+rpkic uses whitespace-delimited text files (called ".csv files", for
+historical reasons) to control issuance of addresses and autonomous
+sequence numbers to children, and to control issuance of ROAs. See
+the "load_asns", "load_prefixes", and "load_roa_requests" commands.
+
+== Maintaining child validity data ==
+
+All resources issued to child entities are tagged with a validity
+date. If not updated, these resources will eventually expire. rpkic
+includes two commands for updating these validity dates:
+
+* "renew_child" updates the validity date for a specific child.
+
+* "renew_all_children" updates the validity date for all children.
+
+== BPKI maintenance ==
+
+Certificates and CRLs in the BPKI have expiration dates and netUpdate
+dates, so they need to be maintained. Failure to maintain these will
+eventually cause the CA software to grind to a halt, as expired
+certificates will cause CMS validation failures.
+
+rpkic's "update_bpki" command takes care of this. Usually one will
+want to run this periodically (perhaps once per month), under cron.
+
+== Forcing synchronization ==
+
+Most rpkic commands synchronize the back end database with the daemons
+automatically, so in general it should not be necessary to synchronize
+manually. However, since these are separate databases, it is
+theoretically possible for them to get out of synch, perhaps because
+something crashed at exactly the wrong time.
+
+rpkic's "synchronize" command runs a synchronization cycle with rpkid
+(if {{{run_rpkic}}} is set) and pubd (if {{{run_pubd}}} is set).
diff --git a/doc/manual/28.RPKI.CA.UI.GUI.00.jpg b/doc/manual/28.RPKI.CA.UI.GUI.00.jpg
new file mode 100644
index 00000000..e912116f
--- /dev/null
+++ b/doc/manual/28.RPKI.CA.UI.GUI.00.jpg
Binary files differ
diff --git a/doc/manual/28.RPKI.CA.UI.GUI.01.jpg b/doc/manual/28.RPKI.CA.UI.GUI.01.jpg
new file mode 100644
index 00000000..8aad1db9
--- /dev/null
+++ b/doc/manual/28.RPKI.CA.UI.GUI.01.jpg
Binary files differ
diff --git a/doc/manual/28.RPKI.CA.UI.GUI.02.jpg b/doc/manual/28.RPKI.CA.UI.GUI.02.jpg
new file mode 100644
index 00000000..a6371ff2
--- /dev/null
+++ b/doc/manual/28.RPKI.CA.UI.GUI.02.jpg
Binary files differ
diff --git a/doc/manual/28.RPKI.CA.UI.GUI.03.jpg b/doc/manual/28.RPKI.CA.UI.GUI.03.jpg
new file mode 100644
index 00000000..e24fa354
--- /dev/null
+++ b/doc/manual/28.RPKI.CA.UI.GUI.03.jpg
Binary files differ
diff --git a/doc/manual/28.RPKI.CA.UI.GUI.04.jpg b/doc/manual/28.RPKI.CA.UI.GUI.04.jpg
new file mode 100644
index 00000000..675bc511
--- /dev/null
+++ b/doc/manual/28.RPKI.CA.UI.GUI.04.jpg
Binary files differ
diff --git a/doc/manual/28.RPKI.CA.UI.GUI.05.jpg b/doc/manual/28.RPKI.CA.UI.GUI.05.jpg
new file mode 100644
index 00000000..aea168b0
--- /dev/null
+++ b/doc/manual/28.RPKI.CA.UI.GUI.05.jpg
Binary files differ
diff --git a/doc/manual/28.RPKI.CA.UI.GUI.06.jpg b/doc/manual/28.RPKI.CA.UI.GUI.06.jpg
new file mode 100644
index 00000000..a55c1556
--- /dev/null
+++ b/doc/manual/28.RPKI.CA.UI.GUI.06.jpg
Binary files differ
diff --git a/doc/manual/28.RPKI.CA.UI.GUI.md b/doc/manual/28.RPKI.CA.UI.GUI.md
new file mode 100644
index 00000000..bca8e9b9
--- /dev/null
+++ b/doc/manual/28.RPKI.CA.UI.GUI.md
@@ -0,0 +1,52 @@
+# Installing and Configuring
+
+ * [GUI/Installing][1] for new installs
+ * [GUI/Upgrading][2] for upgrading from a previous install
+ * [GUI/Configuring][3]
+ * [GUI/UserModel][4] for instructions on managing users
+
+# Using the GUI
+
+# GUI Examples
+
+## Logging in to the GUI
+
+![][Login]
+
+## The Dashboard - Let's Make a ROA
+
+![][Dashboard]
+
+## ROA List Currently Empty, So Let's Create One
+
+![]ROAs]
+
+## Choose an AS and Prefix - Let MaxLen? Default
+
+![][Create-ROA]
+
+## What Will the Consequences Be? - Confirm OK
+
+![][Are-You-Sure]
+
+## Now We Can See ROAs - Let's Look at Routes
+
+![][ROA-List]
+
+## Real Effect on Routing Table
+
+![][Route-View]
+
+## Ghostbusters etc. are Similar
+
+[Installing]: 29.RPKI.CA.UI.GUI.Installing.md
+[Upgrading]: 30.RPKI.CA.UI.GUI.Upgrading.md
+[Configuring]: 32.RPKI.CA.UI.GUI.Configuring.md
+[UserModel]: 34.RPKI.CA.UI.GUI.UserModel.md
+[Login]: 28.RPKI.CA.UI.GUI.00.jpg
+[Dashboard]: 28.RPKI.CA.UI.GUI.01.jpg
+[ROAs]: 28.RPKI.CA.UI.GUI.02.jpg
+[Create-ROA]: 28.RPKI.CA.UI.GUI.03.jpg
+[Are-You-Sure]: 28.RPKI.CA.UI.GUI.04.jpg
+[ROA-List]: 28.RPKI.CA.UI.GUI.05.jpg
+[Route-View]: 28.RPKI.CA.UI.GUI.06.jpg
diff --git a/doc/manual/28.RPKI.CA.UI.GUI.wiki b/doc/manual/28.RPKI.CA.UI.GUI.wiki
new file mode 100644
index 00000000..57f9c688
--- /dev/null
+++ b/doc/manual/28.RPKI.CA.UI.GUI.wiki
@@ -0,0 +1,47 @@
+[[TracNav(doc/RPKI/TOC)]]
+
+[[PageOutline]]
+
+= Installing and Configuring =
+
+* [[wiki:GUI/Installing]] for new installs
+* [[wiki:GUI/Upgrading]] for upgrading from a previous install
+* [[wiki:GUI/Configuring]]
+* [[wiki:GUI/UserModel]] for instructions on managing users
+
+\\
+\\
+= Using the GUI =
+
+= GUI Examples =
+\\
+== Logging in to the GUI ==
+[[Image(htdocs:gui-pics/01-login.jpg)]]
+\\
+\\
+== The Dashboard - Let's Make a ROA ==
+[[Image(htdocs:gui-pics/02-dashboard.jpg)]]
+\\
+\\
+== ROA List Currently Empty, So Let's Create One ==
+[[Image(htdocs:gui-pics/03-roas.jpg)]]
+\\
+\\
+== Choose an AS and Prefix - Let MaxLen Default ==
+[[Image(htdocs:gui-pics/04-create-roa.jpg)]]
+\\
+\\
+== What Will the Consequences Be? - Confirm OK ==
+[[Image(htdocs:gui-pics/05-are-you-sure.jpg)]]
+\\
+\\
+== Now We Can See ROAs - Let's Look at Routes ==
+ [[Image(htdocs:gui-pics/06-roa-list.jpg)]]
+\\
+\\
+== Real Effect on Routing Table ==
+[[Image(htdocs:gui-pics/07-route view.jpg)]]
+\\
+\\
+== Ghostbusters etc. are Similar ==
+
diff --git a/doc/manual/29.RPKI.CA.UI.GUI.Installing.md b/doc/manual/29.RPKI.CA.UI.GUI.Installing.md
new file mode 100644
index 00000000..bb582b56
--- /dev/null
+++ b/doc/manual/29.RPKI.CA.UI.GUI.Installing.md
@@ -0,0 +1,41 @@
+# Installing the Web Portal for the First Time
+
+This page documents how to install the web portal software. **If you have
+previously installed the software**, see [doc/RPKI/CA/UI/GUI/Upgrading][1] for
+instructions.
+
+## Prerequisites
+
+This page assumes that you have already followed the steps to install the CA
+software (see [doc/RPKI/Installation][2])
+
+This page assumes that you have already created `/etc/rpki.conf` (see
+[doc/RPKI/CA/Configuration][3])
+
+## Create Database Tables
+
+This step creates the tables used by the web portal in the database. Run the
+following commands in the shell (you do not need to be _root_, just have
+permission to read `/etc/rpki.conf`):
+
+ rpki-manage syncdb --noinput
+ rpki-manage migrate
+
+Note that at the end of the `syncdb` output you will see the following
+message:
+
+ Not synced (use migrations):
+ - rpki.gui.app
+ (use ./manage.py migrate to migrate these)
+
+You should **ignore the message about running ./manage.py** since that script
+does not exist in our setup (we use `rpki-manage` instead`).
+
+## Next Step
+
+See [doc/RPKI/CA/UI/GUI/Configuring][4]
+
+[1]: 30.RPKI.CA.UI.GUI.Upgrading.md
+[2]: 01.RPKI.Installation.md
+[3]: 12.RPKI.CA.Configuration.md
+[4]: 32.RPKI.CA.UI.GUI.Configuring.md
diff --git a/doc/manual/29.RPKI.CA.UI.GUI.Installing.wiki b/doc/manual/29.RPKI.CA.UI.GUI.Installing.wiki
new file mode 100644
index 00000000..9a273d8f
--- /dev/null
+++ b/doc/manual/29.RPKI.CA.UI.GUI.Installing.wiki
@@ -0,0 +1,34 @@
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= Installing the Web Portal for the First Time =
+
+This page documents how to install the web portal software. '''If you have previously installed the software''', see [[wiki:doc/RPKI/CA/UI/GUI/Upgrading]] for instructions.
+
+== Prerequisites ==
+
+This page assumes that you have already followed the steps to install the CA software (see [[wiki:doc/RPKI/Installation]])
+
+This page assumes that you have already created `/etc/rpki.conf` (see [[wiki:doc/RPKI/CA/Configuration]])
+
+== Create Database Tables ==
+
+This step creates the tables used by the web portal in the database. Run the following commands in the shell (you do not need to be ''root'', just have permission to read `/etc/rpki.conf`):
+
+{{{#!sh
+rpki-manage syncdb --noinput
+rpki-manage migrate
+}}}
+
+Note that at the end of the `syncdb` output you will see the following message:
+{{{
+Not synced (use migrations):
+ - rpki.gui.app
+(use ./manage.py migrate to migrate these)
+}}}
+
+You should '''ignore the message about running ./manage.py''' since that script does not exist in our setup (we use `rpki-manage` instead`).
+
+== Next Step ==
+
+See [[wiki:doc/RPKI/CA/UI/GUI/Configuring]]
diff --git a/doc/manual/30.RPKI.CA.UI.GUI.Upgrading.md b/doc/manual/30.RPKI.CA.UI.GUI.Upgrading.md
new file mode 100644
index 00000000..0b5c5bb1
--- /dev/null
+++ b/doc/manual/30.RPKI.CA.UI.GUI.Upgrading.md
@@ -0,0 +1,40 @@
+# Upgrading from a Previous Version
+
+ * See [wiki:doc/RPKI/CA/UI/GUI/Upgrading/BeforeMigration][1] for the special situation where you are upgrading from a release **prior to database migration support being added**.
+
+This page describes the steps you must take if you upgrading from a previous
+version of the software that is already installed on the system. If you are
+installing for the first time see [doc/RPKI/CA/UI/GUI/Installing][2].
+
+Run the following commands at a shell prompt. Note that you do not need run
+these as the _root_ user, any user with permission to read `/etc/rpki.conf` is
+sufficient.
+
+ rpki-manage syncdb
+ rpki-manage migrate
+
+Note that at the end of the `syncdb` output you will see the following
+message:
+
+ Not synced (use migrations):
+ - rpki.gui.app
+ (use ./manage.py migrate to migrate these)
+
+You should **ignore the message about running ./manage.py** since that script
+does not exist in our setup (we use `rpki-manage` instead`).
+
+## Restart Apache
+
+In order to cause Apache to reload the web portal software using the newly
+installed software, it must be restarted. Execute the following command as
+_root_ in a shell:
+
+ apachectl restart
+
+## Next Step
+
+See [doc/RPKI/CA/UI/GUI/Configuring][3]
+
+[1]: 31.RPKI.CA.UI.GUI.Upgrading.BeforeMigration.md
+[2]: 29.RPKI.CA.UI.GUI.Installing.md
+[3]: 32.RPKI.CA.UI.GUI.Configuring.md
diff --git a/doc/manual/30.RPKI.CA.UI.GUI.Upgrading.wiki b/doc/manual/30.RPKI.CA.UI.GUI.Upgrading.wiki
new file mode 100644
index 00000000..644cbb16
--- /dev/null
+++ b/doc/manual/30.RPKI.CA.UI.GUI.Upgrading.wiki
@@ -0,0 +1,36 @@
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= Upgrading from a Previous Version =
+
+* See wiki:doc/RPKI/CA/UI/GUI/Upgrading/BeforeMigration for the special situation where you are upgrading from a release '''prior to database migration support being added'''.
+
+This page describes the steps you must take if you upgrading from a previous version of the software that is already installed on the system. If you are installing for the first time see [[wiki:doc/RPKI/CA/UI/GUI/Installing]].
+
+Run the following commands at a shell prompt. Note that you do not need run these as the ''root'' user, any user with permission to read `/etc/rpki.conf` is sufficient.
+
+{{{#!sh
+rpki-manage syncdb
+rpki-manage migrate
+}}}
+
+Note that at the end of the `syncdb` output you will see the following message:
+{{{
+Not synced (use migrations):
+ - rpki.gui.app
+(use ./manage.py migrate to migrate these)
+}}}
+
+You should '''ignore the message about running ./manage.py''' since that script does not exist in our setup (we use `rpki-manage` instead`).
+
+== Restart Apache ==
+
+In order to cause Apache to reload the web portal software using the newly installed software, it must be restarted. Execute the following command as ''root'' in a shell:
+
+{{{#!sh
+apachectl restart
+}}}
+
+== Next Step ==
+
+See [[wiki:doc/RPKI/CA/UI/GUI/Configuring]]
diff --git a/doc/manual/31.RPKI.CA.UI.GUI.Upgrading.BeforeMigration.md b/doc/manual/31.RPKI.CA.UI.GUI.Upgrading.BeforeMigration.md
new file mode 100644
index 00000000..a2df6f8f
--- /dev/null
+++ b/doc/manual/31.RPKI.CA.UI.GUI.Upgrading.BeforeMigration.md
@@ -0,0 +1,78 @@
+# Upgrading from a Previous Release without Migration Support
+
+This page documents the steps required to upgrade the web portal when you have
+a previous version of the software install **prior to migration support via
+Django South**. Note that this is a special case and will not apply to most
+situations (see [Upgrading][] for the normal upgrade
+path). If you have already performed the steps on this page previously, then
+it does not apply to your situation.
+
+If you are unsure whether or not you have previously run this command, you can
+verify with the following command:
+
+ $ rpki-manage migrate --list
+
+ app
+ (*) 0001_initial
+ (*) 0002_auto__add_field_resourcecert_conf
+ (*) 0003_set_conf_from_parent
+ (*) 0004_auto__chg_field_resourcecert_conf
+ (*) 0005_auto__chg_field_resourcecert_parent
+ ( ) 0006_add_conf_acl
+ ( ) 0007_default_acls
+
+The migrations are an ordered list. The presence of the asterisk `(*)`
+indicates that the migration has already been performed. `( )` indicates that
+the specific migration has not yet been applied. In the example above,
+migrations 0001 through 0005 have been applied, but 0006 and 0007 have not.
+
+## Sync databases
+
+Execute the following command in a shell. Note that you do not need to be the
+_root_ user, any user with permission to read `/etc/rpki.conf` is sufficient.
+
+ $ rpki-manage syncdb
+
+Note that at the end of the `syncdb` output you will see the following
+message:
+
+ Not synced (use migrations):
+ - rpki.gui.app
+ (use ./manage.py migrate to migrate these)
+
+You should **ignore the message about running ./manage.py** since that script
+does not exist in our setup.
+
+## Initial Database Migration
+
+For a completely new install, there will not be any existing tables in the
+database, and the `rpki-manage migrate` command will create them. However, in
+the special situation where you are upgrading from a previous release prior to
+the migration support being added, you will already have the tables created,
+which will case the initial migration to fail. In order to work around this
+problem, we have to tell the migration that the initial step has already been
+performed. This is accomplished via the use the `--fake` command line
+argument:
+
+ $ rpki-manage migrate app 0001 --fake
+
+Note that this step doesn't actually modify the database, other than to record
+that the migration has already taken place.
+
+## Database Migration
+
+Now bring your database up to date with the current release:
+
+ $ rpki-manage migrate
+
+From this point forward you will follow the steps in
+[Upgrading][] each time you upgrade.
+
+## Restart Apache
+
+In order to make Apache use the new version of the software, it must be
+restarted:
+
+ $ apachectl restart
+
+[Upgrading]: 30.RPKI.CA.UI.GUI.Upgrading.md
diff --git a/doc/manual/31.RPKI.CA.UI.GUI.Upgrading.BeforeMigration.wiki b/doc/manual/31.RPKI.CA.UI.GUI.Upgrading.BeforeMigration.wiki
new file mode 100644
index 00000000..d0098c05
--- /dev/null
+++ b/doc/manual/31.RPKI.CA.UI.GUI.Upgrading.BeforeMigration.wiki
@@ -0,0 +1,71 @@
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= Upgrading from a Previous Release without Migration Support =
+
+This page documents the steps required to upgrade the web portal when you have a previous version of the software install '''prior to migration support via Django South'''. Note that this is a special case and will not apply to most situations (see [[wiki:doc/RPKI/CA/UI/GUI/Upgrading]] for the normal upgrade path). If you have already performed the steps on this page previously, then it does not apply to your situation.
+
+If you are unsure whether or not you have previously run this command, you can verify with the following command:
+{{{#!sh
+$ rpki-manage migrate --list
+
+ app
+ (*) 0001_initial
+ (*) 0002_auto__add_field_resourcecert_conf
+ (*) 0003_set_conf_from_parent
+ (*) 0004_auto__chg_field_resourcecert_conf
+ (*) 0005_auto__chg_field_resourcecert_parent
+ ( ) 0006_add_conf_acl
+ ( ) 0007_default_acls
+}}}
+The migrations are an ordered list. The presence of the asterisk `(*)` indicates that the migration has
+already been performed. `( )` indicates that the specific migration
+has not yet been applied. In the example above, migrations 0001 through 0005 have been applied, but 0006 and 0007 have not.
+
+== Sync databases ==
+
+Execute the following command in a shell. Note that you do not need to be the ''root'' user, any user with permission to read `/etc/rpki.conf` is sufficient.
+{{{
+#!sh
+$ rpki-manage syncdb
+}}}
+
+Note that at the end of the `syncdb` output you will see the following message:
+{{{
+Not synced (use migrations):
+ - rpki.gui.app
+(use ./manage.py migrate to migrate these)
+}}}
+
+You should '''ignore the message about running ./manage.py''' since that script does not exist in our setup.
+
+== Initial Database Migration ==
+
+For a completely new install, there will not be any existing tables in the database, and the `rpki-manage migrate` command will create them. However, in the special situation where you are upgrading from a previous release prior to the migration support being added, you will already have the tables created, which will case the initial migration to fail. In order to work around this problem, we have to tell the migration that the initial step has already been performed. This is accomplished via the use the `--fake` command line argument:
+
+{{{
+#!sh
+$ rpki-manage migrate app 0001 --fake
+}}}
+
+Note that this step doesn't actually modify the database, other than to record that the migration has already taken place.
+
+== Database Migration ==
+
+Now bring your database up to date with the current release:
+
+{{{
+#!sh
+$ rpki-manage migrate
+}}}
+
+From this point forward you will follow the steps in [[wiki:doc/RPKI/CA/UI/GUI/Upgrading]] each time you upgrade.
+
+== Restart Apache ==
+
+In order to make Apache use the new version of the software, it must be restarted:
+
+{{{
+#!sh
+$ apachectl restart
+}}}
diff --git a/doc/manual/32.RPKI.CA.UI.GUI.Configuring.md b/doc/manual/32.RPKI.CA.UI.GUI.Configuring.md
new file mode 100644
index 00000000..3c1acf54
--- /dev/null
+++ b/doc/manual/32.RPKI.CA.UI.GUI.Configuring.md
@@ -0,0 +1,89 @@
+# Configuring the Web Portal
+
+Also see [doc/RPKI/CA/Configuration][1] for documentation on the
+`/etc/rpki.conf` configuration file.
+
+## Creating Users
+
+See [doc/RPKI/CA/UI/GUI/UserModel][2]
+
+## Configuring Apache
+
+In order to use the web portal, Apache must be installed and configured to
+serve the application. See [doc/RPKI/CA/UI/GUI/Configuring/Apache][3].
+
+## Error Notifications via Email
+
+If an exception is generated while the web portal is processing a request, by
+default will be logged to the apache log file, and an email will be set to
+`root@localhost`. If you wish to change where email is sent, you can edit
+`/etc/rpki/local_settings.py` and add the following lines:
+
+ ADMINS = (('YOUR NAME', 'YOUR EMAIL ADDRESS'),)
+
+For example,
+
+ ADMINS = (('Joe User', 'joe@example.com'),)
+
+## Cron Jobs
+
+The web portal makes use of some external data sources to display the
+validation status of routing entries. Therefore, it is necessary to run some
+background jobs periodically to refresh this data. The web portal software
+makes use of the `cron` facility present in POSIX operating systems to perform
+these tasks.
+
+### Importing Routing Table Snapshot
+
+In order for the web portal to display the validation status of routes covered
+by a resource holder's RPKI certificates, it needs a source of the currently
+announced global routing table. The web portal includes a script which can
+parse the output of the [RouteViews][4] [full snapshot][5] (**warning**: links
+to very large file!).
+
+When the software is installed, there will be a `/usr/local/sbin/rpkigui-
+import-routes` script that should be invoked periodically. Routeviews.org
+updates the snapshot every two hours, so it does not make sense to run it more
+frequently than two hours. How often to run it depends on how often the routes
+you are interested in are changing.
+
+Create an entry in root's crontab such as
+
+ 30 */2 * * * /usr/local/sbin/rpkigui-import-routes
+
+### Importing ROAs
+
+If you want the GUI's "routes" page to see ROAs when you click those buttons,
+you will need to run rcynic. see the [instructions for setting up rcynic][6].
+
+This data is imported by the `rcynic-cron` script. If you have not already set
+up that cron job, you should do so now. Note that by default, rcynic-cron is
+run once an hour. What this means is that the _routes_ view in the GUI will
+**not** immediately update as you create/destroy ROAs. You may wish to run
+`rcynic-cron` more frequently, or configure `rcynic.conf` to only include the
+TAL that is the root of your resources, and run the script more frequently
+(perhaps every 2-5 minutes).
+
+If you are running rootd, you may want to run with only your local trust
+anchor. In this case, to have the GUI be fairly responsive to changes, you may
+want to run the rcynic often. In this case, you may want to look at the value
+of **jitter** in rcynic.conf.
+
+### Expiration Checking
+
+The web portal can notify users when it detects that RPKI certificates will
+expire in the near future. Run the following script as a cron job, perhaps
+once a night:
+
+ /usr/local/sbin/rpkigui-check-expired
+
+By default it will warn of expiration 14 days in advance, but this may be
+changed by using the `-t` command line option and specifying how many days in
+advance to check.
+
+[1]: 12.RPKI.CA.Configuration.md
+[2]: 34.RPKI.CA.UI.GUI.UserModel.md
+[3]: 33.RPKI.CA.UI.GUI.Configuring.Apache.md
+[4]: http://www.routeviews.org
+[5]: http://archive.routeviews.org/oix-route-views/oix-full-snapshot-latest.dat.bz2
+[6]: 06.RPKI.RP.rcynic.md
diff --git a/doc/manual/32.RPKI.CA.UI.GUI.Configuring.wiki b/doc/manual/32.RPKI.CA.UI.GUI.Configuring.wiki
new file mode 100644
index 00000000..c2176d97
--- /dev/null
+++ b/doc/manual/32.RPKI.CA.UI.GUI.Configuring.wiki
@@ -0,0 +1,65 @@
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= Configuring the Web Portal =
+
+Also see [[wiki:doc/RPKI/CA/Configuration]] for documentation on the `/etc/rpki.conf` configuration file.
+
+== Creating Users ==
+
+See [[wiki:doc/RPKI/CA/UI/GUI/UserModel]]
+
+== Configuring Apache ==
+
+In order to use the web portal, Apache must be installed and configured to serve the application.
+See [[wiki:doc/RPKI/CA/UI/GUI/Configuring/Apache]].
+
+== Error Notifications via Email ==
+
+If an exception is generated while the web portal is processing a request, by default will be logged to the apache log file, and an email will be set to `root@localhost`. If you wish to change where email is sent, you can edit `/etc/rpki/local_settings.py` and add the following lines:
+{{{
+ADMINS = (('YOUR NAME', 'YOUR EMAIL ADDRESS'),)
+}}}
+For example,
+{{{
+ADMINS = (('Joe User', 'joe@example.com'),)
+}}}
+
+== Cron Jobs ==
+
+The web portal makes use of some external data sources to display the validation status of routing entries. Therefore, it is necessary to run some background jobs periodically to refresh this data. The web portal software makes use of the `cron` facility present in POSIX operating systems to perform these tasks.
+
+=== Importing Routing Table Snapshot ===
+
+In order for the web portal to display the validation status of routes covered by a resource holder's RPKI certificates, it needs a source of the currently announced global routing table. The web portal includes a script which can parse the output of the [http://www.routeviews.org RouteViews] [http://archive.routeviews.org/oix-route-views/oix-full-snapshot-latest.dat.bz2 full snapshot] ('''warning''': links to very large file!).
+
+When the software is installed, there will be a `/usr/local/sbin/rpkigui-import-routes` script that should be invoked periodically. Routeviews.org updates the snapshot every two hours, so it does not make sense to run it more frequently than two hours. How often to run it depends on how often the routes you are interested in are changing.
+
+Create an entry in root's crontab such as
+
+{{{
+30 */2 * * * /usr/local/sbin/rpkigui-import-routes
+}}}
+
+=== Importing ROAs ===
+
+If you want the GUI's "routes" page to see ROAs when you click those
+buttons, you will need to run rcynic. see the
+[[doc/RPKI/RP/rcynic|instructions for setting up rcynic]].
+
+This data is imported by the `rcynic-cron` script. If you have not already set up that cron job, you should do so now. Note that by default, rcynic-cron is run once an hour. What this means is that the ''routes'' view in the GUI will '''not''' immediately update as you create/destroy ROAs. You may wish to run `rcynic-cron` more frequently, or configure `rcynic.conf` to only include the TAL that is the root of your resources, and run the script more frequently (perhaps every 2-5 minutes).
+
+If you are running rootd, you may want to run with only your local trust
+anchor. In this case, to have the GUI be fairly responsive to changes,
+you may want to run the rcynic often. In this case, you may want to
+look at the value of '''jitter''' in rcynic.conf.
+
+=== Expiration Checking === #expire-check
+
+The web portal can notify users when it detects that RPKI certificates will expire in the near future. Run the following script as a cron job, perhaps once a night:
+{{{
+#!sh
+/usr/local/sbin/rpkigui-check-expired
+}}}
+
+By default it will warn of expiration 14 days in advance, but this may be changed by using the `-t` command line option and specifying how many days in advance to check. \ No newline at end of file
diff --git a/doc/manual/33.RPKI.CA.UI.GUI.Configuring.Apache.md b/doc/manual/33.RPKI.CA.UI.GUI.Configuring.Apache.md
new file mode 100644
index 00000000..9b81c974
--- /dev/null
+++ b/doc/manual/33.RPKI.CA.UI.GUI.Configuring.Apache.md
@@ -0,0 +1,85 @@
+# Apache Configuration
+
+This page documents how to configure Apache to server the web portal
+application.
+
+During the software install process, `/usr/local/etc/rpki/apache.conf` is
+created, which needs to be included from the apache configuration inside of a
+`VirtualHost` section.
+
+Note that the web portal application **requires TLS** to be enabled for the
+`VirtualHost` it is configured in, otherwise it will fail to operate.
+
+## Requirements
+
+ * Apache 2.2 or later
+ * mod_ssl
+ * mod_wsgi 3 or later
+
+## Debian &amp; Ubuntu
+
+First, you need to install `apache` and enable SSL. Run the following commands
+in a shell as **root**:
+
+ apt-get install apache2 libapache2-mod-wsgi
+ a2enmod ssl
+ a2ensite default-ssl
+
+Edit `/etc/apache2/sites-enabled/default-ssl` and place the following line
+inside the `<VirtualHost>` section:
+
+ Include /usr/local/etc/rpki/apache.conf
+
+Now restart `apache`:
+
+ service apache2 restart
+
+## FreeBSD
+
+Now configure apache, using `/usr/local/etc/rpki/apache.conf`, e.g.
+
+ $ cp apache.conf /usr/local/etc/apache22/Includes/rpki.conf
+
+Restart apache
+
+ $ apachectl restart
+
+## Running the web portal as a different user (optional)
+
+By default, the web portal is run in embedded mode in mod_wsgi, which means it
+runs inside the apache process. However, you can make the web portal run in
+daemon mode as a different user using mod_wsgi.
+
+ $ ./configure --enable-wsgi-daemon-mode[=user[:group]]
+
+Where `user` is the optional user to run the web portal as, and `group` is the
+optional group to run the web portal as. If `user` is not specified, it will
+run in a separate process but the same user as apache is configured to run.
+
+Note that when run in daemon mode, a unix domain socket will be created in the
+same directory as the apache log files. If the user you have specified to run
+the web portal as does not have permission to read a file in that directory,
+the web interface will return a **500 Internal Server Error** and you will see
+a **permission denied** error in your apache logs. The solution to this is to
+use the `WSGISocketPrefix` apache configuration directive to specify an
+alternative location, such as:
+
+ WSGISocketPrefix /var/run/wsgi
+
+Note that this directive **must not** be placed inside of the `VirtualHost`
+section. It **must** be located at the global scope.
+
+see <http://code.google.com/p/modwsgi/wiki/ConfigurationDirectives#WSGISocketP
+refix> for more information.
+
+## Verify the Web Portal is Working
+
+Navigate to <https://YOURHOST/rpki/> and you should see the login page for the
+web portal.
+
+Enter the superuser and password in login form (see [UserModel][] if
+you haven't yet created a superuser). If you've only done the above
+bootstrap, there will only be a single handle to manage, so the GUI
+will automatically bring you to the dashboard for that handle.
+
+[UserModel]: 34.RPKI.CA.UI.GUI.UserModel.md
diff --git a/doc/manual/33.RPKI.CA.UI.GUI.Configuring.Apache.wiki b/doc/manual/33.RPKI.CA.UI.GUI.Configuring.Apache.wiki
new file mode 100644
index 00000000..1e97dc57
--- /dev/null
+++ b/doc/manual/33.RPKI.CA.UI.GUI.Configuring.Apache.wiki
@@ -0,0 +1,79 @@
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= Apache Configuration =
+
+This page documents how to configure Apache to server the web portal application.
+
+During the software install process, `/usr/local/etc/rpki/apache.conf` is created, which needs to be included from the apache configuration inside of a `VirtualHost` section.
+
+Note that the web portal application '''requires TLS''' to be enabled for the `VirtualHost` it is configured in, otherwise it will fail to operate.
+
+== Requirements ==
+
+* Apache 2.2 or later
+* mod_ssl
+* mod_wsgi 3 or later
+
+== Debian & Ubuntu ==
+
+First, you need to install `apache` and enable SSL. Run the following commands in a shell as '''root''':
+
+{{{#!sh
+apt-get install apache2 libapache2-mod-wsgi
+a2enmod ssl
+a2ensite default-ssl
+}}}
+
+Edit `/etc/apache2/sites-enabled/default-ssl` and place the following line inside the `<VirtualHost>` section:
+{{{
+Include /usr/local/etc/rpki/apache.conf
+}}}
+
+Now restart `apache`:
+{{{#!sh
+service apache2 restart
+}}}
+
+== FreeBSD ==
+
+Now configure apache, using `/usr/local/etc/rpki/apache.conf`, e.g.
+
+{{{
+#!sh
+$ cp apache.conf /usr/local/etc/apache22/Includes/rpki.conf
+}}}
+
+Restart apache
+{{{
+#!sh
+$ apachectl restart
+}}}
+
+== Running the web portal as a different user (optional) ==
+
+By default, the web portal is run in embedded mode in mod_wsgi, which means it runs inside the apache process. However, you can make the web portal run in daemon mode as a different user using mod_wsgi.
+
+{{{
+#!sh
+$ ./configure --enable-wsgi-daemon-mode[=user[:group]]
+}}}
+
+Where `user` is the optional user to run the web portal as, and `group` is the optional group to run the web portal as. If `user` is not specified, it will run in a separate process but the same user as apache is configured to run.
+
+Note that when run in daemon mode, a unix domain socket will be created in the same directory as the apache log files. If the user you have specified to run the web portal as does not have permission to read a file in that directory, the web interface will return a **500 Internal Server Error** and you will see a **permission denied** error in your apache logs. The solution to this is to use the `WSGISocketPrefix` apache configuration directive to specify an alternative location, such as:
+{{{
+WSGISocketPrefix /var/run/wsgi
+}}}
+
+Note that this directive **must not** be placed inside of the `VirtualHost` section. It **must** be located at the global scope.
+
+see http://code.google.com/p/modwsgi/wiki/ConfigurationDirectives#WSGISocketPrefix for more information.
+
+== Verify the Web Portal is Working ==
+
+Navigate to https://YOURHOST/rpki/ and you should see the login page for the web portal.
+
+Enter the superuser and password in login form (see [[wiki:doc/RPKI/CA/UI/GUI/UserModel]] if you haven't yet created a superuser). If you've only done the above bootstrap, there will only be a single
+handle to manage, so the GUI will automatically bring you to the
+dashboard for that handle. \ No newline at end of file
diff --git a/doc/manual/34.RPKI.CA.UI.GUI.UserModel.md b/doc/manual/34.RPKI.CA.UI.GUI.UserModel.md
new file mode 100644
index 00000000..62e859ff
--- /dev/null
+++ b/doc/manual/34.RPKI.CA.UI.GUI.UserModel.md
@@ -0,0 +1,130 @@
+# RPKI Web Portal User Model
+
+## Roles
+
+The web portal uses a model where users are distinct from resource holders.
+
+### Users
+
+A user is an entity that is granted permission to utilize the web portal. Each
+user account has an associated password that is used to log in to the web
+portal.
+
+The web portal maintains an access control list that specifies which resource
+holders the user is allowed to manage. If a user is authorized to manage more
+than a single resource holder, the user will be presented with a list of the
+resource holders upon login.
+
+Database tables: `irdbd.auth_user` and `irdbd.app_confacl`
+
+#### Changing User Passwords
+
+The password for a user may be changed via the web portal, or on the command
+line:
+
+ $ rpki-manage changepassword <USER>
+
+#### Superuser
+
+A user account with the superuser bit set has the special capability that it
+may assume the role of any resource holder managed by the local RPKI service.
+Superusers are created via the command line interface:
+
+ $ rpki-manage createsuperuser
+
+#### Creating user accounts
+
+When logged into the web portal with a #superuser account, select the **web
+users** link in the sidebar, and then click on the **create** button at the
+bottom of the page. You may optionally select one or more resource holders
+that this user is granted authorization to manage.
+
+Note that creating a user does **not** create a matching #resource-holder. See
+creating resource holders.
+
+#### Destroying user accounts
+
+When logged into the web portal with a #superuser account, select the **web
+users** link in the sidebar, and then click on the **Delete** icon next to the
+user you wish to delete.
+
+Note that this action does **not** remove any of the resource holders the user
+is granted authorization to manage.
+
+### Resource Holders
+
+Resource holders are entities that have authority to manage a set of Internet
+number resources. When a user logs into the web portal, they select which
+resource holder role to assume. The user may choose to assume the role of a
+different resource holder by clicking on the **select identity** link in the
+sidebar.
+
+The list of resource holders managed by the local RPKI service can be viewed
+with a #superuser account by clicking on the **resource holders** link in the
+sidebar of the web portal. From this page the super can manage the resource
+holders.
+
+Database table: `irdbd.irdb_resourceholderca` (via `irdbd.app_conf` proxy
+model)
+
+#### Creating resource holders
+
+Note that creating a new resource holder does **not** create a user account.
+See #create-user.
+
+##### GUI
+
+When logged into the web portal with a #superuser account, select the
+**resource holders** link in the sidebar, and then click on the **create**
+button at the bottom of the page.
+
+If the new resource holder is going to be a child of another resource holder
+hosted by the local RPKI service, you may optionally select the parent
+resource holder from the dropdown box, and the parent-child relationship will
+automatically be established when the new resource holder is created.
+
+Additionally, one or more #users authorized to manage the new resource holder
+may be selected from the **Users** list on the creation form.
+
+##### Command Line
+
+You can also create resource holders on the command line:
+
+ $ rpkic -i <HANDLE> initialize
+ $ rpkic synchronize
+
+where **HANDLE** is the name of new resource holder. Note that this new
+resource holder will initially only be allowed to be managed by #superuser
+accounts. You may wish to create a matching user account, but the name of the
+user need not be the same as the handle of the resource holder. Additionally,
+you can manage the list of users allowed to manage this resource holder via
+the web portal; click on the **Edit** icon next to the resource holder, and
+select the users you wish to grant permission to manage.
+
+#### Destroying resource holders
+
+Note that deleting a resource holder does **not** remove any user accounts.
+
+##### GUI
+
+When logged into the web portal with a #superuser account, select the
+**resource holders** link in the sidebar, and then click on the **delete**
+button next to the resource holder you wish to delete.
+
+##### Command Line
+
+Or you may use the command line interface:
+
+ $ rpkic -i <HANDLE> delete_self
+ $ rpkic synchronize
+
+where _HANDLE_ is the name of the resource holder you wish to destroy.
+
+#### Modifying the User ACL
+
+Each resource holder may be managed by one or more user accounts. The list of
+users authorized to assume the role of a particular resource holder may be
+changed in the web portal. When logged into the web portal with a #superuser
+account, select the **resource holders** link in the sidebar, and then click
+on the **Edit** icon next to the resource holder, and select the users you
+wish to grant permission to manage.
diff --git a/doc/manual/34.RPKI.CA.UI.GUI.UserModel.wiki b/doc/manual/34.RPKI.CA.UI.GUI.UserModel.wiki
new file mode 100644
index 00000000..bc7201f2
--- /dev/null
+++ b/doc/manual/34.RPKI.CA.UI.GUI.UserModel.wiki
@@ -0,0 +1,93 @@
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+= RPKI Web Portal User Model =
+
+== Roles ==
+
+The web portal uses a model where users are distinct from resource holders.
+
+=== Users ===
+
+A user is an entity that is granted permission to utilize the web portal. Each user account has an associated password that is used to log in to the web portal.
+
+The web portal maintains an access control list that specifies which [#resource-holder resource holders] the user is allowed to manage. If a user is authorized to manage more than a single resource holder, the user will be presented with a list of the resource holders upon login.
+
+Database tables: `irdbd.auth_user` and `irdbd.app_confacl`
+
+==== Changing User Passwords ====
+
+The password for a user may be changed via the web portal, or on the command line:
+{{{#!sh
+$ rpki-manage changepassword <USER>
+}}}
+
+==== Superuser ====
+
+A user account with the superuser bit set has the special capability that it may assume the role of any resource holder managed by the local RPKI service. Superusers are created via the command line interface:
+
+{{{#!sh
+$ rpki-manage createsuperuser
+}}}
+
+==== Creating user accounts ==== #create-user
+
+When logged into the web portal with a [#superuser] account, select the '''web users''' link in the sidebar, and then click on the '''create''' button at the bottom of the page. You may optionally select one or more [#resource-holder resource holders] that this user is granted authorization to manage.
+
+Note that creating a user does '''not''' create a matching [#resource-holder]. See [#create-holder creating resource holders].
+
+==== Destroying user accounts ====
+
+When logged into the web portal with a [#superuser] account, select the '''web users''' link in the sidebar, and then click on the '''Delete''' icon next to the user you wish to delete.
+
+Note that this action does '''not''' remove any of the [#resource-holder resource holders] the user is granted authorization to manage.
+
+
+=== Resource Holders === #resource-holder
+
+Resource holders are entities that have authority to manage a set of Internet number resources. When a [#users user] logs into the web portal, they select which resource holder role to assume. The user may choose to assume the role of a different resource holder by clicking on the '''select identity''' link in the sidebar.
+
+The list of resource holders managed by the local RPKI service can be viewed with a [#superuser] account by clicking on the **resource holders** link in the sidebar of the web portal. From this page the super can manage the resource holders.
+
+Database table: `irdbd.irdb_resourceholderca` (via `irdbd.app_conf` proxy model)
+
+==== Creating resource holders ==== #create-holder
+
+Note that creating a new resource holder does '''not''' create a [#users user] account. See [#create-user].
+
+===== GUI =====
+When logged into the web portal with a [#superuser] account, select the '''resource holders''' link in the sidebar, and then click on the '''create''' button at the bottom of the page.
+
+If the new resource holder is going to be a child of another resource holder hosted by the local RPKI service, you may optionally select the parent resource holder from the dropdown box, and the parent-child relationship will automatically be established when the new resource holder is created.
+
+Additionally, one or more [#users] authorized to manage the new resource holder may be selected from the '''Users''' list on the creation form.
+
+===== Command Line =====
+
+You can also create resource holders on the command line:
+{{{#!sh
+$ rpkic -i <HANDLE> initialize
+$ rpkic synchronize
+}}}
+where '''HANDLE''' is the name of new resource holder. Note that this new resource holder will initially only be allowed to be managed by [#superuser] accounts. You may wish to [#create-user create a matching user account], but the name of the user need not be the same as the handle of the resource holder. Additionally, you can manage the list of users allowed to manage this resource holder via the web portal; click on the '''Edit''' icon next to the resource holder, and select the users you wish to grant permission to manage.
+
+==== Destroying resource holders ====
+
+Note that deleting a resource holder does '''not''' remove any [#users user] accounts.
+
+===== GUI =====
+
+When logged into the web portal with a [#superuser] account, select the '''resource holders''' link in the sidebar, and then click on the '''delete''' button next to the resource holder you wish to delete.
+
+===== Command Line =====
+
+Or you may use the command line interface:
+{{{#!sh
+$ rpkic -i <HANDLE> delete_self
+$ rpkic synchronize
+}}}
+where ''HANDLE'' is the name of the resource holder you wish to destroy.
+
+==== Modifying the User ACL ==== #acls
+
+Each [#resourceholders resource holder] may be managed by one or more [#users user] accounts. The list of users authorized to assume the role of a particular resource holder may be changed in the web portal. When logged into the web portal with a [#superuser] account, select the '''resource holders''' link in the sidebar, and then click on the '''Edit''' icon next to the resource holder, and select the users you wish to grant permission to manage. \ No newline at end of file
diff --git a/doc/manual/35.RPKI.CA.Protocols.LeftRight.md b/doc/manual/35.RPKI.CA.Protocols.LeftRight.md
new file mode 100644
index 00000000..6aeb1189
--- /dev/null
+++ b/doc/manual/35.RPKI.CA.Protocols.LeftRight.md
@@ -0,0 +1,486 @@
+# The Left-Right Protocol
+
+The left-right protocol is really two separate client/server protocols over
+separate channels between the RPKI engine and the IR back end (IRBE). The IRBE
+is the client for one of the subprotocols, the RPKI engine is the client for
+the other.
+
+## Operations initiated by the IRBE
+
+This part of the protcol uses a kind of message-passing. Each object that the
+RPKI engine knows about takes five messages: "create", "set", "get", "list",
+and "destroy". Actions which are not just data operations on objects are
+handled via an SNMP-like mechanism, as if they were fields to be set. For
+example, to generate a keypair one "sets" the "generate-keypair" field of a
+BSC object, even though there is no such field in the object itself as stored
+in SQL. This is a bit of a kludge, but the reason for doing it as if these
+were variables being set is to allow composite operations such as creating a
+BSC, populating all of its data fields, and generating a keypair, all as a
+single operation. With this model, that's trivial, otherwise it's at least two
+round trips.
+
+Fields can be set in either "create" or "set" operations, the difference just
+being whether the object already exists. A "get" operation returns all visible
+fields of the object. A "list" operation returns a list containing what "get"
+would have returned on each of those objects.
+
+Left-right protocol objects are encoded as signed CMS messages containing XML
+as eContent and using an eContentType OID of `id-ct-xml`
+(1.2.840.113549.1.9.16.1.28). These CMS messages are in turn passed as the
+data for HTTP POST operations, with an HTTP content type of
+"application/x-rpki" for both the POST data and the response data.
+
+All operations allow an optional "tag" attribute which can be any alphanumeric
+token. The main purpose of the tag attribute is to allow batching of multiple
+requests into a single PDU.
+
+### self_obj &lt;self/&gt; object
+
+A `<self/>` object represents one virtual RPKI engine. In simple cases where
+the RPKI engine operator operates the engine only on their own behalf, there
+will only be one `<self/>` object, representing the engine operator's
+organization, but in environments where the engine operator hosts other
+entities, there will be one `<self/>` object per hosted entity (probably
+including the engine operator's own organization, considered as a hosted
+customer of itself).
+
+Some of the RPKI engine's configured parameters and data are shared by all
+hosted entities, but most are tied to a specific `<self/>` object. Data which
+are shared by all hosted entities are referred to as "per-engine" data, data
+which are specific to a particular `<self/>` object are "per-self" data.
+
+Since all other RPKI engine objects refer to a `<self/>` object via a
+"self_handle" value, one must create a `<self/>` object before one can
+usefully configure any other left-right protocol objects.
+
+Every `<self/>` object has a self_handle attribute, which must be specified
+for the "create", "set", "get", and "destroy" actions.
+
+Payload data which can be configured in a `<self/>` object:
+
+use_hsm:: (attribute)
+
+> Whether to use a Hardware Signing Module. At present this option has no
+effect, as the implementation does not yet support HSMs.
+
+crl_interval:: (attribute)
+
+> Positive integer representing the planned lifetime of an RPKI CRL for this
+`<self/>`, measured in seconds.
+
+regen_margin:: (attribute)
+
+> Positive integer representing how long before expiration of an RPKI
+certificiate a new one should be generated, measured in seconds. At present
+this only affects the one-off EE certificates associated with ROAs. This
+parameter also controls how long before the nextUpdate time of CRL or manifest
+the CRL or manifest should be updated.
+
+bpki_cert:: (element)
+
+> BPKI CA certificate for this `<self/>`. This is used as part of the
+certificate chain when validating incoming TLS and CMS messages, and should be
+the issuer of cross-certification BPKI certificates used in `<repository/>`,
+`<parent/>`, and `<child/>` objects. If the bpki_glue certificate is in use
+(below), the bpki_cert certificate should be issued by the bpki_glue
+certificate; otherwise, the bpki_cert certificate should be issued by the per-
+engine bpki_ta certificate.
+
+bpki_glue:: (element)
+
+> Another BPKI CA certificate for this `<self/>`, usually not needed. Certain
+pathological cross-certification cases require a two-certificate chain due to
+issuer name conflicts. If used, the bpki_glue certificate should be the issuer
+of the bpki_cert certificate and should be issued by the per-engine bpki_ta
+certificate; if not needed, the bpki_glue certificate should be left unset.
+
+Control attributes that can be set to "yes" to force actions:
+
+rekey::
+
+> Start a key rollover for every RPKI CA associated with every `<parent/>`
+object associated with this `<self/>` object. This is the first phase of a key
+rollover operation.
+
+revoke::
+
+> Revoke any remaining certificates for any expired key associated with any
+RPKI CA for any `<parent/>` object associated with this `<self/>` object. This
+is the second (cleanup) phase for a key rollover operation; it's separate from
+the first phase to leave time for new RPKI certificates to propegate and be
+installed.
+
+reissue::
+
+> Not implemented, may be removed from protocol. Original theory was that this
+operation would force reissuance of any object with a changed key, but as that
+happens automatically as part of the key rollover mechanism this operation
+seems unnecessary.
+
+run_now::
+
+> Force immediate processing for all tasks associated with this `<self/>`
+object that would ordinarily be performed under cron. Not currently
+implemented.
+
+publish_world_now::
+
+> Force (re)publication of every publishable object for this `<self/>` object.
+Not currently implemented. Intended to aid in recovery if RPKI engine and
+publication engine somehow get out of sync.
+
+### &lt;bsc/&gt; object
+
+The `<bsc/>` ("business signing context") object represents all the BPKI data
+needed to sign outgoing CMS messages. Various other objects include pointers
+to a `<bsc/>` object. Whether a particular `<self/>` uses only one `<bsc/>` or
+multiple is a configuration decision based on external requirements: the RPKI
+engine code doesn't care, it just cares that, for any object representing a
+relationship for which it must sign messages, there be a `<bsc/>` object that
+it can use to produce that signature.
+
+Every `<bsc/>` object has a bsc_handle, which must be specified for the
+"create", "get", "set", and "destroy" actions. Every `<bsc/>` also has a
+self_handle attribute which indicates the `<self/>` object with which this
+`<bsc/>` object is associated.
+
+Payload data which can be configured in a `<isc/>` object:
+
+signing_cert:: (element)
+
+> BPKI certificate to use when generating a signature.
+
+signing_cert_crl:: (element)
+
+> CRL which would list signing_cert if it had been revoked.
+
+Control attributes that can be set to "yes" to force actions:
+
+generate_keypair::
+
+> Generate a new BPKI keypair and return a `PKCS #10` certificate request. The
+resulting certificate, once issued, should be configured as this `<bsc/>`
+object's signing_cert.
+
+Additional attributes which may be specified when specifying
+"generate_keypair":
+
+key_type::
+
+> Type of BPKI keypair to generate. "rsa" is both the default and, at the
+moment, the only allowed value.
+
+hash_alg::
+
+> Cryptographic hash algorithm to use with this keypair. "sha256" is both the
+default and, at the moment, the only allowed value.
+
+key_length::
+
+> Length in bits of the keypair to be generated. "2048" is both the default
+and, at the moment, the only allowed value.
+
+Replies to "create" and "set" actions that specify "generate-keypair" include
+a &lt;bsc_pkcs10/&gt; element, as do replies to "get" and "list" actions for a
+`<bsc/>` object for which a "generate-keypair" command has been issued. The
+RPKI engine stores the `PKCS #10` request, which allows the IRBE to reuse the
+request if and when it needs to reissue the corresponding BPKI signing
+certificate.
+
+### &lt;parent/&gt; object
+
+The `<parent/>` object represents the RPKI engine's view of a particular
+parent of the current `<self/>` object in the up-down protocol. Due to the way
+that the resource hierarchy works, a given `<self/>` may obtain resources from
+multiple parents, but it will always have at least one; in the case of IANA or
+an RIR, the parent RPKI engine may be a trivial stub.
+
+Every `<parent/>` object has a parent_handle, which must be specified for the
+"create", "get", "set", and "destroy" actions. Every `<parent/>` also has a
+self_handle attribute which indicates the `<self/>` object with which this
+`<parent/>` object is associated, a bsc_handle attribute indicating the
+`<bsc/>` object to be used when signing messages sent to this parent, and a
+repository_handle indicating the `<repository/>` object to be used when
+publishing issued by the certificate issued by this parent.
+
+Payload data which can be configured in a `<parent/>` object:
+
+peer_contact_uri:: (attribute)
+
+> HTTP URI used to contact this parent.
+
+sia_base:: (attribute)
+
+> The leading portion of an rsync URI that the RPKI engine should use when
+composing the publication URI for objects issued by the RPKI certificate
+issued by this parent.
+
+sender_name:: (attribute)
+
+> Sender name to use in the up-down protocol when talking to this parent. The
+RPKI engine doesn't really care what this value is, but other implementations
+of the up-down protocol do care.
+
+recipient_name:: (attribute)
+
+> Recipient name to use in the up-down protocol when talking to this parent.
+The RPKI engine doesn't really care what this value is, but other
+implementations of the up-down protocol do care.
+
+bpki_cms_cert:: (element)
+
+> BPKI CMS CA certificate for this `<parent/>`. This is used as part of the
+certificate chain when validating incoming CMS messages If the bpki_cms_glue
+certificate is in use (below), the bpki_cms_cert certificate should be issued
+by the bpki_cms_glue certificate; otherwise, the bpki_cms_cert certificate
+should be issued by the bpki_cert certificate in the `<self/>` object.
+
+bpki_cms_glue:: (element)
+
+> Another BPKI CMS CA certificate for this `<parent/>`, usually not needed.
+Certain pathological cross-certification cases require a two-certificate chain
+due to issuer name conflicts. If used, the bpki_cms_glue certificate should be
+the issuer of the bpki_cms_cert certificate and should be issued by the
+bpki_cert certificate in the `<self/>` object; if not needed, the
+bpki_cms_glue certificate should be left unset.
+
+Control attributes that can be set to "yes" to force actions:
+
+rekey::
+
+> This is like the rekey command in the `<self/>` object, but limited to RPKI
+CAs under this parent.
+
+reissue::
+
+> This is like the reissue command in the `<self/>` object, but limited to
+RPKI CAs under this parent.
+
+revoke::
+
+> This is like the revoke command in the `<self/>` object, but limited to RPKI
+CAs under this parent.
+
+### &lt;child/&gt; object
+
+The `<child/>` object represents the RPKI engine's view of particular child of
+the current `<self/>` in the up-down protocol.
+
+Every `<child/>` object has a child_handle, which must be specified for the
+"create", "get", "set", and "destroy" actions. Every `<child/>` also has a
+self_handle attribute which indicates the `<self/>` object with which this
+`<child/>` object is associated.
+
+Payload data which can be configured in a `<child/>` object:
+
+bpki_cert:: (element)
+
+> BPKI CA certificate for this `<child/>`. This is used as part of the
+certificate chain when validating incoming TLS and CMS messages. If the
+bpki_glue certificate is in use (below), the bpki_cert certificate should be
+issued by the bpki_glue certificate; otherwise, the bpki_cert certificate
+should be issued by the bpki_cert certificate in the `<self/>` object.
+
+bpki_glue:: (element)
+
+> Another BPKI CA certificate for this `<child/>`, usually not needed. Certain
+pathological cross-certification cases require a two-certificate chain due to
+issuer name conflicts. If used, the bpki_glue certificate should be the issuer
+of the bpki_cert certificate and should be issued by the bpki_cert certificate
+in the `<self/>` object; if not needed, the bpki_glue certificate should be
+left unset.
+
+Control attributes that can be set to "yes" to force actions:
+
+reissue::
+
+> Not implemented, may be removed from protocol.
+
+### &lt;repository/&gt; object
+
+The `<repository/>` object represents the RPKI engine's view of a particular
+publication repository used by the current `<self/>` object.
+
+Every `<repository/>` object has a repository_handle, which must be specified
+for the "create", "get", "set", and "destroy" actions. Every `<repository/>`
+also has a self_handle attribute which indicates the `<self/>` object with
+which this `<repository/>` object is associated.
+
+Payload data which can be configured in a `<repository/>` object:
+
+peer_contact_uri:: (attribute)
+
+> HTTP URI used to contact this repository.
+
+bpki_cms_cert:: (element)
+
+> BPKI CMS CA certificate for this `<repository/>`. This is used as part of
+the certificate chain when validating incoming CMS messages If the
+bpki_cms_glue certificate is in use (below), the bpki_cms_cert certificate
+should be issued by the bpki_cms_glue certificate; otherwise, the
+bpki_cms_cert certificate should be issued by the bpki_cert certificate in the
+`<self/>` object.
+
+bpki_cms_glue:: (element)
+
+> Another BPKI CMS CA certificate for this `<repository/>`, usually not
+needed. Certain pathological cross-certification cases require a two-
+certificate chain due to issuer name conflicts. If used, the bpki_cms_glue
+certificate should be the issuer of the bpki_cms_cert certificate and should
+be issued by the bpki_cert certificate in the `<self/>` object; if not needed,
+the bpki_cms_glue certificate should be left unset.
+
+At present there are no control attributes for `<repository/>` objects.
+
+### &lt;route_origin/&gt; object
+
+This section is out-of-date. The `<route_origin/>` object has been replaced by
+the `<list_roa_requests/>` IRDB query, but the documentation for that hasn't
+been written yet.
+
+The `<route_origin/>` object is a kind of prototype for a ROA. It contains all
+the information needed to generate a ROA once the RPKI engine obtains the
+appropriate RPKI certificates from its parent(s).
+
+Note that a `<route_origin/>` object represents a ROA to be generated on
+behalf of `<self/>`, not on behalf of a `<child/>`. Thus, a hosted entity that
+has no children but which does need to generate ROAs would be represented by a
+hosted `<self/>` with no `<child/>` objects but one or more `<route_origin/>`
+objects. While lumping ROA generation in with the other RPKI engine activities
+may seem a little odd at first, it's a natural consequence of the design
+requirement that the RPKI daemon never transmit private keys across the
+network in any form; given this requirement, the RPKI engine that holds the
+private keys for an RPKI certificate must also be the engine which generates
+any ROAs that derive from that RPKI certificate.
+
+The precise content of the `<route_origin/>` has changed over time as the
+underlying ROA specification has changed. The current implementation as of
+this writing matches what we expect to see in draft-ietf-sidr-roa-format-03,
+once it is issued. In particular, note that the exactMatch boolean from the
+-02 draft has been replaced by the prefix and maxLength encoding used in the
+-03 draft.
+
+Payload data which can be configured in a `<route_origin/>` object:
+
+asn:: (attribute)
+
+> Autonomous System Number (ASN) to place in the generated ROA. A single ROA
+can only grant authorization to a single ASN; multiple ASNs require multiple
+ROAs, thus multiple `<route_origin/>` objects.
+
+ipv4:: (attribute)
+
+> List of IPv4 prefix and maxLength values, see below for format.
+
+ipv6:: (attribute)
+
+> List of IPv6 prefix and maxLength values, see below for format.
+
+Control attributes that can be set to "yes" to force actions:
+
+suppress_publication::
+
+> Not implemented, may be removed from protocol.
+
+The lists of IPv4 and IPv6 prefix and maxLength values are represented as
+comma-separated text strings, with no whitespace permitted. Each entry in such
+a string represents a single prefix/maxLength pair.
+
+ABNF for these address lists:
+
+ <ROAIPAddress> ::= <address> "/" <prefixlen> [ "-" <max_prefixlen> ]
+ ; Where <max_prefixlen> defaults to the same
+ ; value as <prefixlen>.
+
+ <ROAIPAddressList> ::= <ROAIPAddress> *( "," <ROAIPAddress> )
+
+For example, `10.0.1.0/24-32,10.0.2.0/24`, which is a shorthand form of
+`10.0.1.0/24-32,10.0.2.0/24-24`.
+
+## Operations initiated by the RPKI engine
+
+The left-right protocol also includes queries from the RPKI engine back to the
+IRDB. These queries do not follow the message-passing pattern used in the
+IRBE-initiated part of the protocol. Instead, there's a single query back to
+the IRDB, with a corresponding response. The CMS encoding are the same as in
+the rest of the protocol, but the BPKI certificates will be different as the
+back-queries and responses form a separate communication channel.
+
+### &lt;list_resources/&gt; messages
+
+The `<list_resources/>` query and response allow the RPKI engine to ask the
+IRDB for information about resources assigned to a particular child. The query
+must include both a `self_handle` attribute naming the `<self/>` that is
+making the request and also a `child_handle` attribute naming the child that
+is the subject of the query. The query and response also allow an optional
+_tag_ attribute of the same form used elsewhere in this protocol, to allow
+batching.
+
+A `<list_resources/>` response includes the following attributes, along with
+the tag (if specified), `self_handle`, and `child_handle` copied from the
+request:
+
+valid_until::
+
+> A timestamp indicating the date and time at which certificates generated by
+the RPKI engine for these data should expire. The timestamp is expressed as an
+XML `xsd:dateTime`, must be expressed in UTC, and must carry the "Z" suffix
+indicating UTC.
+
+asn::
+
+> A list of autonomous sequence numbers, expressed as a comma-separated
+sequence of decimal integers with no whitespace.
+
+ipv4::
+
+> A list of IPv4 address prefixes and ranges, expressed as a comma-separated
+list of prefixes and ranges with no whitespace. See below for format details.
+
+ipv6::
+
+> A list of IPv6 address prefixes and ranges, expressed as a comma-separated
+list of prefixes and ranges with no whitespace. See below for format details.
+
+Entries in a list of address prefixes and ranges can be either prefixes, which
+are written in the usual address/prefixlen notation, or ranges, which are
+expressed as a pair of addresses denoting the beginning and end of the range,
+written in ascending order separated by a single "-" character. This format is
+superficially similar to the format used for prefix and maxLength values in
+the `<route_origin/>` object, but the semantics differ: note in particular
+that `<route_origin/>` objects don't allow ranges, while `<list_resources/>`
+messages don't allow a maxLength specification.
+
+## Error handling
+
+Error in this protocol are handled at two levels.
+
+Since all messages in this protocol are conveyed over HTTP connections, basic
+errors are indicated via the HTTP response code. 4xx and 5xx responses
+indicate that something bad happened. Errors that make it impossible to decode
+a query or encode a response are handled in this way.
+
+Where possible, errors will result in a `<report_error/>` message which takes
+the place of the expected protocol response message. `<report_error/>`
+messages are CMS-signed XML messages like the rest of this protocol, and thus
+can be archived to provide an audit trail.
+
+`<report_error/>` messages only appear in replies, never in queries. The
+`<report_error/>` message can appear on either the "forward" (IRBE as client
+of RPKI engine) or "back" (RPKI engine as client of IRDB) communication
+channel.
+
+The `<report_error/>` message includes an optional _tag_ attribute to assist
+in matching the error with a particular query when using batching, and also
+includes a `self_handle` attribute indicating the `<self/>` that issued the
+error.
+
+The error itself is conveyed in the `error_code` (attribute). The value of
+this attribute is a token indicating the specific error that occurred. At
+present this will be the name of a Python exception; the production version of
+this protocol will nail down the allowed error tokens here, probably in the
+RelaxNG schema.
+
+The body of the `<report_error/>` element itself is an optional text string;
+if present, this is debugging information. At present this capabilty is not
+used, debugging information goes to syslog.
diff --git a/doc/manual/35.RPKI.CA.Protocols.LeftRight.wiki b/doc/manual/35.RPKI.CA.Protocols.LeftRight.wiki
new file mode 100644
index 00000000..0859c463
--- /dev/null
+++ b/doc/manual/35.RPKI.CA.Protocols.LeftRight.wiki
@@ -0,0 +1,473 @@
+= The Left-Right Protocol =
+
+[[TracNav(doc/RPKI/TOC)]]
+[[PageOutline]]
+
+The left-right protocol is really two separate client/server
+protocols over separate channels between the RPKI engine and the IR
+back end (IRBE). The IRBE is the client for one of the
+subprotocols, the RPKI engine is the client for the other.
+
+== Operations initiated by the IRBE ==
+
+This part of the protcol uses a kind of message-passing. Each object
+that the RPKI engine knows about takes five messages: "create", "set",
+"get", "list", and "destroy". Actions which are not just data
+operations on objects are handled via an SNMP-like mechanism, as if
+they were fields to be set. For example, to generate a keypair one
+"sets" the "generate-keypair" field of a BSC object, even though there
+is no such field in the object itself as stored in SQL. This is a bit
+of a kludge, but the reason for doing it as if these were variables
+being set is to allow composite operations such as creating a BSC,
+populating all of its data fields, and generating a keypair, all as a
+single operation. With this model, that's trivial, otherwise it's at
+least two round trips.
+
+Fields can be set in either "create" or "set" operations, the
+difference just being whether the object already exists. A "get"
+operation returns all visible fields of the object. A "list"
+operation returns a list containing what "get" would have returned on
+each of those objects.
+
+Left-right protocol objects are encoded as signed CMS messages
+containing XML as eContent and using an eContentType OID of {{{id-ct-xml}}}
+(1.2.840.113549.1.9.16.1.28). These CMS messages are in turn passed
+as the data for HTTP POST operations, with an HTTP content type of
+"application/x-rpki" for both the POST data and the response data.
+
+All operations allow an optional "tag" attribute which can be any
+alphanumeric token. The main purpose of the tag attribute is to allow
+batching of multiple requests into a single PDU.
+
+=== self_obj <self/> object ===
+
+A {{{<self/>}}} object represents one virtual RPKI engine. In simple cases
+where the RPKI engine operator operates the engine only on their own
+behalf, there will only be one {{{<self/>}}} object, representing the engine
+operator's organization, but in environments where the engine operator
+hosts other entities, there will be one {{{<self/>}}} object per hosted
+entity (probably including the engine operator's own organization,
+considered as a hosted customer of itself).
+
+Some of the RPKI engine's configured parameters and data are shared by
+all hosted entities, but most are tied to a specific {{{<self/>}}} object.
+Data which are shared by all hosted entities are referred to as
+"per-engine" data, data which are specific to a particular {{{<self/>}}}
+object are "per-self" data.
+
+Since all other RPKI engine objects refer to a {{{<self/>}}} object via a
+"self_handle" value, one must create a {{{<self/>}}} object before one can
+usefully configure any other left-right protocol objects.
+
+Every {{{<self/>}}} object has a self_handle attribute, which must be specified
+for the "create", "set", "get", and "destroy" actions.
+
+Payload data which can be configured in a {{{<self/>}}} object:
+
+use_hsm:: (attribute)
+ Whether to use a Hardware Signing Module. At present this option
+ has no effect, as the implementation does not yet support HSMs.
+
+crl_interval:: (attribute)
+ Positive integer representing the planned lifetime of an RPKI CRL
+ for this {{{<self/>}}}, measured in seconds.
+
+regen_margin:: (attribute)
+ Positive integer representing how long before expiration of an
+ RPKI certificiate a new one should be generated, measured in
+ seconds. At present this only affects the one-off EE
+ certificates associated with ROAs. This parameter also controls
+ how long before the nextUpdate time of CRL or manifest the CRL
+ or manifest should be updated.
+
+bpki_cert:: (element)
+ BPKI CA certificate for this {{{<self/>}}}. This is used as part of the
+ certificate chain when validating incoming TLS and CMS messages,
+ and should be the issuer of cross-certification BPKI certificates
+ used in {{{<repository/>}}}, {{{<parent/>}}}, and {{{<child/>}}} objects. If the
+ bpki_glue certificate is in use (below), the bpki_cert certificate
+ should be issued by the bpki_glue certificate; otherwise, the
+ bpki_cert certificate should be issued by the per-engine bpki_ta
+ certificate.
+
+bpki_glue:: (element)
+ Another BPKI CA certificate for this {{{<self/>}}}, usually not needed.
+ Certain pathological cross-certification cases require a
+ two-certificate chain due to issuer name conflicts. If used, the
+ bpki_glue certificate should be the issuer of the bpki_cert
+ certificate and should be issued by the per-engine bpki_ta
+ certificate; if not needed, the bpki_glue certificate should be
+ left unset.
+
+Control attributes that can be set to "yes" to force actions:
+
+rekey::
+ Start a key rollover for every RPKI CA associated with every
+ {{{<parent/>}}} object associated with this {{{<self/>}}} object. This is the
+ first phase of a key rollover operation.
+
+revoke::
+ Revoke any remaining certificates for any expired key associated
+ with any RPKI CA for any {{{<parent/>}}} object associated with this
+ {{{<self/>}}} object. This is the second (cleanup) phase for a key
+ rollover operation; it's separate from the first phase to leave
+ time for new RPKI certificates to propegate and be installed.
+
+reissue::
+ Not implemented, may be removed from protocol. Original theory
+ was that this operation would force reissuance of any object with
+ a changed key, but as that happens automatically as part of the
+ key rollover mechanism this operation seems unnecessary.
+
+run_now::
+ Force immediate processing for all tasks associated with this
+ {{{<self/>}}} object that would ordinarily be performed under cron. Not
+ currently implemented.
+
+publish_world_now::
+ Force (re)publication of every publishable object for this {{{<self/>}}}
+ object. Not currently implemented. Intended to aid in recovery
+ if RPKI engine and publication engine somehow get out of sync.
+
+
+=== <bsc/> object ===
+
+The {{{<bsc/>}}} ("business signing context") object represents all the BPKI
+data needed to sign outgoing CMS messages. Various other
+objects include pointers to a {{{<bsc/>}}} object. Whether a particular
+{{{<self/>}}} uses only one {{{<bsc/>}}} or multiple is a configuration decision
+based on external requirements: the RPKI engine code doesn't care, it
+just cares that, for any object representing a relationship for which
+it must sign messages, there be a {{{<bsc/>}}} object that it can use to
+produce that signature.
+
+Every {{{<bsc/>}}} object has a bsc_handle, which must be specified for the
+"create", "get", "set", and "destroy" actions. Every {{{<bsc/>}}} also has a self_handle
+attribute which indicates the {{{<self/>}}} object with which this {{{<bsc/>}}}
+object is associated.
+
+Payload data which can be configured in a {{{<isc/>}}} object:
+
+signing_cert:: (element)
+ BPKI certificate to use when generating a signature.
+
+signing_cert_crl:: (element)
+ CRL which would list signing_cert if it had been revoked.
+
+Control attributes that can be set to "yes" to force actions:
+
+generate_keypair::
+ Generate a new BPKI keypair and return a {{{PKCS #10}}} certificate
+ request. The resulting certificate, once issued, should be
+ configured as this {{{<bsc/>}}} object's signing_cert.
+
+Additional attributes which may be specified when specifying
+"generate_keypair":
+
+key_type::
+ Type of BPKI keypair to generate. "rsa" is both the default and,
+ at the moment, the only allowed value.
+
+hash_alg::
+ Cryptographic hash algorithm to use with this keypair. "sha256"
+ is both the default and, at the moment, the only allowed value.
+
+key_length::
+ Length in bits of the keypair to be generated. "2048" is both the
+ default and, at the moment, the only allowed value.
+
+Replies to "create" and "set" actions that specify "generate-keypair"
+include a <bsc_pkcs10/> element, as do replies to "get" and "list"
+actions for a {{{<bsc/>}}} object for which a "generate-keypair" command has
+been issued. The RPKI engine stores the {{{PKCS #10}}} request, which
+allows the IRBE to reuse the request if and when it needs to reissue
+the corresponding BPKI signing certificate.
+
+=== <parent/> object ===
+
+The {{{<parent/>}}} object represents the RPKI engine's view of a particular
+parent of the current {{{<self/>}}} object in the up-down protocol. Due to
+the way that the resource hierarchy works, a given {{{<self/>}}} may obtain
+resources from multiple parents, but it will always have at least one;
+in the case of IANA or an RIR, the parent RPKI engine may be a trivial
+stub.
+
+Every {{{<parent/>}}} object has a parent_handle, which must be specified for
+the "create", "get", "set", and "destroy" actions. Every {{{<parent/>}}} also has a
+self_handle attribute which indicates the {{{<self/>}}} object with which this
+{{{<parent/>}}} object is associated, a bsc_handle attribute indicating the {{{<bsc/>}}}
+object to be used when signing messages sent to this parent, and a
+repository_handle indicating the {{{<repository/>}}} object to be used when
+publishing issued by the certificate issued by this parent.
+
+Payload data which can be configured in a {{{<parent/>}}} object:
+
+peer_contact_uri:: (attribute)
+ HTTP URI used to contact this parent.
+
+sia_base:: (attribute)
+ The leading portion of an rsync URI that the RPKI engine should
+ use when composing the publication URI for objects issued by the
+ RPKI certificate issued by this parent.
+
+sender_name:: (attribute)
+ Sender name to use in the up-down protocol when talking to this
+ parent. The RPKI engine doesn't really care what this value is,
+ but other implementations of the up-down protocol do care.
+
+recipient_name:: (attribute)
+ Recipient name to use in the up-down protocol when talking to this
+ parent. The RPKI engine doesn't really care what this value is,
+ but other implementations of the up-down protocol do care.
+
+bpki_cms_cert:: (element)
+ BPKI CMS CA certificate for this {{{<parent/>}}}. This is used as part
+ of the certificate chain when validating incoming CMS messages If
+ the bpki_cms_glue certificate is in use (below), the bpki_cms_cert
+ certificate should be issued by the bpki_cms_glue certificate;
+ otherwise, the bpki_cms_cert certificate should be issued by the
+ bpki_cert certificate in the {{{<self/>}}} object.
+
+bpki_cms_glue:: (element)
+ Another BPKI CMS CA certificate for this {{{<parent/>}}}, usually not
+ needed. Certain pathological cross-certification cases require a
+ two-certificate chain due to issuer name conflicts. If used, the
+ bpki_cms_glue certificate should be the issuer of the
+ bpki_cms_cert certificate and should be issued by the bpki_cert
+ certificate in the {{{<self/>}}} object; if not needed, the
+ bpki_cms_glue certificate should be left unset.
+
+Control attributes that can be set to "yes" to force actions:
+
+rekey::
+ This is like the rekey command in the {{{<self/>}}} object, but limited
+ to RPKI CAs under this parent.
+
+reissue::
+ This is like the reissue command in the {{{<self/>}}} object, but limited
+ to RPKI CAs under this parent.
+
+revoke::
+ This is like the revoke command in the {{{<self/>}}} object, but limited
+ to RPKI CAs under this parent.
+
+=== <child/> object ===
+
+The {{{<child/>}}} object represents the RPKI engine's view of particular
+child of the current {{{<self/>}}} in the up-down protocol.
+
+Every {{{<child/>}}} object has a child_handle, which must be specified for the
+"create", "get", "set", and "destroy" actions. Every {{{<child/>}}} also has a
+self_handle attribute which indicates the {{{<self/>}}} object with which this
+{{{<child/>}}} object is associated.
+
+Payload data which can be configured in a {{{<child/>}}} object:
+
+bpki_cert:: (element)
+ BPKI CA certificate for this {{{<child/>}}}. This is used as part of
+ the certificate chain when validating incoming TLS and CMS
+ messages. If the bpki_glue certificate is in use (below), the
+ bpki_cert certificate should be issued by the bpki_glue
+ certificate; otherwise, the bpki_cert certificate should be issued
+ by the bpki_cert certificate in the {{{<self/>}}} object.
+
+bpki_glue:: (element)
+ Another BPKI CA certificate for this {{{<child/>}}}, usually not needed.
+ Certain pathological cross-certification cases require a
+ two-certificate chain due to issuer name conflicts. If used, the
+ bpki_glue certificate should be the issuer of the bpki_cert
+ certificate and should be issued by the bpki_cert certificate in
+ the {{{<self/>}}} object; if not needed, the bpki_glue certificate
+ should be left unset.
+
+Control attributes that can be set to "yes" to force actions:
+
+reissue::
+ Not implemented, may be removed from protocol.
+
+=== <repository/> object ===
+
+The {{{<repository/>}}} object represents the RPKI engine's view of a
+particular publication repository used by the current {{{<self/>}}} object.
+
+Every {{{<repository/>}}} object has a repository_handle, which must be
+specified for the "create", "get", "set", and "destroy" actions. Every
+{{{<repository/>}}} also has a self_handle attribute which indicates the {{{<self/>}}}
+object with which this {{{<repository/>}}} object is associated.
+
+Payload data which can be configured in a {{{<repository/>}}} object:
+
+peer_contact_uri:: (attribute)
+ HTTP URI used to contact this repository.
+
+bpki_cms_cert:: (element)
+ BPKI CMS CA certificate for this {{{<repository/>}}}. This is used as part
+ of the certificate chain when validating incoming CMS messages If
+ the bpki_cms_glue certificate is in use (below), the bpki_cms_cert
+ certificate should be issued by the bpki_cms_glue certificate;
+ otherwise, the bpki_cms_cert certificate should be issued by the
+ bpki_cert certificate in the {{{<self/>}}} object.
+
+bpki_cms_glue:: (element)
+ Another BPKI CMS CA certificate for this {{{<repository/>}}}, usually not
+ needed. Certain pathological cross-certification cases require a
+ two-certificate chain due to issuer name conflicts. If used, the
+ bpki_cms_glue certificate should be the issuer of the
+ bpki_cms_cert certificate and should be issued by the bpki_cert
+ certificate in the {{{<self/>}}} object; if not needed, the
+ bpki_cms_glue certificate should be left unset.
+
+At present there are no control attributes for {{{<repository/>}}} objects.
+
+=== <route_origin/> object ===
+
+This section is out-of-date. The {{{<route_origin/>}}} object
+has been replaced by the {{{<list_roa_requests/>}}} IRDB query,
+but the documentation for that hasn't been written yet.
+
+The {{{<route_origin/>}}} object is a kind of prototype for a ROA. It
+contains all the information needed to generate a ROA once the RPKI
+engine obtains the appropriate RPKI certificates from its parent(s).
+
+Note that a {{{<route_origin/>}}} object represents a ROA to be generated on
+behalf of {{{<self/>}}}, not on behalf of a {{{<child/>}}}. Thus, a hosted entity
+that has no children but which does need to generate ROAs would be
+represented by a hosted {{{<self/>}}} with no {{{<child/>}}} objects but one or
+more {{{<route_origin/>}}} objects. While lumping ROA generation in with
+the other RPKI engine activities may seem a little odd at first, it's
+a natural consequence of the design requirement that the RPKI daemon
+never transmit private keys across the network in any form; given this
+requirement, the RPKI engine that holds the private keys for an RPKI
+certificate must also be the engine which generates any ROAs that
+derive from that RPKI certificate.
+
+The precise content of the {{{<route_origin/>}}} has changed over time as
+the underlying ROA specification has changed. The current
+implementation as of this writing matches what we expect to see in
+draft-ietf-sidr-roa-format-03, once it is issued. In particular, note
+that the exactMatch boolean from the -02 draft has been replaced by
+the prefix and maxLength encoding used in the -03 draft.
+
+Payload data which can be configured in a {{{<route_origin/>}}} object:
+
+asn:: (attribute)
+ Autonomous System Number (ASN) to place in the generated ROA. A
+ single ROA can only grant authorization to a single ASN; multiple
+ ASNs require multiple ROAs, thus multiple {{{<route_origin/>}}} objects.
+
+ipv4:: (attribute)
+ List of IPv4 prefix and maxLength values, see below for format.
+
+ipv6:: (attribute)
+ List of IPv6 prefix and maxLength values, see below for format.
+
+Control attributes that can be set to "yes" to force actions:
+
+suppress_publication::
+ Not implemented, may be removed from protocol.
+
+The lists of IPv4 and IPv6 prefix and maxLength values are represented
+as comma-separated text strings, with no whitespace permitted. Each
+entry in such a string represents a single prefix/maxLength pair.
+
+ABNF for these address lists:
+
+{{{
+ <ROAIPAddress> ::= <address> "/" <prefixlen> [ "-" <max_prefixlen> ]
+ ; Where <max_prefixlen> defaults to the same
+ ; value as <prefixlen>.
+
+ <ROAIPAddressList> ::= <ROAIPAddress> *( "," <ROAIPAddress> )
+}}}
+
+For example, {{{10.0.1.0/24-32,10.0.2.0/24}}}, which is a shorthand
+form of {{{10.0.1.0/24-32,10.0.2.0/24-24}}}.
+
+== Operations initiated by the RPKI engine ==
+
+The left-right protocol also includes queries from the RPKI engine
+back to the IRDB. These queries do not follow the message-passing
+pattern used in the IRBE-initiated part of the protocol. Instead,
+there's a single query back to the IRDB, with a corresponding
+response. The CMS encoding are the same as in the rest of
+the protocol, but the BPKI certificates will be different as the
+back-queries and responses form a separate communication channel.
+
+=== <list_resources/> messages ===
+
+The {{{<list_resources/>}}} query and response allow the RPKI engine to ask
+the IRDB for information about resources assigned to a particular
+child. The query must include both a {{{self_handle}}} attribute naming
+the {{{<self/>}}} that is making the request and also a {{{child_handle}}}
+attribute naming the child that is the subject of the query. The
+query and response also allow an optional //tag// attribute of the
+same form used elsewhere in this protocol, to allow batching.
+
+A {{{<list_resources/>}}} response includes the following attributes, along
+with the tag (if specified), {{{self_handle}}}, and {{{child_handle}}} copied
+from the request:
+
+valid_until::
+ A timestamp indicating the date and time at which certificates
+ generated by the RPKI engine for these data should expire. The
+ timestamp is expressed as an XML {{{xsd:dateTime}}}, must be
+ expressed in UTC, and must carry the "Z" suffix indicating UTC.
+
+asn::
+ A list of autonomous sequence numbers, expressed as a
+ comma-separated sequence of decimal integers with no whitespace.
+
+ipv4::
+ A list of IPv4 address prefixes and ranges, expressed as a
+ comma-separated list of prefixes and ranges with no whitespace.
+ See below for format details.
+
+ipv6::
+ A list of IPv6 address prefixes and ranges, expressed as a
+ comma-separated list of prefixes and ranges with no whitespace.
+ See below for format details.
+
+Entries in a list of address prefixes and ranges can be either
+prefixes, which are written in the usual address/prefixlen notation,
+or ranges, which are expressed as a pair of addresses denoting the
+beginning and end of the range, written in ascending order separated
+by a single "-" character. This format is superficially similar to
+the format used for prefix and maxLength values in the {{{<route_origin/>}}}
+object, but the semantics differ: note in particular that
+{{{<route_origin/>}}} objects don't allow ranges, while {{{<list_resources/>}}}
+messages don't allow a maxLength specification.
+
+== Error handling ==
+
+Error in this protocol are handled at two levels.
+
+Since all messages in this protocol are conveyed over HTTP
+connections, basic errors are indicated via the HTTP response code.
+4xx and 5xx responses indicate that something bad happened. Errors
+that make it impossible to decode a query or encode a response are
+handled in this way.
+
+Where possible, errors will result in a {{{<report_error/>}}} message which
+takes the place of the expected protocol response message.
+{{{<report_error/>}}} messages are CMS-signed XML messages like the rest of
+this protocol, and thus can be archived to provide an audit trail.
+
+{{{<report_error/>}}} messages only appear in replies, never in queries.
+The {{{<report_error/>}}} message can appear on either the "forward" (IRBE
+as client of RPKI engine) or "back" (RPKI engine as client of IRDB)
+communication channel.
+
+The {{{<report_error/>}}} message includes an optional //tag// attribute to
+assist in matching the error with a particular query when using
+batching, and also includes a {{{self_handle}}} attribute indicating the
+{{{<self/>}}} that issued the error.
+
+The error itself is conveyed in the {{{error_code}}} (attribute). The
+value of this attribute is a token indicating the specific error that
+occurred. At present this will be the name of a Python exception; the
+production version of this protocol will nail down the allowed error
+tokens here, probably in the RelaxNG schema.
+
+The body of the {{{<report_error/>}}} element itself is an optional text
+string; if present, this is debugging information. At present this
+capabilty is not used, debugging information goes to syslog.
diff --git a/doc/manual/36.RPKI.Utils.md b/doc/manual/36.RPKI.Utils.md
new file mode 100644
index 00000000..aa668643
--- /dev/null
+++ b/doc/manual/36.RPKI.Utils.md
@@ -0,0 +1,182 @@
+# RPKI utility programs
+
+The distribution contains a few small utility programs. Most of these are
+nominally relying party tools, but work at a low enough level that they may
+also be useful in diagnosing CA problems.
+
+Unless otherwise specified, all of these tools expect RPKI objects
+(certificates, CRLs, CMS signed objects) to be in DER format.
+
+Several of these tools accept an `rcynic_directory` argument. Which directory
+to specify here depends on what you're trying to do, but if you're just trying
+to look at authenticated data in your RP cache, and assuming you've installed
+everything in the default locations, the directory you want is probably
+`/var/rcynic/data/authenticated`.
+
+## uri
+
+`uri` is a utility program to extract URIs from the SIA, AIA, and CRLDP
+extensions of one or more X.509v3 certificates, either specified directly or
+as CMS objects containing X.509v3 certificates within the CMS wrapper.
+
+Usage:
+
+ $ uri [-h | --help] [-s | --single-line] cert [cert...]
+
+`-h --help`
+
+ Show help
+`-s --single-line`
+
+ Single output line per input file
+`cert`
+
+ Object(s) to examine
+
+## hashdir
+
+`hashdir` copies an authenticated result tree from an rcynic run into the
+format expected by most OpenSSL-based programs: a collection of "PEM" format
+files with names in the form that OpenSSL's `-CApath` lookup routines expect.
+This can be useful for validating RPKI objects which are not distributed as
+part of the repository system.
+
+Usage:
+
+ $ hashdir [-h | --help] [-v | --verbose] rcynic_directory output_directory
+
+`-h --help`
+
+ Show help
+`-v --verbose`
+
+ Whistle while you work
+`rcynic_directory`
+
+ rcynic authenticated output tree
+`output_directory`
+
+ Output directory to create
+
+## print_rpki_manifest
+
+`print_rpki_manifest` pretty-prints the content of a manifest. It does _NOT_
+attempt to verify the signature.
+
+Usage:
+
+ $ print_rpki_manifest [-h | --help] [-c | --cms] manifest [manifest...]
+
+`-h --help`
+
+ Show help
+`-c --cms`
+
+ Print text representation of entire CMS blob
+`manifest`
+
+ Manifest(s) to print
+
+## print_roa
+
+`print_roa` pretty-prints the content of a ROA. It does _NOT_ attempt to
+verify the signature.
+
+Usage:
+
+ $ print_roa [-h | --help] [-b | --brief] [-c | --cms] [-s | --signing-time] ROA [ROA...]
+
+`-h --help`
+
+ Show help
+`-b --brief`
+
+ Brief mode (only show ASN and prefix)
+`-c --cms`
+
+ Print text representation of entire CMS blob
+`-s --signing-time`
+
+ Show CMS signingTime
+`ROA`
+
+ ROA object(s) to print
+
+## find_roa
+
+`find_roa` searches the authenticated result tree from an rcynic run for ROAs
+matching specified prefixes.
+
+Usage:
+
+ $ find_roa [-h | --help] [-a | --all]
+ [-m | --match-maxlength ] [-f | --show-filenames]
+ [-i | --show-inception] [-e | --show-expiration]
+ authtree [prefix...]
+
+`-h --help`
+
+ Show help
+`-a --all`
+
+ Show all ROAs, do no prefix matching at all
+`-e --show-expiration`
+
+ Show ROA chain expiration dates
+`-f --show-filenames`
+
+ Show filenames instead of URIs
+`-i --show-inception`
+
+ Show inception dates
+`-m -match-maxlength`
+
+ Pay attention to maxLength values
+`authtree`
+
+ rcynic authenticated output tree
+`prefix`
+
+ ROA prefix(es) to on which to match
+
+## scan_roas
+
+`scan_roas` searchs the authenticated result tree from an rcynic run for ROAs,
+and prints out the signing time, ASN, and prefixes for each ROA, one ROA per
+line.
+
+Other programs such as the [rpki-rtr client][] use `scan_roas` to extract the
+validated ROA payload after an rcynic validation run.
+
+Usage:
+
+ $ scan_roas [-h | --help] rcynic_directory [rcynic_directory...]
+
+`-h --help`
+
+ Show help
+`rcynic_directory`
+
+ rcynic authenticated output tree
+
+## scan_routercerts
+
+`scan_routercerts` searchs the authenticated result tree from an rcynic run
+for BGPSEC router certificates, and prints out data of interest to the rpki-
+rtr code.
+
+Other programs such as the [rpki-rtr client][] use `scan_routercerts` to
+extract the validated ROA payload after an rcynic validation run.
+
+Usage:
+
+ $ scan_routercerts [-h | --help] rcynic_directory [rcynic_directory...]
+
+`-h --help`
+
+ Show help
+`rcynic_directory`
+
+ rcynic authenticated output tree
+
+[rpki-rtr client]: 07.RPKI.RP.rpki-rtr.md
diff --git a/doc/manual/36.RPKI.Utils.wiki b/doc/manual/36.RPKI.Utils.wiki
new file mode 100644
index 00000000..59ae491d
--- /dev/null
+++ b/doc/manual/36.RPKI.Utils.wiki
@@ -0,0 +1,179 @@
+= RPKI utility programs =
+
+[[TracNav(doc/RPKI/TOC)]]
+
+The distribution contains a few small utility programs. Most of these
+are nominally relying party tools, but work at a low enough level that
+they may also be useful in diagnosing CA problems.
+
+Unless otherwise specified, all of these tools expect RPKI objects
+(certificates, CRLs, CMS signed objects) to be in DER format.
+
+Several of these tools accept an `rcynic_directory` argument. Which
+directory to specify here depends on what you're trying to do, but if
+you're just trying to look at authenticated data in your RP cache, and
+assuming you've installed everything in the default locations, the
+directory you want is probably `/var/rcynic/data/authenticated`.
+
+== uri ==
+
+`uri` is a utility program to extract URIs from the SIA, AIA, and
+CRLDP extensions of one or more X.509v3 certificates, either specified
+directly or as CMS objects containing X.509v3 certificates within the
+CMS wrapper.
+
+Usage:
+
+{{{
+#!sh
+$ uri [-h | --help] [-s | --single-line] cert [cert...]
+}}}
+
+ `-h --help`::
+ Show help
+ `-s --single-line`::
+ Single output line per input file
+ `cert`::
+ Object(s) to examine
+
+== hashdir ==
+
+`hashdir` copies an authenticated result tree from an rcynic run into
+the format expected by most OpenSSL-based programs: a collection of
+"PEM" format files with names in the form that OpenSSL's `-CApath`
+lookup routines expect. This can be useful for validating RPKI
+objects which are not distributed as part of the repository system.
+
+Usage:
+
+{{{
+#!sh
+$ hashdir [-h | --help] [-v | --verbose] rcynic_directory output_directory
+}}}
+
+ `-h --help`::
+ Show help
+ `-v --verbose`::
+ Whistle while you work
+ `rcynic_directory`::
+ rcynic authenticated output tree
+ `output_directory`::
+ Output directory to create
+
+== print_rpki_manifest ==
+
+`print_rpki_manifest` pretty-prints the content of a manifest. It
+does //NOT// attempt to verify the signature.
+
+Usage:
+
+{{{
+#!sh
+$ print_rpki_manifest [-h | --help] [-c | --cms] manifest [manifest...]
+}}}
+
+ `-h --help`::
+ Show help
+ `-c --cms`::
+ Print text representation of entire CMS blob
+ `manifest`::
+ Manifest(s) to print
+
+== print_roa ==
+
+`print_roa` pretty-prints the content of a ROA. It does //NOT//
+attempt to verify the signature.
+
+Usage:
+
+{{{
+#!sh
+$ print_roa [-h | --help] [-b | --brief] [-c | --cms] [-s | --signing-time] ROA [ROA...]
+}}}
+
+ `-h --help`::
+ Show help
+ `-b --brief`::
+ Brief mode (only show ASN and prefix)
+ `-c --cms`::
+ Print text representation of entire CMS blob
+ `-s --signing-time`::
+ Show CMS signingTime
+ `ROA`::
+ ROA object(s) to print
+
+== find_roa ==
+
+`find_roa` searches the authenticated result tree from an rcynic run
+for ROAs matching specified prefixes.
+
+Usage:
+
+{{{
+#!sh
+$ find_roa [-h | --help] [-a | --all]
+ [-m | --match-maxlength ] [-f | --show-filenames]
+ [-i | --show-inception] [-e | --show-expiration]
+ authtree [prefix...]
+}}}
+
+ `-h --help`::
+ Show help
+ `-a --all`::
+ Show all ROAs, do no prefix matching at all
+ `-e --show-expiration`::
+ Show ROA chain expiration dates
+ `-f --show-filenames`::
+ Show filenames instead of URIs
+ `-i --show-inception`::
+ Show inception dates
+ `-m -match-maxlength`::
+ Pay attention to maxLength values
+ `authtree`::
+ rcynic authenticated output tree
+ `prefix`::
+ ROA prefix(es) to on which to match
+
+== scan_roas ==
+
+`scan_roas` searchs the authenticated result tree from an rcynic
+run for ROAs, and prints out the signing time, ASN, and prefixes for
+each ROA, one ROA per line.
+
+Other programs such as the [[RP/rpki-rtr|rpki-rtr client]] use
+`scan_roas` to extract the validated ROA payload after an rcynic
+validation run.
+
+Usage:
+
+{{{
+#!sh
+$ scan_roas [-h | --help] rcynic_directory [rcynic_directory...]
+}}}
+
+ `-h --help`::
+ Show help
+ `rcynic_directory`::
+ rcynic authenticated output tree
+
+== scan_routercerts ==
+
+`scan_routercerts` searchs the authenticated result tree from an
+rcynic run for BGPSEC router certificates, and prints out data of
+interest to the rpki-rtr code.
+
+Other programs such as the [[RP/rpki-rtr|rpki-rtr client]] use
+`scan_routercerts` to extract the validated ROA payload after an
+rcynic validation run.
+
+Usage:
+
+{{{
+#!sh
+$ scan_routercerts [-h | --help] rcynic_directory [rcynic_directory...]
+}}}
+
+ `-h --help`::
+ Show help
+ `rcynic_directory`::
+ rcynic authenticated output tree
diff --git a/doc/manual/37.RPKI.Protocols.md b/doc/manual/37.RPKI.Protocols.md
new file mode 100644
index 00000000..35df4984
--- /dev/null
+++ b/doc/manual/37.RPKI.Protocols.md
@@ -0,0 +1,9 @@
+# Overview Of RPKI Protocols
+
+Brief overview of certain RPKI protocols. This is a work in progress.
+
+ * [The out-of-band setup protocol][OOB]
+ * [The "Up-Down" provisioning protocol][Up-Down]
+
+[OOB]: 38.RPKI.Protocols.OOB.md
+[Up-Down]: 39.RPKI.Protocols.Up-Down.md
diff --git a/doc/manual/37.RPKI.Protocols.wiki b/doc/manual/37.RPKI.Protocols.wiki
new file mode 100644
index 00000000..5b852d41
--- /dev/null
+++ b/doc/manual/37.RPKI.Protocols.wiki
@@ -0,0 +1,8 @@
+= Overview Of RPKI Protocols =
+
+[[TracNav(doc/RPKI/TOC)]]
+
+Brief overview of certain RPKI protocols. This is a work in progress.
+
+* [[wiki:doc/RPKI/Protocols/OOB|The out-of-band setup protocol]]
+* [[wiki:doc/RPKI/Protocols/Up-Down|The "Up-Down" provisioning protocol]]
diff --git a/doc/manual/38.RPKI.Protocols.OOB.00.svg b/doc/manual/38.RPKI.Protocols.OOB.00.svg
new file mode 100644
index 00000000..b297e14e
--- /dev/null
+++ b/doc/manual/38.RPKI.Protocols.OOB.00.svg
@@ -0,0 +1,321 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.28.0 (20110821.1312)
+ -->
+<!-- Title: ladder_oob Pages: 1 -->
+<svg width="642pt" height="808pt"
+ viewBox="0.00 0.00 642.00 808.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph1" class="graph" transform="scale(1 1) rotate(0) translate(4 804)">
+<title>ladder_oob</title>
+<polygon fill="white" stroke="white" points="-4,5 -4,-804 639,-804 639,5 -4,5"/>
+<!-- p0 -->
+<g id="node2" class="node"><title>p0</title>
+<polygon fill="deeppink" stroke="black" points="31.5166,-776.438 76,-764 120.483,-776.438 120.442,-796.562 31.5581,-796.562 31.5166,-776.438"/>
+<text text-anchor="middle" x="76" y="-778.3" font-family="Helvetica,sans-Serif" font-size="14.00">Parent</text>
+</g>
+<!-- s0 -->
+<g id="node3" class="node"><title>s0</title>
+<polygon fill="cornflowerblue" stroke="black" points="261.592,-776.438 294,-764 326.408,-776.438 326.378,-796.562 261.622,-796.562 261.592,-776.438"/>
+<text text-anchor="middle" x="294" y="-778.3" font-family="Helvetica,sans-Serif" font-size="14.00">Self</text>
+</g>
+<!-- p0&#45;&gt;s0 -->
+<!-- p2 -->
+<g id="node7" class="node"><title>p2</title>
+<ellipse fill="black" stroke="black" cx="76" cy="-632" rx="1.8" ry="1.8"/>
+</g>
+<!-- p0&#45;&gt;p2 -->
+<g id="edge35" class="edge"><title>p0&#45;&gt;p2</title>
+<path fill="none" stroke="lightgray" stroke-dasharray="5,2" d="M76,-763.733C76,-727.132 76,-644.256 76,-634.039"/>
+</g>
+<!-- r0 -->
+<g id="node4" class="node"><title>r0</title>
+<polygon fill="limegreen" stroke="black" points="450.775,-776.438 518,-764 585.225,-776.438 585.162,-796.562 450.838,-796.562 450.775,-776.438"/>
+<text text-anchor="middle" x="518" y="-778.3" font-family="Helvetica,sans-Serif" font-size="14.00">Repository</text>
+</g>
+<!-- s0&#45;&gt;r0 -->
+<!-- s1 -->
+<g id="node5" class="node"><title>s1</title>
+<polygon fill="cornflowerblue" stroke="cornflowerblue" points="334.5,-728 253.5,-728 241.5,-716 241.5,-704 253.5,-692 334.5,-692 346.5,-704 346.5,-716 334.5,-728"/>
+<path fill="cornflowerblue" stroke="cornflowerblue" d="M253.5,-728C247.5,-728 241.5,-722 241.5,-716"/>
+<path fill="cornflowerblue" stroke="cornflowerblue" d="M241.5,-704C241.5,-698 247.5,-692 253.5,-692"/>
+<path fill="cornflowerblue" stroke="cornflowerblue" d="M334.5,-692C340.5,-692 346.5,-698 346.5,-704"/>
+<path fill="cornflowerblue" stroke="cornflowerblue" d="M346.5,-716C346.5,-722 340.5,-728 334.5,-728"/>
+<polyline fill="none" stroke="black" points="334.5,-728 253.5,-728 "/>
+<path fill="none" stroke="black" d="M253.5,-728C247.5,-728 241.5,-722 241.5,-716"/>
+<polyline fill="none" stroke="black" points="241.5,-716 241.5,-704 "/>
+<path fill="none" stroke="black" d="M241.5,-704C241.5,-698 247.5,-692 253.5,-692"/>
+<polyline fill="none" stroke="black" points="253.5,-692 334.5,-692 "/>
+<path fill="none" stroke="black" d="M334.5,-692C340.5,-692 346.5,-698 346.5,-704"/>
+<polyline fill="none" stroke="black" points="346.5,-704 346.5,-716 "/>
+<path fill="none" stroke="black" d="M346.5,-716C346.5,-722 340.5,-728 334.5,-728"/>
+<text text-anchor="middle" x="294" y="-706.3" font-family="Helvetica,sans-Serif" font-size="14.00">rpkic&gt; initialize</text>
+</g>
+<!-- s0&#45;&gt;s1 -->
+<g id="edge37" class="edge"><title>s0&#45;&gt;s1</title>
+<path fill="none" stroke="lightgray" stroke-dasharray="5,2" d="M294,-763.697C294,-752.846 294,-738.917 294,-728.104"/>
+</g>
+<!-- r6 -->
+<g id="node22" class="node"><title>r6</title>
+<ellipse fill="black" stroke="black" cx="518" cy="-263" rx="1.8" ry="1.8"/>
+</g>
+<!-- r0&#45;&gt;r6 -->
+<g id="edge43" class="edge"><title>r0&#45;&gt;r6</title>
+<path fill="none" stroke="lightgray" stroke-dasharray="5,2" d="M518,-763.683C518,-736.051 518,-680.278 518,-633 518,-633 518,-633 518,-452 518,-373.667 518,-276.974 518,-265.193"/>
+</g>
+<!-- s2 -->
+<g id="node10" class="node"><title>s2</title>
+<ellipse fill="black" stroke="black" cx="294" cy="-632" rx="1.8" ry="1.8"/>
+</g>
+<!-- s1&#45;&gt;s2 -->
+<g id="edge25" class="edge"><title>s1&#45;&gt;s2</title>
+<path fill="none" stroke="black" d="M294,-691.754C294,-671.433 294,-639.69 294,-633.917"/>
+</g>
+<!-- m2 -->
+<g id="node9" class="node"><title>m2</title>
+<polygon fill="lightgrey" stroke="lightgrey" points="143.5,-609 226.5,-609 238.5,-621 238.5,-643 226.5,-655 143.5,-655 131.5,-643 131.5,-621 143.5,-609"/>
+<path fill="lightgrey" stroke="lightgrey" d="M226.5,-609C232.5,-609 238.5,-615 238.5,-621"/>
+<path fill="lightgrey" stroke="lightgrey" d="M238.5,-643C238.5,-649 232.5,-655 226.5,-655"/>
+<path fill="lightgrey" stroke="lightgrey" d="M143.5,-655C137.5,-655 131.5,-649 131.5,-643"/>
+<path fill="lightgrey" stroke="lightgrey" d="M131.5,-621C131.5,-615 137.5,-609 143.5,-609"/>
+<polyline fill="none" stroke="black" points="143.5,-609 226.5,-609 "/>
+<path fill="none" stroke="black" d="M226.5,-609C232.5,-609 238.5,-615 238.5,-621"/>
+<polyline fill="none" stroke="black" points="238.5,-621 238.5,-643 "/>
+<path fill="none" stroke="black" d="M238.5,-643C238.5,-649 232.5,-655 226.5,-655"/>
+<polyline fill="none" stroke="black" points="226.5,-655 143.5,-655 "/>
+<path fill="none" stroke="black" d="M143.5,-655C137.5,-655 131.5,-649 131.5,-643"/>
+<polyline fill="none" stroke="black" points="131.5,-643 131.5,-621 "/>
+<path fill="none" stroke="black" d="M131.5,-621C131.5,-615 137.5,-609 143.5,-609"/>
+<text text-anchor="middle" x="185" y="-639.8" font-family="Helvetica,sans-Serif" font-size="14.00">Child Handle</text>
+<polyline fill="none" stroke="black" points="131.5,-632 238.5,-632 "/>
+<text text-anchor="middle" x="185" y="-616.8" font-family="Helvetica,sans-Serif" font-size="14.00">Child BPKI TA</text>
+</g>
+<!-- p2&#45;&gt;m2 -->
+<g id="edge4" class="edge"><title>p2&#45;&gt;m2</title>
+<path fill="none" stroke="black" d="M88.484,-632C102.705,-632 116.926,-632 131.147,-632"/>
+<polygon fill="black" stroke="black" points="78.1289,-632 88.1289,-627.5 83.1289,-632 88.1289,-632 88.1289,-632 88.1289,-632 83.1289,-632 88.1289,-636.5 78.1289,-632 78.1289,-632"/>
+</g>
+<!-- p3 -->
+<g id="node11" class="node"><title>p3</title>
+<polygon fill="deeppink" stroke="deeppink" points="140.25,-572 11.75,-572 -0.25,-560 -0.25,-548 11.75,-536 140.25,-536 152.25,-548 152.25,-560 140.25,-572"/>
+<path fill="deeppink" stroke="deeppink" d="M11.75,-572C5.75,-572 -0.25,-566 -0.25,-560"/>
+<path fill="deeppink" stroke="deeppink" d="M-0.25,-548C-0.25,-542 5.75,-536 11.75,-536"/>
+<path fill="deeppink" stroke="deeppink" d="M140.25,-536C146.25,-536 152.25,-542 152.25,-548"/>
+<path fill="deeppink" stroke="deeppink" d="M152.25,-560C152.25,-566 146.25,-572 140.25,-572"/>
+<polyline fill="none" stroke="black" points="140.25,-572 11.75,-572 "/>
+<path fill="none" stroke="black" d="M11.75,-572C5.75,-572 -0.25,-566 -0.25,-560"/>
+<polyline fill="none" stroke="black" points="-0.25,-560 -0.25,-548 "/>
+<path fill="none" stroke="black" d="M-0.25,-548C-0.25,-542 5.75,-536 11.75,-536"/>
+<polyline fill="none" stroke="black" points="11.75,-536 140.25,-536 "/>
+<path fill="none" stroke="black" d="M140.25,-536C146.25,-536 152.25,-542 152.25,-548"/>
+<polyline fill="none" stroke="black" points="152.25,-548 152.25,-560 "/>
+<path fill="none" stroke="black" d="M152.25,-560C152.25,-566 146.25,-572 140.25,-572"/>
+<text text-anchor="middle" x="76" y="-550.3" font-family="Helvetica,sans-Serif" font-size="14.00">rpkic&gt; configure_child</text>
+</g>
+<!-- p2&#45;&gt;p3 -->
+<g id="edge22" class="edge"><title>p2&#45;&gt;p3</title>
+<path fill="none" stroke="black" d="M76,-630.146C76,-624.537 76,-592.543 76,-572.151"/>
+</g>
+<!-- m2&#45;&gt;s2 -->
+<g id="edge5" class="edge"><title>m2&#45;&gt;s2</title>
+<path fill="none" stroke="black" d="M249.037,-632C263.304,-632 277.571,-632 291.838,-632"/>
+<polygon fill="black" stroke="black" points="238.648,-632 248.648,-627.5 243.648,-632 248.648,-632 248.648,-632 248.648,-632 243.648,-632 248.648,-636.5 238.648,-632 238.648,-632"/>
+</g>
+<!-- s4 -->
+<g id="node16" class="node"><title>s4</title>
+<ellipse fill="black" stroke="black" cx="294" cy="-453" rx="1.8" ry="1.8"/>
+</g>
+<!-- s2&#45;&gt;s4 -->
+<g id="edge39" class="edge"><title>s2&#45;&gt;s4</title>
+<path fill="none" stroke="lightgray" stroke-dasharray="5,2" d="M294,-629.87C294,-615.502 294,-468.754 294,-455.028"/>
+</g>
+<!-- p4 -->
+<g id="node13" class="node"><title>p4</title>
+<ellipse fill="black" stroke="black" cx="76" cy="-453" rx="1.8" ry="1.8"/>
+</g>
+<!-- p3&#45;&gt;p4 -->
+<g id="edge23" class="edge"><title>p3&#45;&gt;p4</title>
+<path fill="none" stroke="black" d="M76,-535.756C76,-509.607 76,-462.19 76,-454.94"/>
+</g>
+<!-- m4 -->
+<g id="node15" class="node"><title>m4</title>
+<polygon fill="lightgrey" stroke="lightgrey" points="108,-407 262,-407 274,-419 274,-487 262,-499 108,-499 96,-487 96,-419 108,-407"/>
+<path fill="lightgrey" stroke="lightgrey" d="M262,-407C268,-407 274,-413 274,-419"/>
+<path fill="lightgrey" stroke="lightgrey" d="M274,-487C274,-493 268,-499 262,-499"/>
+<path fill="lightgrey" stroke="lightgrey" d="M108,-499C102,-499 96,-493 96,-487"/>
+<path fill="lightgrey" stroke="lightgrey" d="M96,-419C96,-413 102,-407 108,-407"/>
+<polyline fill="none" stroke="black" points="108,-407 262,-407 "/>
+<path fill="none" stroke="black" d="M262,-407C268,-407 274,-413 274,-419"/>
+<polyline fill="none" stroke="black" points="274,-419 274,-487 "/>
+<path fill="none" stroke="black" d="M274,-487C274,-493 268,-499 262,-499"/>
+<polyline fill="none" stroke="black" points="262,-499 108,-499 "/>
+<path fill="none" stroke="black" d="M108,-499C102,-499 96,-493 96,-487"/>
+<polyline fill="none" stroke="black" points="96,-487 96,-419 "/>
+<path fill="none" stroke="black" d="M96,-419C96,-413 102,-407 108,-407"/>
+<text text-anchor="middle" x="185" y="-483.8" font-family="Helvetica,sans-Serif" font-size="14.00">Parent Handle</text>
+<polyline fill="none" stroke="black" points="96,-476 274,-476 "/>
+<text text-anchor="middle" x="185" y="-460.8" font-family="Helvetica,sans-Serif" font-size="14.00">Parent BPKI TA</text>
+<polyline fill="none" stroke="black" points="96,-453 274,-453 "/>
+<text text-anchor="middle" x="185" y="-437.8" font-family="Helvetica,sans-Serif" font-size="14.00">Parent Service URL</text>
+<polyline fill="none" stroke="black" points="96,-430 274,-430 "/>
+<text text-anchor="middle" x="185" y="-414.8" font-family="Helvetica,sans-Serif" font-size="14.00">Repository Hint (Optional)</text>
+</g>
+<!-- p4&#45;&gt;m4 -->
+<g id="edge8" class="edge"><title>p4&#45;&gt;m4</title>
+<path fill="none" stroke="black" d="M78.1289,-453C80.5946,-453 83.0602,-453 85.5259,-453"/>
+<polygon fill="black" stroke="black" points="95.6624,-453 85.6625,-457.5 90.6624,-453 85.6624,-453 85.6624,-453 85.6624,-453 90.6624,-453 85.6624,-448.5 95.6624,-453 95.6624,-453"/>
+</g>
+<!-- m4&#45;&gt;s4 -->
+<g id="edge9" class="edge"><title>m4&#45;&gt;s4</title>
+<path fill="none" stroke="black" d="M274.414,-453C276.91,-453 279.406,-453 281.902,-453"/>
+<polygon fill="black" stroke="black" points="292.164,-453 282.164,-457.5 287.164,-453 282.164,-453 282.164,-453 282.164,-453 287.164,-453 282.164,-448.5 292.164,-453 292.164,-453"/>
+</g>
+<!-- s5 -->
+<g id="node17" class="node"><title>s5</title>
+<polygon fill="cornflowerblue" stroke="cornflowerblue" points="363.25,-370 224.75,-370 212.75,-358 212.75,-346 224.75,-334 363.25,-334 375.25,-346 375.25,-358 363.25,-370"/>
+<path fill="cornflowerblue" stroke="cornflowerblue" d="M224.75,-370C218.75,-370 212.75,-364 212.75,-358"/>
+<path fill="cornflowerblue" stroke="cornflowerblue" d="M212.75,-346C212.75,-340 218.75,-334 224.75,-334"/>
+<path fill="cornflowerblue" stroke="cornflowerblue" d="M363.25,-334C369.25,-334 375.25,-340 375.25,-346"/>
+<path fill="cornflowerblue" stroke="cornflowerblue" d="M375.25,-358C375.25,-364 369.25,-370 363.25,-370"/>
+<polyline fill="none" stroke="black" points="363.25,-370 224.75,-370 "/>
+<path fill="none" stroke="black" d="M224.75,-370C218.75,-370 212.75,-364 212.75,-358"/>
+<polyline fill="none" stroke="black" points="212.75,-358 212.75,-346 "/>
+<path fill="none" stroke="black" d="M212.75,-346C212.75,-340 218.75,-334 224.75,-334"/>
+<polyline fill="none" stroke="black" points="224.75,-334 363.25,-334 "/>
+<path fill="none" stroke="black" d="M363.25,-334C369.25,-334 375.25,-340 375.25,-346"/>
+<polyline fill="none" stroke="black" points="375.25,-346 375.25,-358 "/>
+<path fill="none" stroke="black" d="M375.25,-358C375.25,-364 369.25,-370 363.25,-370"/>
+<text text-anchor="middle" x="294" y="-348.3" font-family="Helvetica,sans-Serif" font-size="14.00">rpkic&gt; configure_parent</text>
+</g>
+<!-- s4&#45;&gt;s5 -->
+<g id="edge27" class="edge"><title>s4&#45;&gt;s5</title>
+<path fill="none" stroke="black" d="M294,-450.888C294,-443.071 294,-395.922 294,-370.019"/>
+</g>
+<!-- s6 -->
+<g id="node19" class="node"><title>s6</title>
+<ellipse fill="black" stroke="black" cx="294" cy="-263" rx="1.8" ry="1.8"/>
+</g>
+<!-- s5&#45;&gt;s6 -->
+<g id="edge28" class="edge"><title>s5&#45;&gt;s6</title>
+<path fill="none" stroke="black" d="M294,-333.812C294,-310.834 294,-272.168 294,-265.12"/>
+</g>
+<!-- m6 -->
+<g id="node21" class="node"><title>m6</title>
+<polygon fill="lightgrey" stroke="lightgrey" points="325.5,-228.5 486.5,-228.5 498.5,-240.5 498.5,-285.5 486.5,-297.5 325.5,-297.5 313.5,-285.5 313.5,-240.5 325.5,-228.5"/>
+<path fill="lightgrey" stroke="lightgrey" d="M486.5,-228.5C492.5,-228.5 498.5,-234.5 498.5,-240.5"/>
+<path fill="lightgrey" stroke="lightgrey" d="M498.5,-285.5C498.5,-291.5 492.5,-297.5 486.5,-297.5"/>
+<path fill="lightgrey" stroke="lightgrey" d="M325.5,-297.5C319.5,-297.5 313.5,-291.5 313.5,-285.5"/>
+<path fill="lightgrey" stroke="lightgrey" d="M313.5,-240.5C313.5,-234.5 319.5,-228.5 325.5,-228.5"/>
+<polyline fill="none" stroke="black" points="325.5,-228.5 486.5,-228.5 "/>
+<path fill="none" stroke="black" d="M486.5,-228.5C492.5,-228.5 498.5,-234.5 498.5,-240.5"/>
+<polyline fill="none" stroke="black" points="498.5,-240.5 498.5,-285.5 "/>
+<path fill="none" stroke="black" d="M498.5,-285.5C498.5,-291.5 492.5,-297.5 486.5,-297.5"/>
+<polyline fill="none" stroke="black" points="486.5,-297.5 325.5,-297.5 "/>
+<path fill="none" stroke="black" d="M325.5,-297.5C319.5,-297.5 313.5,-291.5 313.5,-285.5"/>
+<polyline fill="none" stroke="black" points="313.5,-285.5 313.5,-240.5 "/>
+<path fill="none" stroke="black" d="M313.5,-240.5C313.5,-234.5 319.5,-228.5 325.5,-228.5"/>
+<text text-anchor="middle" x="406" y="-282.3" font-family="Helvetica,sans-Serif" font-size="14.00">Client Handle</text>
+<polyline fill="none" stroke="black" points="313.5,-274.5 498.5,-274.5 "/>
+<text text-anchor="middle" x="406" y="-259.3" font-family="Helvetica,sans-Serif" font-size="14.00">Client BPKI TA</text>
+<polyline fill="none" stroke="black" points="313.5,-251.5 498.5,-251.5 "/>
+<text text-anchor="middle" x="406" y="-236.3" font-family="Helvetica,sans-Serif" font-size="14.00">Hint From Parent (Optional)</text>
+</g>
+<!-- s6&#45;&gt;m6 -->
+<g id="edge12" class="edge"><title>s6&#45;&gt;m6</title>
+<path fill="none" stroke="black" d="M296.188,-263C298.511,-263 300.835,-263 303.158,-263"/>
+<polygon fill="black" stroke="black" points="313.346,-263 303.346,-267.5 308.346,-263 303.346,-263 303.346,-263 303.346,-263 308.346,-263 303.346,-258.5 313.346,-263 313.346,-263"/>
+</g>
+<!-- s8 -->
+<g id="node25" class="node"><title>s8</title>
+<ellipse fill="black" stroke="black" cx="294" cy="-96" rx="1.8" ry="1.8"/>
+</g>
+<!-- s6&#45;&gt;s8 -->
+<g id="edge41" class="edge"><title>s6&#45;&gt;s8</title>
+<path fill="none" stroke="lightgray" stroke-dasharray="5,2" d="M294,-260.946C294,-247.553 294,-110.754 294,-97.9586"/>
+</g>
+<!-- m6&#45;&gt;r6 -->
+<g id="edge13" class="edge"><title>m6&#45;&gt;r6</title>
+<path fill="none" stroke="black" d="M498.75,-263C501.203,-263 503.656,-263 506.11,-263"/>
+<polygon fill="black" stroke="black" points="516.195,-263 506.195,-267.5 511.195,-263 506.195,-263 506.195,-263 506.195,-263 511.195,-263 506.195,-258.5 516.195,-263 516.195,-263"/>
+</g>
+<!-- r7 -->
+<g id="node23" class="node"><title>r7</title>
+<polygon fill="limegreen" stroke="limegreen" points="621.5,-192 414.5,-192 402.5,-180 402.5,-168 414.5,-156 621.5,-156 633.5,-168 633.5,-180 621.5,-192"/>
+<path fill="limegreen" stroke="limegreen" d="M414.5,-192C408.5,-192 402.5,-186 402.5,-180"/>
+<path fill="limegreen" stroke="limegreen" d="M402.5,-168C402.5,-162 408.5,-156 414.5,-156"/>
+<path fill="limegreen" stroke="limegreen" d="M621.5,-156C627.5,-156 633.5,-162 633.5,-168"/>
+<path fill="limegreen" stroke="limegreen" d="M633.5,-180C633.5,-186 627.5,-192 621.5,-192"/>
+<polyline fill="none" stroke="black" points="621.5,-192 414.5,-192 "/>
+<path fill="none" stroke="black" d="M414.5,-192C408.5,-192 402.5,-186 402.5,-180"/>
+<polyline fill="none" stroke="black" points="402.5,-180 402.5,-168 "/>
+<path fill="none" stroke="black" d="M402.5,-168C402.5,-162 408.5,-156 414.5,-156"/>
+<polyline fill="none" stroke="black" points="414.5,-156 621.5,-156 "/>
+<path fill="none" stroke="black" d="M621.5,-156C627.5,-156 633.5,-162 633.5,-168"/>
+<polyline fill="none" stroke="black" points="633.5,-168 633.5,-180 "/>
+<path fill="none" stroke="black" d="M633.5,-180C633.5,-186 627.5,-192 621.5,-192"/>
+<text text-anchor="middle" x="518" y="-170.3" font-family="Helvetica,sans-Serif" font-size="14.00">rpkic&gt; configure_publication_client</text>
+</g>
+<!-- r6&#45;&gt;r7 -->
+<g id="edge30" class="edge"><title>r6&#45;&gt;r7</title>
+<path fill="none" stroke="black" d="M518,-261.023C518,-254.377 518,-215.385 518,-192.24"/>
+</g>
+<!-- r8 -->
+<g id="node28" class="node"><title>r8</title>
+<ellipse fill="black" stroke="black" cx="518" cy="-96" rx="1.8" ry="1.8"/>
+</g>
+<!-- r7&#45;&gt;r8 -->
+<g id="edge31" class="edge"><title>r7&#45;&gt;r8</title>
+<path fill="none" stroke="black" d="M518,-155.754C518,-135.433 518,-103.69 518,-97.9166"/>
+</g>
+<!-- m8 -->
+<g id="node27" class="node"><title>m8</title>
+<polygon fill="lightgrey" stroke="lightgrey" points="335.5,-73 476.5,-73 488.5,-85 488.5,-107 476.5,-119 335.5,-119 323.5,-107 323.5,-85 335.5,-73"/>
+<path fill="lightgrey" stroke="lightgrey" d="M476.5,-73C482.5,-73 488.5,-79 488.5,-85"/>
+<path fill="lightgrey" stroke="lightgrey" d="M488.5,-107C488.5,-113 482.5,-119 476.5,-119"/>
+<path fill="lightgrey" stroke="lightgrey" d="M335.5,-119C329.5,-119 323.5,-113 323.5,-107"/>
+<path fill="lightgrey" stroke="lightgrey" d="M323.5,-85C323.5,-79 329.5,-73 335.5,-73"/>
+<polyline fill="none" stroke="black" points="335.5,-73 476.5,-73 "/>
+<path fill="none" stroke="black" d="M476.5,-73C482.5,-73 488.5,-79 488.5,-85"/>
+<polyline fill="none" stroke="black" points="488.5,-85 488.5,-107 "/>
+<path fill="none" stroke="black" d="M488.5,-107C488.5,-113 482.5,-119 476.5,-119"/>
+<polyline fill="none" stroke="black" points="476.5,-119 335.5,-119 "/>
+<path fill="none" stroke="black" d="M335.5,-119C329.5,-119 323.5,-113 323.5,-107"/>
+<polyline fill="none" stroke="black" points="323.5,-107 323.5,-85 "/>
+<path fill="none" stroke="black" d="M323.5,-85C323.5,-79 329.5,-73 335.5,-73"/>
+<text text-anchor="middle" x="406" y="-103.8" font-family="Helvetica,sans-Serif" font-size="14.00">Repository BPKI TA</text>
+<polyline fill="none" stroke="black" points="323.5,-96 488.5,-96 "/>
+<text text-anchor="middle" x="406" y="-80.8" font-family="Helvetica,sans-Serif" font-size="14.00">Repository Service URL</text>
+</g>
+<!-- s8&#45;&gt;m8 -->
+<g id="edge16" class="edge"><title>s8&#45;&gt;m8</title>
+<path fill="none" stroke="black" d="M306.322,-96C311.952,-96 317.582,-96 323.212,-96"/>
+<polygon fill="black" stroke="black" points="296.188,-96 306.188,-91.5001 301.188,-96 306.188,-96.0001 306.188,-96.0001 306.188,-96.0001 301.188,-96 306.187,-100.5 296.188,-96 296.188,-96"/>
+</g>
+<!-- s9 -->
+<g id="node29" class="node"><title>s9</title>
+<polygon fill="cornflowerblue" stroke="cornflowerblue" points="375.25,-36 212.75,-36 200.75,-24 200.75,-12 212.75,-0 375.25,-0 387.25,-12 387.25,-24 375.25,-36"/>
+<path fill="cornflowerblue" stroke="cornflowerblue" d="M212.75,-36C206.75,-36 200.75,-30 200.75,-24"/>
+<path fill="cornflowerblue" stroke="cornflowerblue" d="M200.75,-12C200.75,-6 206.75,-0 212.75,-0"/>
+<path fill="cornflowerblue" stroke="cornflowerblue" d="M375.25,-0C381.25,-0 387.25,-6 387.25,-12"/>
+<path fill="cornflowerblue" stroke="cornflowerblue" d="M387.25,-24C387.25,-30 381.25,-36 375.25,-36"/>
+<polyline fill="none" stroke="black" points="375.25,-36 212.75,-36 "/>
+<path fill="none" stroke="black" d="M212.75,-36C206.75,-36 200.75,-30 200.75,-24"/>
+<polyline fill="none" stroke="black" points="200.75,-24 200.75,-12 "/>
+<path fill="none" stroke="black" d="M200.75,-12C200.75,-6 206.75,-0 212.75,-0"/>
+<polyline fill="none" stroke="black" points="212.75,-0 375.25,-0 "/>
+<path fill="none" stroke="black" d="M375.25,-0C381.25,-0 387.25,-6 387.25,-12"/>
+<polyline fill="none" stroke="black" points="387.25,-12 387.25,-24 "/>
+<path fill="none" stroke="black" d="M387.25,-24C387.25,-30 381.25,-36 375.25,-36"/>
+<text text-anchor="middle" x="294" y="-14.3" font-family="Helvetica,sans-Serif" font-size="14.00">rpkic&gt; configure_repository</text>
+</g>
+<!-- s8&#45;&gt;s9 -->
+<g id="edge33" class="edge"><title>s8&#45;&gt;s9</title>
+<path fill="none" stroke="black" d="M294,-94.1465C294,-88.5366 294,-56.5427 294,-36.1506"/>
+</g>
+<!-- m8&#45;&gt;r8 -->
+<g id="edge17" class="edge"><title>m8&#45;&gt;r8</title>
+<path fill="none" stroke="black" d="M498.993,-96C504.718,-96 510.443,-96 516.168,-96"/>
+<polygon fill="black" stroke="black" points="488.688,-96 498.688,-91.5001 493.688,-96 498.688,-96.0001 498.688,-96.0001 498.688,-96.0001 493.688,-96 498.687,-100.5 488.688,-96 488.688,-96"/>
+</g>
+</g>
+</svg>
diff --git a/doc/manual/38.RPKI.Protocols.OOB.md b/doc/manual/38.RPKI.Protocols.OOB.md
new file mode 100644
index 00000000..5fd64b52
--- /dev/null
+++ b/doc/manual/38.RPKI.Protocols.OOB.md
@@ -0,0 +1,15 @@
+# The RPKI Out-Of-Band Setup Protocol
+
+This protocol configures the initial URLs and BPKI certificates needed to
+operate the up-down and publication protocols. This is not an IETF standard of
+any kind. The rpki.net code is, as far as we know, the only complete
+implementation of this protocol, but other RPKI CA packages implement portions
+of it for interoperability.
+
+In the long run we intend to clean this up and submit the cleaned-up version
+as a candidate for IETF standardization, since it seems to be in everyone's
+best interests, but we're not there yet.
+
+![][OOB]
+
+[OOB]: 38.RPKI.Protocols.OOB.00.svg
diff --git a/doc/manual/38.RPKI.Protocols.OOB.wiki b/doc/manual/38.RPKI.Protocols.OOB.wiki
new file mode 100644
index 00000000..7e6e77ea
--- /dev/null
+++ b/doc/manual/38.RPKI.Protocols.OOB.wiki
@@ -0,0 +1,15 @@
+= The RPKI Out-Of-Band Setup Protocol =
+
+[[TracNav(doc/RPKI/TOC)]]
+
+This protocol configures the initial URLs and BPKI certificates needed
+to operate the up-down and publication protocols. This is not an IETF
+standard of any kind. The rpki.net code is, as far as we know, the
+only complete implementation of this protocol, but other RPKI CA
+packages implement portions of it for interoperability.
+
+In the long run we intend to clean this up and submit the cleaned-up
+version as a candidate for IETF standardization, since it seems to be
+in everyone's best interests, but we're not there yet.
+
+[[Image(oob-setup.svg)]]
diff --git a/doc/manual/38.RPKI.Protocols.OOB.zip b/doc/manual/38.RPKI.Protocols.OOB.zip
new file mode 100644
index 00000000..7c90862c
--- /dev/null
+++ b/doc/manual/38.RPKI.Protocols.OOB.zip
Binary files differ
diff --git a/doc/manual/39.RPKI.Protocols.Up-Down.00.svg b/doc/manual/39.RPKI.Protocols.Up-Down.00.svg
new file mode 100644
index 00000000..8fda40d5
--- /dev/null
+++ b/doc/manual/39.RPKI.Protocols.Up-Down.00.svg
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.28.0 (20110821.1312)
+ -->
+<!-- Title: ladder_oob Pages: 1 -->
+<svg width="307pt" height="612pt"
+ viewBox="0.00 0.00 307.00 612.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph1" class="graph" transform="scale(1 1) rotate(0) translate(4 608)">
+<title>ladder_oob</title>
+<polygon fill="white" stroke="white" points="-4,5 -4,-608 304,-608 304,5 -4,5"/>
+<!-- i0 -->
+<g id="node2" class="node"><title>i0</title>
+<polygon fill="deeppink" stroke="black" points="-0.220083,-560.67 56,-537.572 112.22,-560.67 112.168,-598.044 -0.167608,-598.044 -0.220083,-560.67"/>
+<text text-anchor="middle" x="56" y="-574.8" font-family="Helvetica,sans-Serif" font-size="14.00">Issuer</text>
+<text text-anchor="middle" x="56" y="-559.8" font-family="Helvetica,sans-Serif" font-size="14.00">(Parent)</text>
+</g>
+<!-- s0 -->
+<g id="node3" class="node"><title>s0</title>
+<polygon fill="cornflowerblue" stroke="black" points="186.78,-560.67 243,-537.572 299.22,-560.67 299.168,-598.044 186.832,-598.044 186.78,-560.67"/>
+<text text-anchor="middle" x="243" y="-574.8" font-family="Helvetica,sans-Serif" font-size="14.00">Subject</text>
+<text text-anchor="middle" x="243" y="-559.8" font-family="Helvetica,sans-Serif" font-size="14.00">(Child)</text>
+</g>
+<!-- i0&#45;&gt;s0 -->
+<!-- i1 -->
+<g id="node5" class="node"><title>i1</title>
+<ellipse fill="black" stroke="black" cx="56" cy="-483" rx="1.8" ry="1.8"/>
+</g>
+<!-- i0&#45;&gt;i1 -->
+<g id="edge41" class="edge"><title>i0&#45;&gt;i1</title>
+<path fill="none" stroke="lightgray" stroke-dasharray="5,2" d="M56,-537.487C56,-516.178 56,-491.209 56,-485.299"/>
+</g>
+<!-- s1 -->
+<g id="node8" class="node"><title>s1</title>
+<ellipse fill="thistle" stroke="thistle" cx="243" cy="-483" rx="30.3206" ry="18"/>
+<text text-anchor="middle" x="243" y="-479.3" font-family="Helvetica,sans-Serif" font-size="14.00">Start</text>
+</g>
+<!-- s0&#45;&gt;s1 -->
+<g id="edge43" class="edge"><title>s0&#45;&gt;s1</title>
+<path fill="none" stroke="lightgray" stroke-dasharray="5,2" d="M243,-537.487C243,-525.12 243,-511.52 243,-501.129"/>
+</g>
+<!-- m1 -->
+<g id="node7" class="node"><title>m1</title>
+<polygon fill="lightgrey" stroke="lightgrey" points="120,-465 150,-465 162,-477 162,-489 150,-501 120,-501 108,-489 108,-477 120,-465"/>
+<path fill="lightgrey" stroke="lightgrey" d="M150,-465C156,-465 162,-471 162,-477"/>
+<path fill="lightgrey" stroke="lightgrey" d="M162,-489C162,-495 156,-501 150,-501"/>
+<path fill="lightgrey" stroke="lightgrey" d="M120,-501C114,-501 108,-495 108,-489"/>
+<path fill="lightgrey" stroke="lightgrey" d="M108,-477C108,-471 114,-465 120,-465"/>
+<polyline fill="none" stroke="black" points="120,-465 150,-465 "/>
+<path fill="none" stroke="black" d="M150,-465C156,-465 162,-471 162,-477"/>
+<polyline fill="none" stroke="black" points="162,-477 162,-489 "/>
+<path fill="none" stroke="black" d="M162,-489C162,-495 156,-501 150,-501"/>
+<polyline fill="none" stroke="black" points="150,-501 120,-501 "/>
+<path fill="none" stroke="black" d="M120,-501C114,-501 108,-495 108,-489"/>
+<polyline fill="none" stroke="black" points="108,-489 108,-477 "/>
+<path fill="none" stroke="black" d="M108,-477C108,-471 114,-465 120,-465"/>
+<text text-anchor="middle" x="135" y="-479.3" font-family="Helvetica,sans-Serif" font-size="14.00">List</text>
+</g>
+<!-- i1&#45;&gt;m1 -->
+<g id="edge4" class="edge"><title>i1&#45;&gt;m1</title>
+<path fill="none" stroke="black" d="M68.0131,-483C81.3012,-483 94.5894,-483 107.878,-483"/>
+<polygon fill="black" stroke="black" points="57.8516,-483 67.8516,-478.5 62.8516,-483 67.8516,-483 67.8516,-483 67.8516,-483 62.8516,-483 67.8515,-487.5 57.8516,-483 57.8516,-483"/>
+</g>
+<!-- i2 -->
+<g id="node10" class="node"><title>i2</title>
+<ellipse fill="black" stroke="black" cx="56" cy="-404" rx="1.8" ry="1.8"/>
+</g>
+<!-- i1&#45;&gt;i2 -->
+<g id="edge31" class="edge"><title>i1&#45;&gt;i2</title>
+<path fill="none" stroke="black" d="M56,-481.135C56,-473.271 56,-414.224 56,-405.96"/>
+</g>
+<!-- m1&#45;&gt;s1 -->
+<g id="edge5" class="edge"><title>m1&#45;&gt;s1</title>
+<path fill="none" stroke="black" d="M172.588,-483C185.881,-483 199.175,-483 212.468,-483"/>
+<polygon fill="black" stroke="black" points="162.422,-483 172.422,-478.5 167.422,-483 172.422,-483 172.422,-483 172.422,-483 167.422,-483 172.422,-487.5 162.422,-483 162.422,-483"/>
+</g>
+<!-- s2 -->
+<g id="node13" class="node"><title>s2</title>
+<ellipse fill="black" stroke="black" cx="243" cy="-404" rx="1.8" ry="1.8"/>
+</g>
+<!-- s1&#45;&gt;s2 -->
+<g id="edge45" class="edge"><title>s1&#45;&gt;s2</title>
+<path fill="none" stroke="lightgray" stroke-dasharray="5,2" d="M243,-464.911C243,-444.353 243,-411.852 243,-405.939"/>
+</g>
+<!-- m2 -->
+<g id="node12" class="node"><title>m2</title>
+<polygon fill="lightgrey" stroke="lightgrey" points="110,-381 190,-381 202,-393 202,-415 190,-427 110,-427 98,-415 98,-393 110,-381"/>
+<path fill="lightgrey" stroke="lightgrey" d="M190,-381C196,-381 202,-387 202,-393"/>
+<path fill="lightgrey" stroke="lightgrey" d="M202,-415C202,-421 196,-427 190,-427"/>
+<path fill="lightgrey" stroke="lightgrey" d="M110,-427C104,-427 98,-421 98,-415"/>
+<path fill="lightgrey" stroke="lightgrey" d="M98,-393C98,-387 104,-381 110,-381"/>
+<polyline fill="none" stroke="black" points="110,-381 190,-381 "/>
+<path fill="none" stroke="black" d="M190,-381C196,-381 202,-387 202,-393"/>
+<polyline fill="none" stroke="black" points="202,-393 202,-415 "/>
+<path fill="none" stroke="black" d="M202,-415C202,-421 196,-427 190,-427"/>
+<polyline fill="none" stroke="black" points="190,-427 110,-427 "/>
+<path fill="none" stroke="black" d="M110,-427C104,-427 98,-421 98,-415"/>
+<polyline fill="none" stroke="black" points="98,-415 98,-393 "/>
+<path fill="none" stroke="black" d="M98,-393C98,-387 104,-381 110,-381"/>
+<text text-anchor="middle" x="150" y="-411.8" font-family="Helvetica,sans-Serif" font-size="14.00">List Response</text>
+<polyline fill="none" stroke="black" points="98,-404 202,-404 "/>
+<text text-anchor="middle" x="150" y="-388.8" font-family="Helvetica,sans-Serif" font-size="14.00">Classes A, B</text>
+</g>
+<!-- i2&#45;&gt;m2 -->
+<g id="edge8" class="edge"><title>i2&#45;&gt;m2</title>
+<path fill="none" stroke="black" d="M57.8359,-404C67.7223,-404 77.6087,-404 87.4951,-404"/>
+<polygon fill="black" stroke="black" points="97.7977,-404 87.7977,-408.5 92.7977,-404 87.7977,-404 87.7977,-404 87.7977,-404 92.7977,-404 87.7977,-399.5 97.7977,-404 97.7977,-404"/>
+</g>
+<!-- i3 -->
+<g id="node15" class="node"><title>i3</title>
+<ellipse fill="black" stroke="black" cx="56" cy="-320" rx="1.8" ry="1.8"/>
+</g>
+<!-- i2&#45;&gt;i3 -->
+<g id="edge47" class="edge"><title>i2&#45;&gt;i3</title>
+<path fill="none" stroke="lightgray" stroke-dasharray="5,2" d="M56,-402.079C56,-393.633 56,-329.762 56,-321.812"/>
+</g>
+<!-- m2&#45;&gt;s2 -->
+<g id="edge9" class="edge"><title>m2&#45;&gt;s2</title>
+<path fill="none" stroke="black" d="M202.312,-404C211.806,-404 221.299,-404 230.792,-404"/>
+<polygon fill="black" stroke="black" points="241.093,-404 231.093,-408.5 236.093,-404 231.093,-404 231.093,-404 231.093,-404 236.093,-404 231.093,-399.5 241.093,-404 241.093,-404"/>
+</g>
+<!-- s3 -->
+<g id="node18" class="node"><title>s3</title>
+<ellipse fill="black" stroke="black" cx="243" cy="-320" rx="1.8" ry="1.8"/>
+</g>
+<!-- s2&#45;&gt;s3 -->
+<g id="edge33" class="edge"><title>s2&#45;&gt;s3</title>
+<path fill="none" stroke="black" d="M243,-402.079C243,-393.633 243,-329.762 243,-321.812"/>
+</g>
+<!-- m3 -->
+<g id="node17" class="node"><title>m3</title>
+<polygon fill="lightgrey" stroke="lightgrey" points="130.5,-297 169.5,-297 181.5,-309 181.5,-331 169.5,-343 130.5,-343 118.5,-331 118.5,-309 130.5,-297"/>
+<path fill="lightgrey" stroke="lightgrey" d="M169.5,-297C175.5,-297 181.5,-303 181.5,-309"/>
+<path fill="lightgrey" stroke="lightgrey" d="M181.5,-331C181.5,-337 175.5,-343 169.5,-343"/>
+<path fill="lightgrey" stroke="lightgrey" d="M130.5,-343C124.5,-343 118.5,-337 118.5,-331"/>
+<path fill="lightgrey" stroke="lightgrey" d="M118.5,-309C118.5,-303 124.5,-297 130.5,-297"/>
+<polyline fill="none" stroke="black" points="130.5,-297 169.5,-297 "/>
+<path fill="none" stroke="black" d="M169.5,-297C175.5,-297 181.5,-303 181.5,-309"/>
+<polyline fill="none" stroke="black" points="181.5,-309 181.5,-331 "/>
+<path fill="none" stroke="black" d="M181.5,-331C181.5,-337 175.5,-343 169.5,-343"/>
+<polyline fill="none" stroke="black" points="169.5,-343 130.5,-343 "/>
+<path fill="none" stroke="black" d="M130.5,-343C124.5,-343 118.5,-337 118.5,-331"/>
+<polyline fill="none" stroke="black" points="118.5,-331 118.5,-309 "/>
+<path fill="none" stroke="black" d="M118.5,-309C118.5,-303 124.5,-297 130.5,-297"/>
+<text text-anchor="middle" x="150" y="-327.8" font-family="Helvetica,sans-Serif" font-size="14.00">Issue</text>
+<polyline fill="none" stroke="black" points="118.5,-320 181.5,-320 "/>
+<text text-anchor="middle" x="150" y="-304.8" font-family="Helvetica,sans-Serif" font-size="14.00">Class A</text>
+</g>
+<!-- i3&#45;&gt;m3 -->
+<g id="edge12" class="edge"><title>i3&#45;&gt;m3</title>
+<path fill="none" stroke="black" d="M68.2314,-320C84.9271,-320 101.623,-320 118.319,-320"/>
+<polygon fill="black" stroke="black" points="57.8359,-320 67.836,-315.5 62.8359,-320 67.8359,-320 67.8359,-320 67.8359,-320 62.8359,-320 67.8359,-324.5 57.8359,-320 57.8359,-320"/>
+</g>
+<!-- i4 -->
+<g id="node20" class="node"><title>i4</title>
+<ellipse fill="black" stroke="black" cx="56" cy="-225" rx="1.8" ry="1.8"/>
+</g>
+<!-- i3&#45;&gt;i4 -->
+<g id="edge35" class="edge"><title>i3&#45;&gt;i4</title>
+<path fill="none" stroke="black" d="M56,-317.956C56,-308.377 56,-235.938 56,-226.92"/>
+</g>
+<!-- m3&#45;&gt;s3 -->
+<g id="edge13" class="edge"><title>m3&#45;&gt;s3</title>
+<path fill="none" stroke="black" d="M191.828,-320C208.246,-320 224.664,-320 241.081,-320"/>
+<polygon fill="black" stroke="black" points="181.605,-320 191.606,-315.5 186.605,-320 191.605,-320 191.605,-320 191.605,-320 186.605,-320 191.605,-324.5 181.605,-320 181.605,-320"/>
+</g>
+<!-- s4 -->
+<g id="node23" class="node"><title>s4</title>
+<ellipse fill="black" stroke="black" cx="243" cy="-225" rx="1.8" ry="1.8"/>
+</g>
+<!-- s3&#45;&gt;s4 -->
+<g id="edge49" class="edge"><title>s3&#45;&gt;s4</title>
+<path fill="none" stroke="lightgray" stroke-dasharray="5,2" d="M243,-317.956C243,-308.377 243,-235.938 243,-226.92"/>
+</g>
+<!-- m4 -->
+<g id="node22" class="node"><title>m4</title>
+<polygon fill="lightgrey" stroke="lightgrey" points="104.5,-190.5 195.5,-190.5 207.5,-202.5 207.5,-247.5 195.5,-259.5 104.5,-259.5 92.5,-247.5 92.5,-202.5 104.5,-190.5"/>
+<path fill="lightgrey" stroke="lightgrey" d="M195.5,-190.5C201.5,-190.5 207.5,-196.5 207.5,-202.5"/>
+<path fill="lightgrey" stroke="lightgrey" d="M207.5,-247.5C207.5,-253.5 201.5,-259.5 195.5,-259.5"/>
+<path fill="lightgrey" stroke="lightgrey" d="M104.5,-259.5C98.5,-259.5 92.5,-253.5 92.5,-247.5"/>
+<path fill="lightgrey" stroke="lightgrey" d="M92.5,-202.5C92.5,-196.5 98.5,-190.5 104.5,-190.5"/>
+<polyline fill="none" stroke="black" points="104.5,-190.5 195.5,-190.5 "/>
+<path fill="none" stroke="black" d="M195.5,-190.5C201.5,-190.5 207.5,-196.5 207.5,-202.5"/>
+<polyline fill="none" stroke="black" points="207.5,-202.5 207.5,-247.5 "/>
+<path fill="none" stroke="black" d="M207.5,-247.5C207.5,-253.5 201.5,-259.5 195.5,-259.5"/>
+<polyline fill="none" stroke="black" points="195.5,-259.5 104.5,-259.5 "/>
+<path fill="none" stroke="black" d="M104.5,-259.5C98.5,-259.5 92.5,-253.5 92.5,-247.5"/>
+<polyline fill="none" stroke="black" points="92.5,-247.5 92.5,-202.5 "/>
+<path fill="none" stroke="black" d="M92.5,-202.5C92.5,-196.5 98.5,-190.5 104.5,-190.5"/>
+<text text-anchor="middle" x="150" y="-244.3" font-family="Helvetica,sans-Serif" font-size="14.00">Issue Response</text>
+<polyline fill="none" stroke="black" points="92.5,-236.5 207.5,-236.5 "/>
+<text text-anchor="middle" x="150" y="-221.3" font-family="Helvetica,sans-Serif" font-size="14.00">Class A</text>
+<polyline fill="none" stroke="black" points="92.5,-213.5 207.5,-213.5 "/>
+<text text-anchor="middle" x="150" y="-198.3" font-family="Helvetica,sans-Serif" font-size="14.00">Certificate</text>
+</g>
+<!-- i4&#45;&gt;m4 -->
+<g id="edge16" class="edge"><title>i4&#45;&gt;m4</title>
+<path fill="none" stroke="black" d="M57.8359,-225C65.9363,-225 74.0367,-225 82.137,-225"/>
+<polygon fill="black" stroke="black" points="92.3975,-225 82.3975,-229.5 87.3975,-225 82.3975,-225 82.3975,-225 82.3975,-225 87.3975,-225 82.3974,-220.5 92.3975,-225 92.3975,-225"/>
+</g>
+<!-- i5 -->
+<g id="node25" class="node"><title>i5</title>
+<ellipse fill="black" stroke="black" cx="56" cy="-130" rx="1.8" ry="1.8"/>
+</g>
+<!-- i4&#45;&gt;i5 -->
+<g id="edge51" class="edge"><title>i4&#45;&gt;i5</title>
+<path fill="none" stroke="lightgray" stroke-dasharray="5,2" d="M56,-222.956C56,-213.377 56,-140.938 56,-131.92"/>
+</g>
+<!-- m4&#45;&gt;s4 -->
+<g id="edge17" class="edge"><title>m4&#45;&gt;s4</title>
+<path fill="none" stroke="black" d="M207.762,-225C215.482,-225 223.203,-225 230.923,-225"/>
+<polygon fill="black" stroke="black" points="241.073,-225 231.073,-229.5 236.073,-225 231.073,-225 231.073,-225 231.073,-225 236.073,-225 231.073,-220.5 241.073,-225 241.073,-225"/>
+</g>
+<!-- s5 -->
+<g id="node28" class="node"><title>s5</title>
+<ellipse fill="black" stroke="black" cx="243" cy="-130" rx="1.8" ry="1.8"/>
+</g>
+<!-- s4&#45;&gt;s5 -->
+<g id="edge37" class="edge"><title>s4&#45;&gt;s5</title>
+<path fill="none" stroke="black" d="M243,-222.956C243,-213.377 243,-140.938 243,-131.92"/>
+</g>
+<!-- m5 -->
+<g id="node27" class="node"><title>m5</title>
+<polygon fill="lightgrey" stroke="lightgrey" points="130,-107 170,-107 182,-119 182,-141 170,-153 130,-153 118,-141 118,-119 130,-107"/>
+<path fill="lightgrey" stroke="lightgrey" d="M170,-107C176,-107 182,-113 182,-119"/>
+<path fill="lightgrey" stroke="lightgrey" d="M182,-141C182,-147 176,-153 170,-153"/>
+<path fill="lightgrey" stroke="lightgrey" d="M130,-153C124,-153 118,-147 118,-141"/>
+<path fill="lightgrey" stroke="lightgrey" d="M118,-119C118,-113 124,-107 130,-107"/>
+<polyline fill="none" stroke="black" points="130,-107 170,-107 "/>
+<path fill="none" stroke="black" d="M170,-107C176,-107 182,-113 182,-119"/>
+<polyline fill="none" stroke="black" points="182,-119 182,-141 "/>
+<path fill="none" stroke="black" d="M182,-141C182,-147 176,-153 170,-153"/>
+<polyline fill="none" stroke="black" points="170,-153 130,-153 "/>
+<path fill="none" stroke="black" d="M130,-153C124,-153 118,-147 118,-141"/>
+<polyline fill="none" stroke="black" points="118,-141 118,-119 "/>
+<path fill="none" stroke="black" d="M118,-119C118,-113 124,-107 130,-107"/>
+<text text-anchor="middle" x="150" y="-137.8" font-family="Helvetica,sans-Serif" font-size="14.00">Issue</text>
+<polyline fill="none" stroke="black" points="118,-130 182,-130 "/>
+<text text-anchor="middle" x="150" y="-114.8" font-family="Helvetica,sans-Serif" font-size="14.00">Class B</text>
+</g>
+<!-- i5&#45;&gt;m5 -->
+<g id="edge20" class="edge"><title>i5&#45;&gt;m5</title>
+<path fill="none" stroke="black" d="M68.1695,-130C84.7659,-130 101.362,-130 117.959,-130"/>
+<polygon fill="black" stroke="black" points="57.8359,-130 67.836,-125.5 62.8359,-130 67.8359,-130 67.8359,-130 67.8359,-130 62.8359,-130 67.8359,-134.5 57.8359,-130 57.8359,-130"/>
+</g>
+<!-- i6 -->
+<g id="node30" class="node"><title>i6</title>
+<ellipse fill="black" stroke="black" cx="56" cy="-35" rx="1.8" ry="1.8"/>
+</g>
+<!-- i5&#45;&gt;i6 -->
+<g id="edge39" class="edge"><title>i5&#45;&gt;i6</title>
+<path fill="none" stroke="black" d="M56,-127.956C56,-118.377 56,-45.9379 56,-36.9205"/>
+</g>
+<!-- m5&#45;&gt;s5 -->
+<g id="edge21" class="edge"><title>m5&#45;&gt;s5</title>
+<path fill="none" stroke="black" d="M192.433,-130C208.657,-130 224.881,-130 241.104,-130"/>
+<polygon fill="black" stroke="black" points="182.332,-130 192.332,-125.5 187.332,-130 192.332,-130 192.332,-130 192.332,-130 187.332,-130 192.332,-134.5 182.332,-130 182.332,-130"/>
+</g>
+<!-- s6 -->
+<g id="node33" class="node"><title>s6</title>
+<ellipse fill="thistle" stroke="thistle" cx="243" cy="-35" rx="34.1708" ry="18"/>
+<text text-anchor="middle" x="243" y="-31.3" font-family="Helvetica,sans-Serif" font-size="14.00">Sleep</text>
+</g>
+<!-- s5&#45;&gt;s6 -->
+<g id="edge53" class="edge"><title>s5&#45;&gt;s6</title>
+<path fill="none" stroke="lightgray" stroke-dasharray="5,2" d="M243,-127.956C243,-120.732 243,-77.7548 243,-53.1931"/>
+</g>
+<!-- m6 -->
+<g id="node32" class="node"><title>m6</title>
+<polygon fill="lightgrey" stroke="lightgrey" points="87.5,-0.5 178.5,-0.5 190.5,-12.5 190.5,-57.5 178.5,-69.5 87.5,-69.5 75.5,-57.5 75.5,-12.5 87.5,-0.5"/>
+<path fill="lightgrey" stroke="lightgrey" d="M178.5,-0.5C184.5,-0.5 190.5,-6.5 190.5,-12.5"/>
+<path fill="lightgrey" stroke="lightgrey" d="M190.5,-57.5C190.5,-63.5 184.5,-69.5 178.5,-69.5"/>
+<path fill="lightgrey" stroke="lightgrey" d="M87.5,-69.5C81.5,-69.5 75.5,-63.5 75.5,-57.5"/>
+<path fill="lightgrey" stroke="lightgrey" d="M75.5,-12.5C75.5,-6.5 81.5,-0.5 87.5,-0.5"/>
+<polyline fill="none" stroke="black" points="87.5,-0.5 178.5,-0.5 "/>
+<path fill="none" stroke="black" d="M178.5,-0.5C184.5,-0.5 190.5,-6.5 190.5,-12.5"/>
+<polyline fill="none" stroke="black" points="190.5,-12.5 190.5,-57.5 "/>
+<path fill="none" stroke="black" d="M190.5,-57.5C190.5,-63.5 184.5,-69.5 178.5,-69.5"/>
+<polyline fill="none" stroke="black" points="178.5,-69.5 87.5,-69.5 "/>
+<path fill="none" stroke="black" d="M87.5,-69.5C81.5,-69.5 75.5,-63.5 75.5,-57.5"/>
+<polyline fill="none" stroke="black" points="75.5,-57.5 75.5,-12.5 "/>
+<path fill="none" stroke="black" d="M75.5,-12.5C75.5,-6.5 81.5,-0.5 87.5,-0.5"/>
+<text text-anchor="middle" x="133" y="-54.3" font-family="Helvetica,sans-Serif" font-size="14.00">Issue Response</text>
+<polyline fill="none" stroke="black" points="75.5,-46.5 190.5,-46.5 "/>
+<text text-anchor="middle" x="133" y="-31.3" font-family="Helvetica,sans-Serif" font-size="14.00">Class B</text>
+<polyline fill="none" stroke="black" points="75.5,-23.5 190.5,-23.5 "/>
+<text text-anchor="middle" x="133" y="-8.3" font-family="Helvetica,sans-Serif" font-size="14.00">Certificate</text>
+</g>
+<!-- i6&#45;&gt;m6 -->
+<g id="edge24" class="edge"><title>i6&#45;&gt;m6</title>
+<path fill="none" stroke="black" d="M57.8047,-35C60.283,-35 62.7614,-35 65.2398,-35"/>
+<polygon fill="black" stroke="black" points="75.4286,-35 65.4286,-39.5001 70.4286,-35 65.4286,-35.0001 65.4286,-35.0001 65.4286,-35.0001 70.4286,-35 65.4285,-30.5001 75.4286,-35 75.4286,-35"/>
+</g>
+<!-- m6&#45;&gt;s6 -->
+<g id="edge25" class="edge"><title>m6&#45;&gt;s6</title>
+<path fill="none" stroke="black" d="M190.578,-35C193.206,-35 195.834,-35 198.462,-35"/>
+<polygon fill="black" stroke="black" points="208.598,-35 198.598,-39.5001 203.598,-35 198.598,-35.0001 198.598,-35.0001 198.598,-35.0001 203.598,-35 198.598,-30.5001 208.598,-35 208.598,-35"/>
+</g>
+<!-- s6&#45;&gt;s1 -->
+<g id="edge29" class="edge"><title>s6&#45;&gt;s1</title>
+<path fill="none" stroke="black" d="M247.556,-52.9634C255.949,-85.7489 273,-160.21 273,-224 273,-321 273,-321 273,-321 273,-368.769 260.079,-423.182 251.196,-454.943"/>
+<polygon fill="black" stroke="black" points="248.363,-464.804 246.8,-453.95 249.744,-459.998 251.125,-455.193 251.125,-455.193 251.125,-455.193 249.744,-459.998 255.45,-456.436 248.363,-464.804 248.363,-464.804"/>
+</g>
+</g>
+</svg>
diff --git a/doc/manual/39.RPKI.Protocols.Up-Down.md b/doc/manual/39.RPKI.Protocols.Up-Down.md
new file mode 100644
index 00000000..51f2835f
--- /dev/null
+++ b/doc/manual/39.RPKI.Protocols.Up-Down.md
@@ -0,0 +1,8 @@
+# RPKI "Up-Down" Provisioning Protocol
+
+This is the provisioning protocol described in [RFC-6492][].
+
+![][Up-Down]
+
+[RFC-6492]: http://www.rfc-editor.org/rfc/rfc6492.txt
+[Up-Down]: 39.RPKI.Protocols.Up-Down.00.svg
diff --git a/doc/manual/39.RPKI.Protocols.Up-Down.wiki b/doc/manual/39.RPKI.Protocols.Up-Down.wiki
new file mode 100644
index 00000000..ed5fb0a1
--- /dev/null
+++ b/doc/manual/39.RPKI.Protocols.Up-Down.wiki
@@ -0,0 +1,8 @@
+= RPKI "Up-Down" Provisioning Protocol =
+
+[[TracNav(doc/RPKI/TOC)]]
+
+This is the provisioning protocol described in
+[[http://www.rfc-editor.org/rfc/rfc6492.txt|RFC-6492]].
+
+[[Image(up-down.svg)]]
diff --git a/doc/manual/39.RPKI.Protocols.Up-Down.zip b/doc/manual/39.RPKI.Protocols.Up-Down.zip
new file mode 100644
index 00000000..e3cd5fb4
--- /dev/null
+++ b/doc/manual/39.RPKI.Protocols.Up-Down.zip
Binary files differ
diff --git a/doc/manual/README b/doc/manual/README
new file mode 100644
index 00000000..8dc0145e
--- /dev/null
+++ b/doc/manual/README
@@ -0,0 +1,34 @@
+This directory contains documentation salvaged from https://wiki.rpki.net/.
+
+The original source format is Trac wiki, but the Trac instance in
+question is ailing, some of the plug-ins it uses are obsolete, and
+Markdown is more commonly used for this sort of thing these days in
+any case, so extracting this from the ailing Wiki seemed advisable.
+
+The numbered files in this directory were extracted by a Python script
+(included). Several kinds of files are present:
+
+* .wiki files, containing the raw Trac Wiki page text;
+
+* .md files, resulting from feeding the HTML version of the Wiki pages
+ into an automated HTML-to-Markdown translator;
+
+* various graphics formats (.svg, .jpg) holding images which were
+ used inline in some of the Wiki pages; and
+
+* .zip files, containing attachments to the Wiki pages.
+
+In some cases the attachments in the .zip files will be the same as
+the image files, but not always. What you see is what there was.
+
+There are two main problems with this documentation at present:
+
+1. It's for the old version of the RPKI code (branch old-trunk) rather
+ than the current version (branch master).
+
+2. The translation to Markdown almost certainly needs some help from a
+ human being, what's here is just what html2markdown could do.
+
+Nevertheless, the content recorded here was a fairly complete manual
+at one point, and it would almost certainly be a lot easier to finish
+the conversion and bring it up to date than to start over.
diff --git a/doc/manual/pubd-bpki.dot b/doc/manual/pubd-bpki.dot
new file mode 100644
index 00000000..44ad8a90
--- /dev/null
+++ b/doc/manual/pubd-bpki.dot
@@ -0,0 +1,42 @@
+// $Id$
+
+// Color code:
+// Black: Operating entity
+// Red: Cross-certified client
+//
+// Shape code:
+// Octagon: TA
+// Diamond: CA
+// Record: EE
+
+digraph bpki_pubd {
+ splines = true;
+ size = "14,14";
+ node [ fontname = Times, fontsize = 9 ];
+
+ // Operating entity
+ node [ color = black, fontcolor = black, shape = record ];
+ TA [ shape = octagon, label = "BPKI TA" ];
+ pubd [ label = "pubd|{HTTPS server|CMS}" ];
+ ctl [ label = "Control|{HTTPS client|CMS}" ];
+
+ // Clients
+ node [ color = red, fontcolor = red, shape = diamond ];
+ Alice_CA;
+ Bob_CA;
+ node [ color = red, fontcolor = red, shape = record ];
+ Alice_EE [ label = "Alice\nEE|{HTTPS client|CMS}" ];
+ Bob_EE [ label = "Bob\nEE|{HTTPS client|CMS}" ];
+
+ edge [ color = black, style = dotted ];
+ TA -> pubd;
+ TA -> ctl;
+
+ edge [ color = black, style = solid ];
+ TA -> Alice_CA;
+ TA -> Bob_CA;
+
+ edge [ color = red, style = solid ];
+ Alice_CA -> Alice_EE;
+ Bob_CA -> Bob_EE;
+}
diff --git a/doc/manual/rpki-wiki-to-markdown.py b/doc/manual/rpki-wiki-to-markdown.py
new file mode 100644
index 00000000..dff87e6b
--- /dev/null
+++ b/doc/manual/rpki-wiki-to-markdown.py
@@ -0,0 +1,341 @@
+# Copyright (C) 2016 Parsons Government Services ("PARSONS")
+# Portions copyright (C) 2014 Dragon Research Labs ("DRL")
+# Portions copyright (C) 2012 Internet Systems Consortium ("ISC")
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notices and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND PARSONS, DRL, AND ISC DISCLAIM
+# ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# PARSONS, DRL, OR ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+"""
+Trac Wiki -> Markdown converter, hacked from old Trac Wiki -> PDF/flat
+text converter.
+
+Pull HTML pages from a Trac Wiki, feed the useful bits to
+html2text to generate Markdown.
+
+Assumes you're using the TracNav plugin for the Wiki pages, and uses
+the same list as the TracNav plugin does to determine the set of pages
+to convert.
+"""
+
+# Dependencies, at least on Ubuntu Xenial:
+#
+# apt-get install python-lxml python-html2text
+#
+# Be warned that there are many unrelated packages named "html2text",
+# installed under various names on various platforms. This one
+# happens to be a useful HTML-to-Markdown converter.
+
+# Most of the work of massaging the HTML is done using XSL transforms,
+# because the template-driven style makes that easy. There's probably
+# some clever way to use lxml's XPath code to do the same thing in a
+# more pythonic way with ElementTrees, but I already had the XSL
+# transforms and there's a point of diminishing returns on this sort of
+# thing.
+
+import sys
+import os
+import argparse
+import lxml.etree
+import urllib
+import urlparse
+import subprocess
+import zipfile
+
+# Main program, up front so it doesn't get lost under all the XSL
+
+def main():
+
+ base = "https://trac.rpki.net"
+
+ parser = argparse.ArgumentParser(description = __doc__, formatter_class = argparse.ArgumentDefaultsHelpFormatter)
+ parser.add_argument("-b", "--base_url",
+ default = base,
+ help = "base URL for documentation web site")
+ parser.add_argument("-t", "--toc",
+ default = base + "/wiki/doc/RPKI/TOC",
+ help = "table of contents URL")
+ parser.add_argument("-d", "--directory",
+ default = ".",
+ help = "output directory")
+ parser.add_argument("-p", "--prefix",
+ default = "/wiki/doc",
+ help = "page name prefix on wiki")
+ args = parser.parse_args()
+
+ urls = str(xsl_get_toc(lxml.etree.parse(urllib.urlopen(args.toc)).getroot(),
+ basename = repr(args.base_url))).splitlines()
+
+ assert all(urlparse.urlparse(url).path.startswith(args.prefix) for url in urls)
+
+ for pagenum, url in enumerate(urls):
+ path = urlparse.urlparse(url).path
+ page = xsl_get_page(lxml.etree.parse(urllib.urlopen(url)).getroot(),
+ basename = repr(args.base_url),
+ path = repr(path))
+
+ fn_base = os.path.join(args.directory, "{:02d}{}".format(pagenum, path[len(args.prefix):].replace("/", ".")))
+
+ fn = fn_base + ".zip"
+ zip_url = urlparse.urljoin(url, "/zip-attachment{}/".format(path))
+ urllib.urlretrieve(zip_url, fn)
+ with zipfile.ZipFile(fn, "r") as z:
+ if len(z.namelist()) == 0:
+ os.unlink(fn)
+ else:
+ sys.stderr.write("Wrote {}\n".format(fn))
+
+ for imgnum, img in enumerate(page.xpath("//img | //object | //embed")):
+ img_url = img.get("data" if img.tag == "object" else "src")
+ img_url = urlparse.urljoin(url, img_url)
+ fn = "{}.{:02d}{}".format(fn_base, imgnum, os.path.splitext(img_url)[1])
+ urllib.urlretrieve(img_url, fn)
+ sys.stderr.write("Wrote {}\n".format(fn))
+
+ html2markdown = subprocess.Popen(("html2markdown", "--no-skip-internal-links", "--reference-links"),
+ stdin = subprocess.PIPE, stdout = subprocess.PIPE)
+ page.write(html2markdown.stdin)
+ html2markdown.stdin.close()
+ lines = html2markdown.stdout.readlines()
+ html2markdown.stdout.close()
+ html2markdown.wait()
+
+ while lines and lines[0].isspace():
+ del lines[0]
+
+ fn = fn_base + ".md"
+ with open(fn, "w") as f:
+ want_blank = False
+ for line in lines:
+ blank = line.isspace()
+ if want_blank and not blank:
+ f.write("\n")
+ if not blank:
+ f.write(line)
+ want_blank = blank
+ sys.stderr.write("Wrote {}\n".format(fn))
+
+ fn = fn[:-3] + ".wiki"
+ urllib.urlretrieve(url + "?format=txt", fn)
+ sys.stderr.write("Wrote {}\n".format(fn))
+
+
+# XSL transform to extract list of Wiki page URLs from the TOC Wiki page
+
+xsl_get_toc = lxml.etree.XSLT(lxml.etree.XML('''\
+ <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="1.0">
+
+ <xsl:output method="text" encoding="us-ascii"/>
+
+ <xsl:param name="basename"/>
+
+ <xsl:template match="/">
+ <xsl:for-each select="//div[@id = 'wikipage']/ul//a">
+ <xsl:value-of select="concat($basename, @href, '&#10;')"/>
+ </xsl:for-each>
+ </xsl:template>
+
+ </xsl:transform>
+'''))
+
+# XSL transform to extract useful content of a Wiki page.
+
+# Django generates weird HTML for ordered lists: it sometimes breaks
+# up a single ordered list into multiple adjacent <ol/> elements,
+# using the @start attribute to try to make the result look like a
+# single ordered list. This looks OK in Firefox but confuses the
+# bejesus out of both html2markdown and htmldoc. In some cases this is
+# probably unavoidable, but most of the uses of this I've seen look
+# gratuitous, and are probably the result of code modulararity issues
+# in Django.
+#
+# So we try to clean this up, by merging adjacent <ol/> elements where
+# we can. The merge incantation is an adaptation of:
+#
+# http://stackoverflow.com/questions/1806123/merging-adjacent-nodes-of-same-type-xslt-1-0
+#
+# There may be a more efficient way to do this, but I don't think
+# we care, and this seems to work.
+#
+# Original author's explanation:
+#
+# The rather convoluted XPath expression for selecting the following
+# sibling aaa nodes which are merged with the current one:
+#
+# following-sibling::aaa[ # following 'aaa' siblings
+# not(preceding-sibling::*[ # if they are not preceded by
+# not(self::aaa) and # a non-'aaa' node
+# not(following-sibling::aaa = current()) # after the current node
+# ])
+# ]
+
+xsl_get_page = lxml.etree.XSLT(lxml.etree.XML('''\
+ <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+
+ <xsl:output method="xml" encoding="us-ascii" omit-xml-declaration="yes" />
+
+ <xsl:param name="basename"/>
+ <xsl:param name="path"/>
+
+ <xsl:template match="/">
+ <xsl:message><xsl:value-of select="concat('Got path: ', $path)"/></xsl:message>
+ <xsl:variable name="id">
+ <xsl:call-template name="path-to-id">
+ <xsl:with-param name="p" select="$path"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:message><xsl:value-of select="concat('Got id: ', $id)"/></xsl:message>
+ <xsl:comment>NEW PAGE</xsl:comment>
+ <html>
+ <body>
+ <div id="{$id}">
+ <xsl:apply-templates select="//div[@id = 'wikipage']/*"/>
+ </div>
+ </body>
+ </html>
+ </xsl:template>
+
+ <xsl:template match="//div[contains(@class, 'wiki-toc')]"/>
+
+ <xsl:template match="//span[@class = 'icon' and not(*)]"/>
+
+ <xsl:template match="a[contains(@class, 'wiki') and
+ starts-with(@href, '/wiki/')]">
+ <xsl:variable name="href">
+ <xsl:call-template name="path-to-id">
+ <xsl:with-param name="p" select="@href"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <a href="#{$href}">
+ <xsl:apply-templates select="@*[name() != 'href']"/>
+ <xsl:apply-templates/>
+ </a>
+ </xsl:template>
+
+ <xsl:template match="a[starts-with(@href, '/attachment/wiki/')]">
+ <a href="{concat($basename, @href)}">
+ <xsl:apply-templates select="@*[name() != 'href']"/>
+ <xsl:apply-templates/>
+ </a>
+ </xsl:template>
+
+ <xsl:template match="img[starts-with(@src, '/raw-attachment/wiki/')]">
+ <img src="{concat($basename, @src)}">
+ <xsl:apply-templates select="@*[name() != 'src']"/>
+ <xsl:apply-templates/>
+ </img>
+ </xsl:template>
+
+ <xsl:template match="object[starts-with(@data, '/raw-attachment/wiki/') or
+ starts-with(@data, '/graphviz/')]">
+ <object data="{concat($basename, @data)}">
+ <xsl:apply-templates select="@*[name() != 'data']"/>
+ <xsl:apply-templates/>
+ </object>
+ </xsl:template>
+
+ <xsl:template match="embed[starts-with(@src, '/raw-attachment/wiki/') or
+ starts-with(@src, '/graphviz/')]">
+ <embed src="{concat($basename, @src)}">
+ <xsl:apply-templates select="@*[name() != 'src']"/>
+ <xsl:apply-templates/>
+ </embed>
+ </xsl:template>
+
+ <xsl:template match="text()[contains(., '&#8203;')]">
+ <xsl:call-template name="remove-zero-width-spaces">
+ <xsl:with-param name="s" select="."/>
+ </xsl:call-template>
+ </xsl:template>
+
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:copy-of select="@*"/>
+ <xsl:apply-templates/>
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template name="path-to-id">
+ <xsl:param name="p"/>
+ <xsl:text>_</xsl:text>
+ <xsl:call-template name="replace">
+ <xsl:with-param name="s" select="$p"/>
+ <xsl:with-param name="old">/</xsl:with-param>
+ <xsl:with-param name="new">.</xsl:with-param>
+ </xsl:call-template>
+ </xsl:template>
+
+ <xsl:template name="remove-zero-width-spaces">
+ <xsl:param name="s"/>
+ <xsl:call-template name="replace">
+ <xsl:with-param name="s" select="$s"/>
+ <xsl:with-param name="old">&#8203;</xsl:with-param>
+ <xsl:with-param name="new"/>
+ </xsl:call-template>
+ </xsl:template>
+
+ <xsl:template name="replace">
+ <xsl:param name="s"/>
+ <xsl:param name="old"/>
+ <xsl:param name="new"/>
+ <xsl:choose>
+ <xsl:when test="contains($s, $old)">
+ <xsl:call-template name="replace">
+ <xsl:with-param name="s" select="concat(substring-before($s, $old),
+ $new,
+ substring-after($s, $old))"/>
+ <xsl:with-param name="old" select="$old"/>
+ <xsl:with-param name="new" select="$new"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$s"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="ol">
+ <xsl:if test="not(preceding-sibling::*[1]/self::ol)">
+ <xsl:variable name="following"
+ select="following-sibling::ol[
+ not(preceding-sibling::*[
+ not(self::ol) and
+ not(following-sibling::ol = current())
+ ])
+ ]"/>
+ <xsl:copy>
+ <xsl:apply-templates select="$following/@*[name() != 'start']"/>
+ <xsl:apply-templates select="@*"/>
+ <xsl:apply-templates select="node()"/>
+ <xsl:apply-templates select="$following/node()"/>
+ </xsl:copy>
+ </xsl:if>
+ </xsl:template>
+
+ </xsl:transform>
+'''))
+
+# All the files we want to parse are HTML, so make HTML the default
+# parser. In theory the HTML produced by Trac is XHTML thus should
+# parse correctly (in fact, better) as XML, but in practice this seems
+# not to work properly at the moment, while parsing as HTML does.
+# Haven't bothered to figure out why, life is too short.
+#
+# If you're reading this comment because this script stopped working
+# after a Trac upgrade, try commenting out this line to see whether
+# things have changed and Trac's HTML now parses better as XML.
+
+lxml.etree.set_default_parser(lxml.etree.HTMLParser())
+
+# Run the main program.
+main()
diff --git a/doc/manual/rpkid-bpki.dot b/doc/manual/rpkid-bpki.dot
new file mode 100644
index 00000000..651591cb
--- /dev/null
+++ b/doc/manual/rpkid-bpki.dot
@@ -0,0 +1,76 @@
+// $Id$
+
+// Color code:
+// Black: Hosting entity
+// Blue: Hosted entity
+// Red: Cross-certified peer
+//
+// Shape code:
+// Octagon: TA
+// Diamond: CA
+// Record: EE
+
+digraph bpki_rpkid {
+ splines = true;
+ size = "14,14";
+ node [ fontname = Times, fontsize = 9 ];
+
+ // Hosting entity
+ node [ color = black, shape = record ];
+ TA [ shape = octagon, label = "BPKI TA" ];
+ rpkid [ label = "rpkid|{HTTPS server|HTTPS left-right client|CMS left-right}" ];
+ irdbd [ label = "irdbd|{HTTPS left-right server|CMS left-right}" ];
+ irbe [ label = "IRBE|{HTTPS left-right client|CMS left-right}" ];
+
+ // Hosted entities
+ node [ color = blue, fontcolor = blue ];
+ Alice_CA [ shape = diamond ];
+ Alice_EE [ label = "Alice\nBSC EE|{HTTPS up-down client|CMS up-down}" ];
+ Ellen_CA [ shape = diamond ];
+ Ellen_EE [ label = "Ellen\nBSC EE|{HTTPS up-down client|CMS up-down}" ];
+
+ // Peers
+ node [ color = red, fontcolor = red, shape = diamond ];
+ Bob_CA;
+ Carol_CA;
+ Dave_CA;
+ Frank_CA;
+ Ginny_CA;
+ Harry_CA;
+ node [ shape = record ];
+ Bob_EE [ label = "Bob\nEE|{HTTPS up-down|CMS up-down}" ];
+ Carol_EE [ label = "Carol\nEE|{HTTPS up-down|CMS up-down}" ];
+ Dave_EE [ label = "Dave\nEE|{HTTPS up-down|CMS up-down}" ];
+ Frank_EE [ label = "Frank\nEE|{HTTPS up-down|CMS up-down}" ];
+ Ginny_EE [ label = "Ginny\nEE|{HTTPS up-down|CMS up-down}" ];
+ Harry_EE [ label = "Bob\nEE|{HTTPS up-down|CMS up-down}" ];
+
+ edge [ color = black, style = solid ];
+ TA -> Alice_CA;
+ TA -> Ellen_CA;
+
+ edge [ color = black, style = dotted ];
+ TA -> rpkid;
+ TA -> irdbd;
+ TA -> irbe;
+
+ edge [ color = blue, style = solid ];
+ Alice_CA -> Bob_CA;
+ Alice_CA -> Carol_CA;
+ Alice_CA -> Dave_CA;
+ Ellen_CA -> Frank_CA;
+ Ellen_CA -> Ginny_CA;
+ Ellen_CA -> Harry_CA;
+
+ edge [ color = blue, style = dotted ];
+ Alice_CA -> Alice_EE;
+ Ellen_CA -> Ellen_EE;
+
+ edge [ color = red, style = solid ];
+ Bob_CA -> Bob_EE;
+ Carol_CA -> Carol_EE;
+ Dave_CA -> Dave_EE;
+ Frank_CA -> Frank_EE;
+ Ginny_CA -> Ginny_EE;
+ Harry_CA -> Harry_EE;
+}