The life cycle of a certificate:
	* Generating a key pair.
	* Generating a CSR containing public key.
	* Submitting CSR to a CA.
	* Checking for response from CA.
	* Waiting for certificate to near expiration.
Administrative action can also add these states:
	* On hold
	* Revoked

We model that life cycle as a state machine.

Now with some arbitrarily-named states for our per-certificate state machine:
	* Generating a key pair.
	  States: NEED_KEY_PAIR, GENERATING_KEY_PAIR [*], NEED_KEY_GEN_PERMS,
		  NEED_KEY_GEN_TOKEN, NEED_KEY_GEN_PIN, HAVE_KEY_PAIR
	* Reading info about key pair.
		  NEED_KEYINFO, READING_KEYINFO [*],
		  NEED_KEYINFO_READ_TOKEN, NEED_KEYINFO_READ_PIN, HAVE_KEYINFO
	* Generating a CSR containing public key.
	  States: NEED_CSR, GENERATING_CSR [*],
		  NEED_CSR_GEN_TOKEN, NEED_CSR_GEN_PIN, HAVE_CSR
	* Generating SCEP data, if we need it.
	  States: NEED_SCEP_DATA, GENERATING_SCEP_DATA [*],
		  NEED_SCEP_GEN_TOKEN, NEED_SCEP_GEN_PIN,
		  NEED_SCEP_ENCRYPTION_CERT, NEED_SCEP_RSA_CLIENT_KEY,
		  HAVE_SCEP_DATA
	* Submitting CSR to a CA.
	  States: NEED_TO_SUBMIT, SUBMITTING [*]
	* Don't know which CA to submit to.
	  States: NEED_CA [*]
	* Don't have complete information about CA.
	  States: CA_UNCONFIGURED [*]
	* Can't contact CA.
	  States: CA_UNREACHABLE [*]
	* Rejected, very sad.
	  States: CA_REJECTED [*]
	* CA is thinking.
	  States: CA_WORKING [*]
	* Saving certificate to the desired location and parsing it for the
	  information we think is interesting.
	  States: NEED_TO_SAVE_CERT, PRE_SAVE_CERT[*],
		  START_SAVING_CERT, SAVING_CERT [*], NEED_CERTSAVE_PERMS,
		  NEED_CERTSAVE_TOKEN, NEED_CERTSAVE_PIN,
		  NEED_TO_READ_CERT, READING_CERT [*],
		  SAVED_CERT, POST_SAVED_CERT[*]
	* Waiting for certificate to near expiration.
	  States: MONITORING
	* Notifying the admin of impending/passed expiration.
	  States: NEED_TO_NOTIFY_VALIDITY, NOTIFYING_VALIDITY [*]
	* Notifying the admin of CA rejection.
	  States: NEED_TO_NOTIFY_REJECTION, NOTIFYING_REJECTION [*]
	* Notifying the admin of CA issued cert, but not saved.
	  States: NEED_TO_NOTIFY_ISSUED_FAILED, NOTIFYING_ISSUED_FAILED [*]
	* Notifying the admin of that we failed to save CA certs.
	  States: NEED_TO_NOTIFY_ONLY_CA_SAVE_FAILED,
		  NOTIFYING_ONLY_CA_SAVE_FAILED
	* Saving CA certs while saving an issued cert.
	  States: NEED_TO_SAVE_CA_CERTS, START_SAVING_CA_CERTS,
		  SAVING_CA_CERTS [*], NEED_CA_CERT_SAVE_PERMS
	* Notifying the admin of CA issued cert, and saved.
	  States: NEED_TO_NOTIFY_ISSUED_SAVED, NOTIFYING_ISSUED_SAVED [*]
	* Saving CA certs while not saving an issued cert.
	  States: NEED_TO_SAVE_ONLY_CA_CERTS, START_SAVING_ONLY_CA_CERTS,
		  SAVING_ONLY_CA_CERTS [*]
	* Waiting for user input
	  States: NEED_GUIDANCE [*]
	* Getting our bearings
	  States: NEWLY_ADDED,
		  NEWLY_ADDED_READING_KEYINFO [*],
		  NEWLY_ADDED_NEED_KEYINFO_READ_TOKEN,
		  NEWLY_ADDED_NEED_KEYINFO_READ_PIN,
		  NEWLY_ADDED_START_READING_CERT,
		  NEWLY_ADDED_READING_CERT [*],
		  NEWLY_ADDED_DECIDING [*]
[*] Denotes states in which we have to wait for instructions from the user
    or completion of interaction with external systems.

State logic:
	NEED_KEY_PAIR:
		start-key-generation
		state_next = GENERATING_KEY_PAIR
		state_transition = now
		break

	GENERATING_KEY_PAIR:
		if starting-up
			state_next = NEED_KEY_PAIR
			state_transition = now
		else
			if keygen-finished
				if key-was-stored-successfully
					state_next = HAVE_KEY_PAIR
					state_transition = now
				elseif key-store-needs-token
					state_next = NEED_KEY_GEN_TOKEN
					state_transition = now
				elseif key-store-needs-pin
					state_next = NEED_KEY_GEN_PIN
					state_transition = now
				elseif key-store-needs-perms
					state_next = NEED_KEY_GEN_PERMS
					state_transition = now
				else
					state_next = NEED_KEY_PAIR
					state_transition = now
			else
				state_next = GENERATING_KEY_PAIR
				state_transition = when-notified
		break

	NEED_KEY_GEN_PERMS:
		if starting-up
			state_next = NEED_KEY_PAIR
			state_transition = now
		break

	NEED_KEY_GEN_TOKEN:
		if starting-up
			state_next = NEED_KEY_PAIR
			state_transition = soon
		break

	NEED_KEY_GEN_PIN:
		if starting-up
			state_next = NEED_KEY_PAIR
			state_transition = now
		break

	HAVE_KEY_PAIR:
		state_next = NEED_KEYINFO
		state_transition = now
		break

	NEED_KEYINFO:
		start-reading-key-information
		state_next = READING_KEYINFO
		state_transition = now
		break

	READING_KEYINFO:
		if starting-up
			state_next = NEED_KEYINFO
			state_transition = now
		else
			if finished-reading-key-information
				state_next = HAVE_KEYINFO
				state_transition = now
			elseif key-store-needs-token
				state_next = NEED_KEYINFO_READ_TOKEN
				state_transition = now
			elseif key-store-needs-pin
				state_next = NEED_KEYINFO_READ_PIN
				state_transition = now
			else
				state_next = NEED_KEY_PAIR
				state_transition = now
		break

	NEED_KEYINFO_READ_TOKEN:
		if starting-up
			state_next = NEED_KEYINFO
			state_transition = soon
		break

	NEED_KEYINFO_READ_PIN:
		if starting-up
			state_next = NEED_KEYINFO
			state_transition = soon
		break

	HAVE_KEYINFO:
		state_next = NEED_CSR
		state_transition = now
		break

	NEED_CSR:
		if starting-up
			state_next = HAVE_KEYINFO
			state_transition = now
		else
			if don't-have-a-full-template
				fill-in-template-values-based-on-defaults
			start-csr-generation-using-template-values
			state_next = GENERATING_CSR
			state_transition = now
		break

	GENERATING_CSR:
		if starting-up
			state_next = HAVE_KEYINFO
			state_transition = now
		else
			if csrgen-finished
				if csr-was-stored
					state_next = HAVE_CSR
					state_transition = now
				elseif key-store-needs-token
					state_next = NEED_CSR_GEN_TOKEN
					state_transition = now
				elseif key-store-needs-pin
					state_next = NEED_CSR_GEN_PIN
					state_transition = now
				else
					state_next = NEED_CSR
					state_transition = now
			else
				state_next = GENERATING_CSR
				state_transition = when-notified
		break

	NEED_CSR_GEN_TOKEN:
		if starting-up
			state_next = HAVE_KEYINFO
			state_transition = soon
		break

	NEED_CSR_GEN_PIN:
		if starting-up
			state_next = HAVE_KEYINFO
			state_transition = now
		break

	HAVE_CSR:
		state_next = NEED_TO_SUBMIT
		state_transition = now
		break

	NEED_SCEP_DATA:
		if starting-up
			state_next = HAVE_KEYINFO
			state_transition = now
		else
			if don't-have-a-full-template
				fill-in-template-values-based-on-defaults
			start-csr-generation-using-template-values
			state_next = GENERATING_SCEP_DATA
			state_transition = now
		break

	GENERATING_SCEP_DATA:
		if starting-up
			state_next = NEED_SCEP_DATA
			state_transition = now
		else
			if scepgen-finished
				if scep-data-was-stored
					state_next = HAVE_SCEP_DATA
					state_transition = now
				elseif key-store-needs-token
					state_next = NEED_SCEP_GEN_TOKEN
					state_transition = now
				elseif key-store-needs-pin
					state_next = NEED_SCEP_GEN_PIN
					state_transition = now
				elseif requires-ra-encryption-cert
					state_next = NEED_SCEP_ENCRYPTION_CERT
					state_transition = now
				else
					state_next = NEED_SCEP_RSA_CLIENT_KEY
					state_transition = now
			else
				state_next = GENERATING_SCEP_DATA
				state_transition = when-notified
		break

	NEED_SCEP_GEN_TOKEN:
		if starting-up
			state_next = NEED_SCEP_DATA
			state_transition = soon
		break

	NEED_SCEP_GEN_PIN:
		if starting-up
			state_next = NEED_SCEP_DATA
			state_transition = now
		break

	NEED_SCEP_ENCRYPTION_CERT:
		if starting-up
			state_next = NEED_SCEP_DATA
			state_transition = now
		break

	NEED_SCEP_RSA_CLIENT_KEY:
		if starting-up
			state_next = NEED_SCEP_DATA
			state_transition = now
		break

	HAVE_SCEP_DATA:
		state_next = NEED_TO_SUBMIT
		state_transition = now
		break

	NEED_TO_SUBMIT:
		if starting-up
			state_next = HAVE_CSR
			state_transition = now
		else
			start-csr-submission
			if csr-submission-started
				state_next = SUBMITTING
				state_transition = now
			else
				if don't-know-a-ca
					state_next = NEED_CA
					state_transition = now
		break

	SUBMITTING:
		if starting-up
			state_next = HAVE_CSR
			state_transition = now
		else
			if csr-submission-attempt-completed
				if ca-issued-cert
					state_next = NEED_TO_SAVE_CERT
					state_transition = now
				elseif ca-rejected-us
					if already-had-a-cert
						state_next = MONITORING
						state_transition = now
					else
						state_next = CA_NEED_TO_NOTIFY_REJECTION
						state_transition = later
				elseif ca-is-unreachable
					store-ca-cookie
					state_next = CA_UNREACHABLE
					state_transition = later
				elseif ca-is-thinking-about-it-and-have-cookie
					store-ca-cookie
					state_next = CA_WORKING
					state_transition = soon
				elseif ca-is-underconfigured
					if already-had-a-cert
						state_next = MONITORING
						state_transition = now
					else
						store-ca-cookie
						state_next = CA_UNCONFIGURED
						state_transition = later
				elseif need-scep-data
					state_next = NEED_SCEP_DATA
					state_transition = now
				elseif need-rekey
					state_next = NEED_REKEY
					state_transition = now
				else
					state_next = NEED_GUIDANCE
					state_transition = now
			else
				state_next = SUBMITTING
				state_transition = when-notified
		break

	NEED_TO_SAVE_CERT:
		if pre-save-command-configured
			start-configured-pre-save-command
			state_next = PRE_SAVE_CERT
			state_transition = now
		else
			state_next = START_SAVING_CERT
			state_transition = now
		break

	PRE_SAVE_CERT:
		if starting-up
			state_next = NEED_TO_SAVE_CERT
			state_transition = now
		else
			if pre-save-completed
				state_next = START_SAVING_CERT
				state_transition = now
		break

	START_SAVING_CERT:
		start-saving-cert
		state_next = SAVING_CERT
		state_transition = now
		break

	SAVING_CERT:
		if starting-up
			state_next = NEED_TO_SAVE_CERT
			state_transition = now
		else
			if cert-save-completed
				state_next = NEED_TO_SAVE_CA_CERTS
				state_transition = now
			else
				if cert-save-needs-perms
					state_next = NEED_CERTSAVE_PERMS
					state_transition = now
				elseif cert-save-needs-token
					state_next = NEED_CERTSAVE_TOKEN
					state_transition = now
				elseif cert-save-needs-pin
					state_next = NEED_CERTSAVE_PIN
					state_transition = now
				else
					state_next = NEED_TO_NOTIFY_ISSUED_SAVE_FAILED
					state_transition = now
		break

	NEED_CERTSAVE_PERMS:
		if starting-up
			state_next = NEED_TO_SAVE_CERT
			state_transition = now
		break

	NEED_CERTSAVE_TOKEN:
		if starting-up
			state_next = NEED_TO_SAVE_CERT
			state_transition = now
		break

	NEED_CERTSAVE_PIN:
		if starting-up
			state_next = NEED_TO_SAVE_CERT
			state_transition = now
		break

	NEED_TO_SAVE_CA_CERTS:
		state_next = START_SAVING_CA_CERTS
		state_transition = now

	START_SAVING_CA_CERTS:
		if starting-up
			state_next = NEED_TO_SAVE_CA_CERTS
			state_transition = now
		else
			start-saving-ca-certs
			state_next = SAVING_CA_CERTS
			state_transition = now
		break

	SAVING_CA_CERTS:
		if starting-up
			state_next = NEED_TO_SAVE_CA_CERTS
			state_transition = now
		else
			if saving-ca-certs-complete
				state_next = NEED_TO_READ_CERT
				state_transition = now
			else
				if permissions-problem
					state_next = NEED_CA_CERT_SAVE_PERMS
					state_transition = now
				else
					state_next = NEED_TO_NOTIFY_ISSUED_CA_SAVE_FAILED
					state_transition = now

	NEED_CA_CERT_SAVE_PERMS:
		if starting-up
			state_next = NEED_TO_SAVE_CA_CERTS
			state_transition = now
		break

	NEED_TO_READ_CERT:
		start-reading-cert
		state_next = READING_CERT
		state_transition = now
		break

	READING_CERT:
		if starting-up
			state_next = NEED_TO_READ_CERT
			state_transition = now
		else
			if cert-read-completed
				if post-save-command-configured
					start-configured-post-save-command
					state_next = POST_SAVED_CERT
					state_transition = now
				else
					state_next = NEED_TO_NOTIFY_ISSUED_SAVED
					state_transition = now
		break

	POST_SAVED_CERT:
		if starting-up
			state_next = NEED_TO_NOTIFY_ISSUED_SAVED
			state_transition = now
		else
			if post-save-completed
				state_next = NEED_TO_NOTIFY_ISSUED_SAVED
				state_transition = now

	SAVED_CERT:
		state_next = NEED_TO_SAVE_CA_CERTS
		state_transition = now
		break

	NEED_TO_SAVE_ONLY_CA_CERTS:
		state_next = START_SAVING_ONLY_CA_CERTS
		state_transition = now

	START_SAVING_ONLY_CA_CERTS:
		if starting-up
			state_next = NEED_TO_SAVE_ONLY_CA_CERTS
			state_transition = now
		else
			start-saving-only-ca-certs
			state_next = SAVING_ONLY_CA_CERTS
			state_transition = now
		break

	SAVING_ONLY_CA_CERTS:
		if starting-up
			state_next = NEED_TO_SAVE_ONLY_CA_CERTS
			state_transition = now
		else
			if saving-ca-certs-complete
				state_next = MONITORING
				state_transition = now
			else
				if permissions-problem
					state_next = NEED_CA_CERT_SAVE_PERMS
					state_transition = now
				else
					state_next = NEED_TO_NOTIFY_ONLY_CA_SAVE_FAILED
					state_transition = now


	NEED_TO_NOTIFY_REJECTION:
		start-notifying
		state_next = NOTIFYING_REJECTION
		state_transition = now
		break

	NOTIFYING_REJECTION:
		if starting-up
			state_next = NEED_TO_NOTIFY_REJECTION
			state_transition = now
		else
			if notification-completed
				state_next = CA_REJECTED
				state_transition = now
		break

	NEED_TO_NOTIFY_ISSUED_SAVE_FAILED:
		start-notifying
		state_next = NOTIFYING_ISSUED_SAVE_FAILED
		state_transition = now
		break

	NOTIFYING_ISSUED_SAVE_FAILED:
		if starting-up
			state_next = NEED_TO_NOTIFY_ISSUED_SAVE_FAILED
			state_transition = now
		else
			if notification-completed
				state_next = START_SAVING_CERT
				state_transition = soonish
		break

	NEED_TO_NOTIFY_ISSUED_CA_SAVE_FAILED
		start-notifying
		state_next = NOTIFYING_ISSUED_CA_SAVE_FAILED
		state_transition = now
		break

	NOTIFYING_ISSUED_CA_SAVE_FAILED
		if starting-up
			state_next = NEED_TO_NOTIFY_ISSUED_CA_SAVE_FAILED
			state_transition = now
		else
			if notification-completed
				state_next = MONITORING
				state_transition = soonish
		break

	NEED_TO_NOTIFY_ONLY_CA_SAVE_FAILED
		start-notifying
		state_next = NOTIFYING_ONLY_CA_SAVE_FAILED
		state_transition = now
		break

	NOTIFYING_ONLY_CA_SAVE_FAILED
		if starting-up
			state_next = NEED_TO_NOTIFY_ONLY_CA_SAVE_FAILED
			state_transition = now
		else
			if notification-completed
				state_next = MONITORING
				state_transition = now
		break

	NEED_TO_NOTIFY_ISSUED_SAVED:
		start-notifying
		state_next = NOTIFYING_ISSUED_SAVED
		state_transition = now
		break

	NOTIFYING_ISSUED_SAVED:
		if starting-up
			state_next = NEED_TO_NOTIFY_ISSUED_SAVED
			state_transition = now
		else
			if notification-completed
				state_next = MONITORING
				state_transition = now
		break

	CA_REJECTED:
		state_transition = soon
		break

	CA_WORKING:
		if starting-up
			state_next = HAVE_CSR
			state_transition = now
		else
			state_next = NEED_TO_SUBMIT
			state_transition = soon
		break

	CA_UNREACHABLE:
		if starting-up
			state_next = HAVE_CSR
			state_transition = now
		else
			state_next = NEED_TO_SUBMIT
			state_transition = soon
		break

	CA_UNCONFIGURED:
		if starting-up
			state_next = HAVE_CSR
			state_transition = now
		break

	NEED_CA:
		if starting-up
			state_next = HAVE_CSR
			state_transition = now
		break

	NEED_GUIDANCE:
		if have-guidance
			state_next = as-guided
			state_waitfor = now
		else
			state_next = NEED_GUIDANCE
			state_transition = timeout
		break


	MONITORING:
		if certificate-is-expired or
		   (expiration-time-is-below-notify-threshold-value and
		    expiration-time-was-above-notify-threshold-value)
			update-template-values-based-on-cert
			state_next = NEED_TO_NOTIFY_VALIDITY
			state_transition = now
		else
		if (expiration-time-is-below-renewal-threshold-value and
		    expiration-time-was-above-renewal-threshold-value)
			if due-for-rekey
				state_next = NEED_KEY_PAIR
			else
				state_next = NEED_CSR
			state_transition = now
		else
			state_next = MONITORING
			state_transition = timeout
		break

	NEED_TO_NOTIFY_VALIDITY:
		if starting-up
			state_next = MONITORING
			state_transition = now
		else
			start-notifying
			state_next = NOTIFYING_VALIDITY
			state_transition = now
		break

	NOTIFYING_VALIDITY:
		if starting-up
			state_next = NEED_TO_NOTIFY_VALIDITY
			state_transition = now
		else
			if notification-completed
				if this-cert-gets-autorenew and
				   (expiration-time-is-below-renewal-threshold-value and
				    expiration-time-was-above-renewal-threshold-value)
					if due-for-rekey
						state_next = NEED_KEY_PAIR
					else
						state_next = NEED_CSR
					state_transition = now
				else
					state_next = MONITORING
					state_transition = timeout
		break

	NEWLY_ADDED:
		if key-storage-is-known
			state_next = NEWLY_ADDED_START_READING_KEYINFO
			state_transition = now
		else
			state_next = NEWLY_ADDED_START_READING_CERT
			state_transition = now
		break

	NEWLY_ADDED_START_READING_KEYINFO:
		start-reading-key-information
		state_next = NEWLY_ADDED_READING_KEYINFO
		state_transition = now
		break

	NEWLY_ADDED_READING_KEYINFO:
		if starting-up
			state_next = NEWLY_ADDED_START_READING_KEYINFO
			state_transition = now
		else
			if finished-reading-key-information
				state_next = NEWLY_ADDED_START_READING_CERT
				state_transition = now
			elseif key-store-needs-token
				state_next = NEWLY_ADDED_NEED_KEYINFO_READ_TOKEN
				state_transition = now
			elseif key-store-needs-pin
				state_next = NEWLY_ADDED_NEED_KEYINFO_READ_PIN
				state_transition = now
			else
				state_next = NEWLY_ADDED_START_READING_CERT
				state_transition = now
		break

	NEWLY_ADDED_NEED_KEYINFO_READ_TOKEN:
		if starting-up
			state_next = NEWLY_ADDED_START_READING_KEYINFO
			state_transition = now
		break

	NEWLY_ADDED_NEED_KEYINFO_READ_PIN:
		if starting-up
			state_next = NEWLY_ADDED_START_READING_KEYINFO
			state_transition = now
		break

	NEWLY_ADDED_START_READING_CERT:
		start-reading-cert
		state_next = NEWLY_ADDED_READING_CERT
		state_transition = now
		break

	NEWLY_ADDED_READING_CERT:
		if starting-up
			state_next = NEWLY_ADDED_START_READING_CERT
			state_transition = now
		else
			if finished-reading-cert
				state_next = NEWLY_ADDED_DECIDING
				state_transition = now
		break

	NEWLY_ADDED_DECIDING:
		if entry-has-no-associated-ca
			try-to-set-ca-using-known-ca-list
		if we-have-a-cert
			if we-have-ca-certs-to-save
				state_next = NEED_TO_SAVE_ONLY_CA_CERTS
				state_transition = now
			else
				state_next = MONITORING
				state_transition = now
		else
			if key-storage-is-known
				if key-is-present
					state_next = NEED_CSR
					state_transition = now
				else
					state_next = NEED_KEY_PAIR
					state_transition = now
			else
				state_next = NEED_GUIDANCE
				state_transition = now
		break

Types of actions and user guidance:
	Reenroll-from-scratch ("request -g"):
		state_next = NEED_KEY_PAIR
		state_transition = now
	Submit-key ("request", if no csr or arguments alter it):
		state_next = NEED_CSR
		state_transition = now
	Submit-csr (automatic for "request")
		state_next = HAVE_CSR
		state_transition = now
	Resubmit-csr (need to add "resubmit")
		state_next = HAVE_CSR
		state_transition = now
	Start-Tracking-with-AutoRenew ("start-tracking"):
		add-cert-to-monitoring-list
		state_next = MONITORING
		state_transition = now
	Start-Tracking-without-AutoRenew ("start-tracking"):
		add-cert-to-monitoring-list
		state_next = MONITORING
		state_transition = now
	Cancel ("stop-tracking"):
		remove-cert-from-monitoring-list
	Status ("list"):
		dump-monitoring-list

Data we need to track for each certificate/task/dbentry:
	* Type of key pair to generate [or use default settings]
	  default: RSA,2048
	* Location of key pair [use-once default]
	  default: NSS,/etc/pki/nssdb,,Server-Key-default
	* Location of certificate [use-once default]
	  default: NSS,/etc/pki/nssdb,,Server-Cert-default
	* Cached certificate issuer/serial/subject/spki/expiration/host/email
	* The last time we checked if expiration was imminent.
	* Interesting TTL values [or use default settings]
	  default: 30*24*60*60,7*24*60*60,3*24*60*60,2*24*60*60,1*24*60*60
	* How to notify administrator [or use default settings]
	  syslog(LOG_AUTHPRIV?) or mail to root@?
	* CSR template information [or imported from existing certificate]
	  * subject (cn=host name)
	  * SANs¹
	    * DNS
	    * email
	    * principal name
	    * IP addresses
	  * ku¹, eku¹
	  ¹ Encoded as extensionRequest attributes.
	* Certificate State (state_current)
	* Whether to autorenew-at-expiration [or use default settings]
	* Whether to start monitoring at issue [or use default settings]
	* Type and location of CA [or use default settings]
	* Value of CA cookie for in-progress submissions.
	* Date of submission for in-progress submissions.

When we interact with CAs, there are things that we "know" about them, or would
like to know:
	* A nickname by which we refer to the CA.
	* The certificate which the CA uses as the issuer of certificates for
	  end entities.
	* The root of the chain of trust, if it's not the CA's issuer
	  certificate, and any other certificates in the chain between them.
	* A set of mandatory-to-supply pieces of information when we're
	  requesting a new or renewed certificate from the CA.  For IPA, for
	  example, during requests for a new certificate (it doesn't
	  distinguish between "new" and "renew" cases), this is the Kerberos
	  principal name of the subject for whom we're requesting the
	  certificate.
	* If it supports different types of enrollment (known as profiles in
	  Dogtag, or as templates in ADCS), what the options are, and if
	  there's a recommended default.

Each of these pieces of information which we might obtain from the CA is
essentially either missing, current, in the process of being fetched, or in the
process of being disseminated out to the rest of the local system.  We can
model the states for each of these using roughly the same set of states:

	* Pulling data from the CA:
	  States: NEED_TO_REFRESH,REFRESHING,UNREACHABLE

	* Saving the data obtained from the CA to places where it's expected:
	  States: NEED_TO_SAVE_DATA,PRE_SAVE_DATA,START_SAVING_DATA,
		  SAVING_DATA,POST_SAVE_DATA,SAVED_DATA

	* Figuring out when we'll need to re-fetch data:
	  NEED_TO_ANALYZE, ANALYZING

	* Waiting until we need to re-fetch data:
	  States: IDLE

And this state machine:

	NEED_TO_REFRESH:
		start-refresh-submission
		if refresh-submission-started
			state_next = REFRESHING
			state_transition = now
		else
			state_transition = later
		break

	REFRESHING:
		if refresh-submission-attempt-completed
			if ca-gave-us-data
				state_next = NEED_TO_SAVE_DATA
				state_transition = now
			elseif ca-needs-retry
				state_next = NEED_TO_REFRESH
				state_transition = later
			elseif ca-is-unreachable
				state_next = UNREACHABLE
				state_transition = now
			else
				state_next = DISABLED
				state_transition = now
		else
			state_next = REFRESHING
			state_transition = when-notified
		break

	NEED_TO_SAVE_DATA:
		if pre-save-command-configured
			start-configured-pre-save-command
			state_next = PRE_SAVE_DATA
			state_transition = now
		else
			state_next = START_SAVING_DATA
			state_transition = now
		break

	PRE_SAVE_DATA:
		if pre-save-completed
			state_next = START_SAVING_DATA
			state_transition = now
		break

	START_SAVING_DATA:
		start-saving-data
		if saving-data-started
			state_next = SAVING_DATA
			state_transition = now
		break

	SAVING_DATA:
		if done-saving-data
			if post-save-command-configured
				start-configured-post-save-command
				state_next = POST_SAVE_DATA
				state_transition = now
			else
				state_next = SAVED_DATA
				state_transition = now
		break

	POST_SAVE_DATA:
		if post-save-completed
			state_next = SAVED_DATA
			state_transition = now
		break

	SAVED_DATA:
		state_next = NEED_TO_ANALYZE
		state_transition = now

	NEED_TO_ANALYZE:
		start-analysis
		if analysis-started
			state_next = ANALYZING
			state_transition = now
		else
			state_next = IDLE
			state_transition = now
		break

	ANALYZING:
		if fetched-data-will-need-to-be-refreshed:
			state_next = NEED_TO_REFRESH
			state_transition = timeout
		else:
			state_next = IDLE
			state_transition = now

	UNREACHABLE:
		state_next = NEED_TO_REFRESH
		state_transition = now
