diff --git a/.certmonger.metadata b/.certmonger.metadata
new file mode 100644
index 0000000..c19e22f
--- /dev/null
+++ b/.certmonger.metadata
@@ -0,0 +1 @@
+7eac3ce49718df4be8f47ec92ae3a951eb4ac435 SOURCES/certmonger-0.79.6.tar.gz
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f7a6717
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+SOURCES/certmonger-0.79.6.tar.gz
diff --git a/SOURCES/0001-NSS-crypto-policy-sets-minimum-RSA-and-DSA-key-size-.patch b/SOURCES/0001-NSS-crypto-policy-sets-minimum-RSA-and-DSA-key-size-.patch
new file mode 100644
index 0000000..8e19e28
--- /dev/null
+++ b/SOURCES/0001-NSS-crypto-policy-sets-minimum-RSA-and-DSA-key-size-.patch
@@ -0,0 +1,293 @@
+From fd17f002b2f4150a1fddc2582a21c6c03933a28a Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Fri, 23 Feb 2018 10:43:44 -0500
+Subject: [PATCH] NSS crypto policy sets minimum RSA and DSA key size to 2048
+
+Remove keys < 2048 for the NSS tests. This affects some of the
+OpenSSL tests as well where they run in a combined loop.
+
+Where it was not invasive to do I left the 1024/1536 for OpenSSL.
+---
+ tests/001-keyiread-dsa/expected.out |  6 +++---
+ tests/001-keyiread-dsa/run.sh       |  2 +-
+ tests/001-keyiread-rsa/expected.out |  2 --
+ tests/001-keyiread-rsa/run.sh       |  2 +-
+ tests/001-keyiread/expected.out     |  2 --
+ tests/001-keyiread/run.sh           |  2 +-
+ tests/002-keygen-rsa/expected.out   |  6 ------
+ tests/002-keygen-rsa/run.sh         |  2 +-
+ tests/002-keygen/expected.out       | 18 ------------------
+ tests/002-keygen/run.sh             |  2 +-
+ tests/003-csrgen-rsa/expected.out   |  6 ------
+ tests/003-csrgen-rsa/run.sh         |  4 ++--
+ tests/003-csrgen/expected.out       |  8 --------
+ tests/003-csrgen/run.sh             |  4 ++--
+ tests/004-selfsign-rsa/expected.out |  2 --
+ tests/004-selfsign-rsa/run.sh       |  2 +-
+ tests/004-selfsign/expected.out     |  2 --
+ tests/004-selfsign/run.sh           |  2 +-
+ 18 files changed, 14 insertions(+), 60 deletions(-)
+
+diff --git a/tests/001-keyiread-dsa/expected.out b/tests/001-keyiread-dsa/expected.out
+index b09db0ae..50643176 100644
+--- a/tests/001-keyiread-dsa/expected.out
++++ b/tests/001-keyiread-dsa/expected.out
+@@ -1,4 +1,4 @@
+-OK (DSA:1024).
+-OK (DSA:1024).
+-OK (DSA:1024).
++OK (DSA:2048).
++OK (DSA:2048).
++OK (DSA:2048).
+ Test complete.
+diff --git a/tests/001-keyiread-dsa/run.sh b/tests/001-keyiread-dsa/run.sh
+index 9f96b3bc..68f6d1c3 100755
+--- a/tests/001-keyiread-dsa/run.sh
++++ b/tests/001-keyiread-dsa/run.sh
+@@ -5,7 +5,7 @@ cd "$tmpdir"
+ source "$srcdir"/functions
+ initnssdb "$tmpdir"
+ 
+-for size in 1024 ; do
++for size in 2048 ; do
+ 	# Generate a self-signed cert.
+ 	run_certutil -d "$tmpdir" -S -g $size -n keyi$size \
+ 		-s "cn=T$size" -c "cn=T$size" \
+diff --git a/tests/001-keyiread-rsa/expected.out b/tests/001-keyiread-rsa/expected.out
+index 727897d1..3daa51f2 100644
+--- a/tests/001-keyiread-rsa/expected.out
++++ b/tests/001-keyiread-rsa/expected.out
+@@ -1,5 +1,3 @@
+-OK (RSA:1024).
+-OK (RSA:1536).
+ OK (RSA:2048).
+ OK (RSA:3072).
+ OK (RSA:4096).
+diff --git a/tests/001-keyiread-rsa/run.sh b/tests/001-keyiread-rsa/run.sh
+index c7b77686..ec31c7c7 100755
+--- a/tests/001-keyiread-rsa/run.sh
++++ b/tests/001-keyiread-rsa/run.sh
+@@ -5,7 +5,7 @@ cd "$tmpdir"
+ source "$srcdir"/functions
+ initnssdb "$tmpdir"
+ 
+-for size in 1024 1536 2048 3072 4096 ; do
++for size in 2048 3072 4096 ; do
+ 	# Generate a self-signed cert.
+ 	run_certutil -d "$tmpdir" -S -g $size -n keyi$size \
+ 		-s "cn=T$size" -c "cn=T$size" \
+diff --git a/tests/001-keyiread/expected.out b/tests/001-keyiread/expected.out
+index 727897d1..3daa51f2 100644
+--- a/tests/001-keyiread/expected.out
++++ b/tests/001-keyiread/expected.out
+@@ -1,5 +1,3 @@
+-OK (RSA:1024).
+-OK (RSA:1536).
+ OK (RSA:2048).
+ OK (RSA:3072).
+ OK (RSA:4096).
+diff --git a/tests/001-keyiread/run.sh b/tests/001-keyiread/run.sh
+index ce1428ed..0b31df95 100755
+--- a/tests/001-keyiread/run.sh
++++ b/tests/001-keyiread/run.sh
+@@ -5,7 +5,7 @@ cd "$tmpdir"
+ source "$srcdir"/functions
+ initnssdb "$tmpdir"
+ 
+-for size in 1024 1536 2048 3072 4096 ; do
++for size in 2048 3072 4096 ; do
+ 	# Generate a self-signed cert.
+ 	run_certutil -d "$tmpdir" -S -g $size -n keyi$size \
+ 		-s "cn=T$size" -c "cn=T$size" \
+diff --git a/tests/002-keygen-rsa/expected.out b/tests/002-keygen-rsa/expected.out
+index 3e6e9f3c..f7c146d0 100644
+--- a/tests/002-keygen-rsa/expected.out
++++ b/tests/002-keygen-rsa/expected.out
+@@ -1,9 +1,3 @@
+-[nss:1024]
+-OK.
+-OK (RSA:1024).
+-[nss:1536]
+-OK.
+-OK (RSA:1536).
+ [nss:2048]
+ OK.
+ OK (RSA:2048).
+diff --git a/tests/002-keygen-rsa/run.sh b/tests/002-keygen-rsa/run.sh
+index 476f4127..c0c59249 100755
+--- a/tests/002-keygen-rsa/run.sh
++++ b/tests/002-keygen-rsa/run.sh
+@@ -5,7 +5,7 @@ cd "$tmpdir"
+ source "$srcdir"/functions
+ initnssdb "$tmpdir"
+ 
+-for size in 1024 1536 2048 3072 4096 ; do
++for size in 2048 3072 4096 ; do
+ 	echo "[nss:$size]"
+ 	# Generate a key.
+ 	cat > entry.$size <<- EOF
+diff --git a/tests/002-keygen/expected.out b/tests/002-keygen/expected.out
+index dcd1af06..b8fbea56 100644
+--- a/tests/002-keygen/expected.out
++++ b/tests/002-keygen/expected.out
+@@ -1,21 +1,3 @@
+-[nss:1024]
+-OK.
+-OK (RSA:1024).
+-OK.
+-OK (RSA:1024 after RSA:1024).
+-OK.
+-OK (RSA:1024 after RSA:1024).
+-keyi1024
+-keyi1024 (candidate (next))
+-[nss:1536]
+-OK.
+-OK (RSA:1536).
+-OK.
+-OK (RSA:1536 after RSA:1536).
+-OK.
+-OK (RSA:1536 after RSA:1536).
+-keyi1536
+-keyi1536 (candidate (next))
+ [nss:2048]
+ OK.
+ OK (RSA:2048).
+diff --git a/tests/002-keygen/run.sh b/tests/002-keygen/run.sh
+index 08af1523..94230e6f 100755
+--- a/tests/002-keygen/run.sh
++++ b/tests/002-keygen/run.sh
+@@ -7,7 +7,7 @@ scheme="${scheme:-dbm:}"
+ source "$srcdir"/functions
+ initnssdb "$scheme$tmpdir"
+ 
+-for size in 1024 1536 2048 3072 4096 ; do
++for size in 2048 3072 4096 ; do
+ 	echo "[nss:$size]"
+ 	# Generate a key.
+ 	cat > entry.$size <<- EOF
+diff --git a/tests/003-csrgen-rsa/expected.out b/tests/003-csrgen-rsa/expected.out
+index c9dec729..def53fe4 100644
+--- a/tests/003-csrgen-rsa/expected.out
++++ b/tests/003-csrgen-rsa/expected.out
+@@ -1,10 +1,4 @@
+ pk12util: PKCS12 EXPORT SUCCESSFUL
+-1024 OK.
+-Signature OK
+-pk12util: PKCS12 EXPORT SUCCESSFUL
+-1536 OK.
+-Signature OK
+-pk12util: PKCS12 EXPORT SUCCESSFUL
+ 2048 OK.
+ Signature OK
+ pk12util: PKCS12 EXPORT SUCCESSFUL
+diff --git a/tests/003-csrgen-rsa/run.sh b/tests/003-csrgen-rsa/run.sh
+index 4cd84084..bb8ebecb 100755
+--- a/tests/003-csrgen-rsa/run.sh
++++ b/tests/003-csrgen-rsa/run.sh
+@@ -5,7 +5,7 @@ cd "$tmpdir"
+ source "$srcdir"/functions
+ initnssdb "$tmpdir"
+ 
+-for size in 1024 1536 2048 3072 4096 ; do
++for size in 2048 3072 4096 ; do
+ 	# Build a self-signed certificate.
+ 	run_certutil -d "$tmpdir" -S -g $size -n keyi$size \
+ 		-s "cn=T$size" -c "cn=T$size" \
+@@ -147,7 +147,7 @@ iterate() {
+ 
+ iteration=1
+ 
+-for size in 1024 ; do
++for size in 2048 ; do
+ 	iterate "$size" "$subject" "$hostname" "$email" "$principal" "$ku" "$eku" "$challengepassword" "$certfname" "$ca" "$capathlen" "$crldp" "$ocsp" "$nscomment"
+ done
+ 
+diff --git a/tests/003-csrgen/expected.out b/tests/003-csrgen/expected.out
+index 8e6cac6e..04342c0f 100644
+--- a/tests/003-csrgen/expected.out
++++ b/tests/003-csrgen/expected.out
+@@ -1,13 +1,5 @@
+ pk12util: PKCS12 EXPORT SUCCESSFUL
+ Signature OK
+-minicert.openssl.1024.pem: OK
+-1024 OK.
+-pk12util: PKCS12 EXPORT SUCCESSFUL
+-Signature OK
+-minicert.openssl.1536.pem: OK
+-1536 OK.
+-pk12util: PKCS12 EXPORT SUCCESSFUL
+-Signature OK
+ minicert.openssl.2048.pem: OK
+ 2048 OK.
+ pk12util: PKCS12 EXPORT SUCCESSFUL
+diff --git a/tests/003-csrgen/run.sh b/tests/003-csrgen/run.sh
+index 7c169ed9..31466b5c 100755
+--- a/tests/003-csrgen/run.sh
++++ b/tests/003-csrgen/run.sh
+@@ -5,7 +5,7 @@ cd "$tmpdir"
+ source "$srcdir"/functions
+ initnssdb "$tmpdir"
+ 
+-for size in 1024 1536 2048 3072 4096 ; do
++for size in 2048 3072 4096 ; do
+ 	# Build a self-signed certificate.
+ 	run_certutil -d "$tmpdir" -S -g $size -n keyi$size \
+ 		-s "cn=T$size" -c "cn=T$size" \
+@@ -199,7 +199,7 @@ iterate() {
+ 
+ iteration=1
+ 
+-for size in 1024 ; do
++for size in 2048 ; do
+ 	iterate "$size" "$subject" "$hostname" "$email" "$principal" "$ku" "$eku" "$challengepassword" "$certfname" "$ca" "$capathlen" "$crldp" "$ocsp" "$nscomment" "$subjectder" "$ipaddress" "$freshestcrl" "$no_ocsp_check" "$profile" "$ns_certtype"
+ done
+ 
+diff --git a/tests/004-selfsign-rsa/expected.out b/tests/004-selfsign-rsa/expected.out
+index dd5029ec..0eb84ef1 100644
+--- a/tests/004-selfsign-rsa/expected.out
++++ b/tests/004-selfsign-rsa/expected.out
+@@ -1,5 +1,3 @@
+-1024 OK.
+-1536 OK.
+ 2048 OK.
+ 3072 OK.
+ 4096 OK.
+diff --git a/tests/004-selfsign-rsa/run.sh b/tests/004-selfsign-rsa/run.sh
+index 6f9285b6..c1dd4c80 100755
+--- a/tests/004-selfsign-rsa/run.sh
++++ b/tests/004-selfsign-rsa/run.sh
+@@ -33,7 +33,7 @@ function setupca() {
+ 	EOF
+ }
+ 
+-for size in 1024 1536 2048 3072 4096 ; do
++for size in 2048 3072 4096 ; do
+ 	# Build a self-signed certificate.
+ 	run_certutil -d "$tmpdir" -S -g $size -n keyi$size \
+ 		-s "cn=T$size" -c "cn=T$size" \
+diff --git a/tests/004-selfsign/expected.out b/tests/004-selfsign/expected.out
+index dd5029ec..0eb84ef1 100644
+--- a/tests/004-selfsign/expected.out
++++ b/tests/004-selfsign/expected.out
+@@ -1,5 +1,3 @@
+-1024 OK.
+-1536 OK.
+ 2048 OK.
+ 3072 OK.
+ 4096 OK.
+diff --git a/tests/004-selfsign/run.sh b/tests/004-selfsign/run.sh
+index 7bb368ec..eb1df4ee 100755
+--- a/tests/004-selfsign/run.sh
++++ b/tests/004-selfsign/run.sh
+@@ -43,7 +43,7 @@ function setupca() {
+ 	EOF
+ }
+ 
+-for size in 1024 1536 2048 3072 4096 ; do
++for size in 2048 3072 4096 ; do
+ 	# Build a self-signed certificate.
+ 	run_certutil -d "$tmpdir" -S -g $size -n keyi$size \
+ 		-s "cn=T$size" -c "cn=T$size" \
+-- 
+2.16.2
+
diff --git a/SOURCES/0002-Convert-tests-to-use-python3.patch b/SOURCES/0002-Convert-tests-to-use-python3.patch
new file mode 100644
index 0000000..b31e3ce
--- /dev/null
+++ b/SOURCES/0002-Convert-tests-to-use-python3.patch
@@ -0,0 +1,788 @@
+From 653cd0571fe92c9fd4323f93ff23b9720c00fd5f Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Tue, 31 Jul 2018 13:09:02 -0400
+Subject: [PATCH] Convert tests to use python3
+
+---
+ tests/028-dbus/expected.out                 |  32 +-
+ tests/028-dbus/expected.out.nodsa           |  22 +-
+ tests/028-dbus/prequal.sh                   |   8 +-
+ tests/028-dbus/run.sh                       |   9 +-
+ tests/028-dbus/runsub.sh                    |   2 +-
+ tests/028-dbus/simpleprop.py                |  14 +-
+ tests/028-dbus/walk.py                      | 392 ++++++++++----------
+ tests/038-ms-v2-template/extract-extdata.py |   5 +-
+ 8 files changed, 243 insertions(+), 241 deletions(-)
+
+diff --git a/tests/028-dbus/expected.out b/tests/028-dbus/expected.out
+index ca3179e..1d8bec4 100644
+--- a/tests/028-dbus/expected.out
++++ b/tests/028-dbus/expected.out
+@@ -1,5 +1,3 @@
+-Certificate in file "${tmpdir}/test.crt" issued by CA and saved.
+-Certificate in file "${tmpdir}/test.crt" issued by CA and saved.
+ [[ getcert ]]
+ State MONITORING, stuck: no.
+ Number of certificates and requests being tracked: 1.
+@@ -187,13 +185,13 @@ dbus.Array([dbus.ObjectPath('/org/fedorahosted/certmonger/cas/CA1'), dbus.Object
+ dbus.Array([dbus.ObjectPath('/org/fedorahosted/certmonger/requests/Request2')], signature=dbus.Signature('o'))
+ 
+ [ /org/fedorahosted/certmonger: org.fedorahosted.certmonger.get_supported_key_types ]
+-dbus.Array([dbus.String(u'RSA'), dbus.String(u'DSA'), dbus.String(u'EC')], signature=dbus.Signature('s'))
++dbus.Array([dbus.String('RSA'), dbus.String('DSA'), dbus.String('EC')], signature=dbus.Signature('s'))
+ 
+ [ /org/fedorahosted/certmonger: org.fedorahosted.certmonger.get_supported_key_storage ]
+-dbus.Array([dbus.String(u'NSSDB'), dbus.String(u'FILE')], signature=dbus.Signature('s'))
++dbus.Array([dbus.String('NSSDB'), dbus.String('FILE')], signature=dbus.Signature('s'))
+ 
+ [ /org/fedorahosted/certmonger: org.fedorahosted.certmonger.get_supported_cert_storage ]
+-dbus.Array([dbus.String(u'NSSDB'), dbus.String(u'FILE')], signature=dbus.Signature('s'))
++dbus.Array([dbus.String('NSSDB'), dbus.String('FILE')], signature=dbus.Signature('s'))
+ 
+ [ /org/fedorahosted/certmonger : org.fedorahosted.certmonger.remove_known_ca ]
+ OK
+@@ -433,19 +431,19 @@ Buddy
+ 
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_cert_info ]
+-(dbus.String(u'CN=$UUID,CN=Local Signing Authority'), dbus.String(u'$UUID'), dbus.String(u'CN=localhost'), dbus.Int64(tomorrow), dbus.Array([], signature=dbus.Signature('s')), dbus.Array([dbus.String(u'localhost')], signature=dbus.Signature('s')), dbus.Array([dbus.String(u'host/localhost@LOCALHOST')], signature=dbus.Signature('s')), dbus.Int64(9L), dbus.Array([dbus.String(u'1.3.6.1.5.5.7.3.1')], signature=dbus.Signature('s')))
++(dbus.String('CN=$UUID,CN=Local Signing Authority'), dbus.String('$UUID'), dbus.String('CN=localhost'), dbus.Int64(tomorrow), dbus.Array([], signature=dbus.Signature('s')), dbus.Array([dbus.String('localhost')], signature=dbus.Signature('s')), dbus.Array([dbus.String('host/localhost@LOCALHOST')], signature=dbus.Signature('s')), dbus.Int64(9), dbus.Array([dbus.String('1.3.6.1.5.5.7.3.1')], signature=dbus.Signature('s')))
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_cert_last_checked ]
+ recently
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_cert_storage_info ]
+-(dbus.String(u'FILE'), dbus.String(u'$tmpdir/test.crt'))
++(dbus.String('FILE'), dbus.String('$tmpdir/test.crt'))
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_csr_data ]
+ 
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_csr_info ]
+-(dbus.String(u'CN=localhost'), dbus.Array([], signature=dbus.Signature('s')), dbus.Array([dbus.String(u'localhost')], signature=dbus.Signature('s')), dbus.Array([dbus.String(u'host/localhost@LOCALHOST')], signature=dbus.Signature('s')), dbus.Int64(9L), dbus.Array([dbus.String(u'id-kp-serverAuth')], signature=dbus.Signature('s')))
++(dbus.String('CN=localhost'), dbus.Array([], signature=dbus.Signature('s')), dbus.Array([dbus.String('localhost')], signature=dbus.Signature('s')), dbus.Array([dbus.String('host/localhost@LOCALHOST')], signature=dbus.Signature('s')), dbus.Int64(9), dbus.Array([dbus.String('id-kp-serverAuth')], signature=dbus.Signature('s')))
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_key_pin ]
+ 
+@@ -454,19 +452,19 @@ recently
+ 
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_key_storage_info ]
+-(dbus.String(u'FILE'), dbus.String(u'$tmpdir/test.key'))
++(dbus.String('FILE'), dbus.String('$tmpdir/test.key'))
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_key_type_and_size ]
+-(dbus.String(u'RSA'), dbus.Int64(512L))
++(dbus.String('RSA'), dbus.Int64(512))
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_monitoring ]
+ 1
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_notification_info ]
+-(dbus.String(u'stdout'), dbus.String(u'daemon.notice'))
++(dbus.String('stdout'), dbus.String('daemon.notice'))
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_status ]
+-(dbus.String(u'MONITORING'), dbus.Boolean(False))
++(dbus.String('MONITORING'), dbus.Boolean(False))
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_ca ]
+ /org/fedorahosted/certmonger/cas/CA1
+@@ -482,7 +480,7 @@ recently
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2 : org.fedorahosted.certmonger.request.modify ]
+ 1 on /org/fedorahosted/certmonger/requests/Request2
+-After setting template-eku to 1.2.3.4.5.6.7.8.9.10, we got dbus.Array([dbus.String(u'1.2.3.4.5.6.7.8.9.10')], signature=dbus.Signature('s'), variant_level=1)
++After setting template-eku to 1.2.3.4.5.6.7.8.9.10, we got dbus.Array([dbus.String('1.2.3.4.5.6.7.8.9.10')], signature=dbus.Signature('s'), variant_level=1)
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.rekey ]
+ 1
+@@ -713,7 +711,7 @@ dbus.Array([], signature=dbus.Signature('s'))
+ </node>
+ 
+ [ /org/fedorahosted/certmonger/cas/CA2: org.fedorahosted.certmonger.ca.get_config_file_path ]
+-$tmpdir/cas/20180327134236
++$tmpdir/cas/date
+ 
+ [ /org/fedorahosted/certmonger/cas/CA2: org.fedorahosted.certmonger.ca.get_nickname ]
+ SelfSign
+@@ -828,7 +826,7 @@ dbus.Array([], signature=dbus.Signature('s'))
+ </node>
+ 
+ [ /org/fedorahosted/certmonger/cas/CA3: org.fedorahosted.certmonger.ca.get_config_file_path ]
+-$tmpdir/cas/20180327134236-1
++$tmpdir/cas/date-1
+ 
+ [ /org/fedorahosted/certmonger/cas/CA3: org.fedorahosted.certmonger.ca.get_nickname ]
+ IPA
+@@ -941,7 +939,7 @@ dbus.Array([], signature=dbus.Signature('s'))
+ </node>
+ 
+ [ /org/fedorahosted/certmonger/cas/CA4: org.fedorahosted.certmonger.ca.get_config_file_path ]
+-$tmpdir/cas/20180327134236-2
++$tmpdir/cas/date-2
+ 
+ [ /org/fedorahosted/certmonger/cas/CA4: org.fedorahosted.certmonger.ca.get_nickname ]
+ certmaster
+@@ -1054,7 +1052,7 @@ dbus.Array([], signature=dbus.Signature('s'))
+ </node>
+ 
+ [ /org/fedorahosted/certmonger/cas/CA5: org.fedorahosted.certmonger.ca.get_config_file_path ]
+-$tmpdir/cas/20180327134236-3
++$tmpdir/cas/date-3
+ 
+ [ /org/fedorahosted/certmonger/cas/CA5: org.fedorahosted.certmonger.ca.get_nickname ]
+ dogtag-ipa-renew-agent
+diff --git a/tests/028-dbus/expected.out.nodsa b/tests/028-dbus/expected.out.nodsa
+index a23af40..5082ee0 100644
+--- a/tests/028-dbus/expected.out.nodsa
++++ b/tests/028-dbus/expected.out.nodsa
+@@ -187,13 +187,13 @@ dbus.Array([dbus.ObjectPath('/org/fedorahosted/certmonger/cas/CA1'), dbus.Object
+ dbus.Array([dbus.ObjectPath('/org/fedorahosted/certmonger/requests/Request2')], signature=dbus.Signature('o'))
+ 
+ [ /org/fedorahosted/certmonger: org.fedorahosted.certmonger.get_supported_key_types ]
+-dbus.Array([dbus.String(u'RSA'), dbus.String(u'EC')], signature=dbus.Signature('s'))
++dbus.Array([dbus.String('RSA'), dbus.String('EC')], signature=dbus.Signature('s'))
+ 
+ [ /org/fedorahosted/certmonger: org.fedorahosted.certmonger.get_supported_key_storage ]
+-dbus.Array([dbus.String(u'NSSDB'), dbus.String(u'FILE')], signature=dbus.Signature('s'))
++dbus.Array([dbus.String('NSSDB'), dbus.String('FILE')], signature=dbus.Signature('s'))
+ 
+ [ /org/fedorahosted/certmonger: org.fedorahosted.certmonger.get_supported_cert_storage ]
+-dbus.Array([dbus.String(u'NSSDB'), dbus.String(u'FILE')], signature=dbus.Signature('s'))
++dbus.Array([dbus.String('NSSDB'), dbus.String('FILE')], signature=dbus.Signature('s'))
+ 
+ [ /org/fedorahosted/certmonger : org.fedorahosted.certmonger.remove_known_ca ]
+ OK
+@@ -432,19 +432,19 @@ Buddy
+ 
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_cert_info ]
+-(dbus.String(u'CN=$UUID,CN=Local Signing Authority'), dbus.String(u'$UUID'), dbus.String(u'CN=localhost'), dbus.Int64(tomorrow), dbus.Array([], signature=dbus.Signature('s')), dbus.Array([dbus.String(u'localhost')], signature=dbus.Signature('s')), dbus.Array([dbus.String(u'host/localhost@LOCALHOST')], signature=dbus.Signature('s')), dbus.Int64(9L), dbus.Array([dbus.String(u'1.3.6.1.5.5.7.3.1')], signature=dbus.Signature('s')))
++(dbus.String('CN=$UUID,CN=Local Signing Authority'), dbus.String('$UUID'), dbus.String('CN=localhost'), dbus.Int64(tomorrow), dbus.Array([], signature=dbus.Signature('s')), dbus.Array([dbus.String('localhost')], signature=dbus.Signature('s')), dbus.Array([dbus.String('host/localhost@LOCALHOST')], signature=dbus.Signature('s')), dbus.Int64(9), dbus.Array([dbus.String('1.3.6.1.5.5.7.3.1')], signature=dbus.Signature('s')))
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_cert_last_checked ]
+ recently
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_cert_storage_info ]
+-(dbus.String(u'FILE'), dbus.String(u'$tmpdir/test.crt'))
++(dbus.String('FILE'), dbus.String('$tmpdir/test.crt'))
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_csr_data ]
+ 
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_csr_info ]
+-(dbus.String(u'CN=localhost'), dbus.Array([], signature=dbus.Signature('s')), dbus.Array([dbus.String(u'localhost')], signature=dbus.Signature('s')), dbus.Array([dbus.String(u'host/localhost@LOCALHOST')], signature=dbus.Signature('s')), dbus.Int64(9L), dbus.Array([dbus.String(u'id-kp-serverAuth')], signature=dbus.Signature('s')))
++(dbus.String('CN=localhost'), dbus.Array([], signature=dbus.Signature('s')), dbus.Array([dbus.String('localhost')], signature=dbus.Signature('s')), dbus.Array([dbus.String('host/localhost@LOCALHOST')], signature=dbus.Signature('s')), dbus.Int64(9), dbus.Array([dbus.String('id-kp-serverAuth')], signature=dbus.Signature('s')))
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_key_pin ]
+ 
+@@ -453,19 +453,19 @@ recently
+ 
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_key_storage_info ]
+-(dbus.String(u'FILE'), dbus.String(u'$tmpdir/test.key'))
++(dbus.String('FILE'), dbus.String('$tmpdir/test.key'))
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_key_type_and_size ]
+-(dbus.String(u'RSA'), dbus.Int64(512L))
++(dbus.String('RSA'), dbus.Int64(512))
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_monitoring ]
+ 1
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_notification_info ]
+-(dbus.String(u'stdout'), dbus.String(u'daemon.notice'))
++(dbus.String('stdout'), dbus.String('daemon.notice'))
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_status ]
+-(dbus.String(u'MONITORING'), dbus.Boolean(False))
++(dbus.String('MONITORING'), dbus.Boolean(False))
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.get_ca ]
+ /org/fedorahosted/certmonger/cas/CA1
+@@ -481,7 +481,7 @@ recently
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2 : org.fedorahosted.certmonger.request.modify ]
+ 1 on /org/fedorahosted/certmonger/requests/Request2
+-After setting template-eku to 1.2.3.4.5.6.7.8.9.10, we got dbus.Array([dbus.String(u'1.2.3.4.5.6.7.8.9.10')], signature=dbus.Signature('s'), variant_level=1)
++After setting template-eku to 1.2.3.4.5.6.7.8.9.10, we got dbus.Array([dbus.String('1.2.3.4.5.6.7.8.9.10')], signature=dbus.Signature('s'), variant_level=1)
+ 
+ [ /org/fedorahosted/certmonger/requests/Request2: org.fedorahosted.certmonger.request.rekey ]
+ 1
+diff --git a/tests/028-dbus/prequal.sh b/tests/028-dbus/prequal.sh
+index e645c19..4fe79c8 100755
+--- a/tests/028-dbus/prequal.sh
++++ b/tests/028-dbus/prequal.sh
+@@ -9,19 +9,19 @@ if test -z "$DBUSDAEMON" ; then
+ 	echo dbus-daemon not found
+ 	exit 1
+ fi
+-if ! python -c 'import os' 2> /dev/null ; then
++if ! python3 -c 'import os' 2> /dev/null ; then
+ 	echo python not found
+ 	exit 1
+ fi
+-if ! python -c 'import dbus' 2> /dev/null ; then
++if ! python3 -c 'import dbus' 2> /dev/null ; then
+ 	echo python-dbus not found
+ 	exit 1
+ fi
+-if ! python -c 'import xml' 2> /dev/null ; then
++if ! python3 -c 'import xml' 2> /dev/null ; then
+ 	echo python-xml not found
+ 	exit 1
+ fi
+-if ! python -c 'import xml.etree.ElementTree' 2> /dev/null ; then
++if ! python3 -c 'import xml.etree.ElementTree' 2> /dev/null ; then
+ 	echo python-xml does not include etree.ElementTree
+ 	exit 1
+ fi
+diff --git a/tests/028-dbus/run.sh b/tests/028-dbus/run.sh
+index c468d51..ee90875 100755
+--- a/tests/028-dbus/run.sh
++++ b/tests/028-dbus/run.sh
+@@ -23,7 +23,7 @@ EOF
+ $DBUSDAEMON --session --print-address=3 --print-pid=4 --fork 3> $tmpdir/address 4> $tmpdir/pid
+ if test -s $tmpdir/pid ; then
+ 	env DBUS_SESSION_BUS_ADDRESS=`cat $tmpdir/address` \
+-	$toolsdir/../../src/certmonger-session -n -c $tmpdir/runsub.sh
++	$toolsdir/../../src/certmonger-session -n -c $tmpdir/runsub.sh > /dev/null
+ fi
+ kill `cat $tmpdir/pid`
+ 
+@@ -33,8 +33,8 @@ now=`date +%s`
+ for i in `seq 240` ; do
+ 	recently=$(($now-$i))
+ 	tomorrow=$(($now-$i+24*60*60))
+-	sed -i -e s/^$recently'$/recently/g' -e s/"("$recently"L)"/'(recently)'/g \
+-	       -e s/^$tomorrow'$/tomorrow/g' -e s/"("$tomorrow"L)"/'(tomorrow)'/g $tmpdir/runsub.out
++	sed -i -e s/^$recently'$/recently/g' -e s/"("$recently")"/'(recently)'/g \
++	       -e s/^$tomorrow'$/tomorrow/g' -e s/"("$tomorrow")"/'(tomorrow)'/g $tmpdir/runsub.out
+ done
+ 
+ cat $tmpdir/runsub.out | \
+@@ -43,4 +43,5 @@ sed -r -e 's,CN=........-........-........-........,CN=$UUID,g' \
+        -e "s|$libexecdir|\$libexecdir|g" \
+        -e "s|$tmpdir|\$tmpdir|g" \
+        -e "s|expires:.*|expires: sometime|g" \
+-       -e "s|u'(00)?[0-9a-fA-F]{32}|u'"'$UUID|g'
++       -e "s|'(00)?[0-9a-fA-F]{32}|'"'$UUID|g' \
++       -e "s|cas\/[0-9]{14}|cas\/date|g"
+diff --git a/tests/028-dbus/runsub.sh b/tests/028-dbus/runsub.sh
+index 3510d79..fe6766c 100755
+--- a/tests/028-dbus/runsub.sh
++++ b/tests/028-dbus/runsub.sh
+@@ -22,5 +22,5 @@ echo ""
+ echo "[[ API ]]"
+ for i in ./*.py ; do
+ 	echo "[" `basename "$i"` "]"
+-	python $i
++	python3 $i
+ done
+diff --git a/tests/028-dbus/simpleprop.py b/tests/028-dbus/simpleprop.py
+index e4f937e..35d9591 100644
+--- a/tests/028-dbus/simpleprop.py
++++ b/tests/028-dbus/simpleprop.py
+@@ -1,4 +1,4 @@
+-#!/usr/bin/python
++#!/usr/bin/python3
+ import dbus
+ 
+ # Get a handle for the main certmonger interface.
+@@ -19,7 +19,7 @@ ca = dbus.Interface(o, 'org.freedesktop.DBus.Properties')
+ 
+ # Toggle the helper a couple of times.
+ ca_ext_h = o.Get('org.fedorahosted.certmonger.ca', 'external-helper')
+-print ca_ext_h, "->",
++print(ca_ext_h, "-> ", end='')
+ 
+ if ca_ext_h.split()[0] == ca_ext_h:
+     ca_ext_h += ' -k admin@localhost'
+@@ -28,7 +28,7 @@ else:
+ ca.Set('org.fedorahosted.certmonger.ca', 'external-helper', ca_ext_h)
+ 
+ ca_ext_h = o.Get('org.fedorahosted.certmonger.ca', 'external-helper')
+-print ca_ext_h, "->",
++print(ca_ext_h, "-> ", end='')
+ 
+ if ca_ext_h.split()[0] == ca_ext_h:
+     ca_ext_h += ' -k admin@localhost'
+@@ -37,20 +37,20 @@ else:
+ ca.Set('org.fedorahosted.certmonger.ca', 'external-helper', ca_ext_h)
+ 
+ ca_ext_h = o.Get('org.fedorahosted.certmonger.ca', 'external-helper')
+-print ca_ext_h
++print(ca_ext_h)
+ 
+ # Toggle the "is-default" value a couple of times.
+ isdef = ca.Get('org.fedorahosted.certmonger.ca', 'is-default')
+-print isdef, "->",
++print(isdef, "-> ", end='')
+ 
+ ca.Set('org.fedorahosted.certmonger.ca', 'is-default', not isdef)
+ 
+ isdef = ca.Get('org.fedorahosted.certmonger.ca', 'is-default')
+-print isdef, "->",
++print(isdef, "-> ", end='')
+ 
+ ca.Set('org.fedorahosted.certmonger.ca', 'is-default', not isdef)
+ 
+ isdef = ca.Get('org.fedorahosted.certmonger.ca', 'is-default')
+-print isdef
++print(isdef)
+ 
+ cm.remove_known_ca(path)
+diff --git a/tests/028-dbus/walk.py b/tests/028-dbus/walk.py
+index f60ca93..683d94e 100644
+--- a/tests/028-dbus/walk.py
++++ b/tests/028-dbus/walk.py
+@@ -1,4 +1,4 @@
+-#!/usr/bin/python
++#!/usr/bin/python3
+ import dbus
+ import xml.etree.ElementTree
+ import os
+@@ -9,217 +9,219 @@ bus = dbus.SessionBus()
+ 
+ # Check that reading a property directly produces the same value as reading it via GetAll().
+ def check_props(objpath, interface):
+-	o = bus.get_object('org.fedorahosted.certmonger', objpath)
+-	i = dbus.Interface(o, 'org.freedesktop.DBus.Properties')
+-	props = i.GetAll(interface)
+-	for prop in props.keys():
+-		value = props[prop]
+-		if value != i.Get(interface, prop):
+-			print("%s: property %s.%s mismatch (%s, %s)" % (objpath, interface, prop, value, i.Get(interface, prop)))
+-			return False
+-	return True
++    o = bus.get_object('org.fedorahosted.certmonger', objpath)
++    i = dbus.Interface(o, 'org.freedesktop.DBus.Properties')
++    props = i.GetAll(interface)
++    for prop in props.keys():
++        value = props[prop]
++        if value != i.Get(interface, prop):
++            print("%s: property %s.%s mismatch (%s, %s)" % (objpath, interface, prop, value, i.Get(interface, prop)))
++            return False
++    return True
+ 
+ # Try to call the method.
+ def examine_method(objpath, interface, method, idata):
+-	in_args = 0
+-	out_args = 0
+-	o = bus.get_object('org.fedorahosted.certmonger', objpath)
+-	i = dbus.Interface(o, interface)
+-	for child in idata.getchildren():
+-		if child.tag == 'arg':
+-			if child.get('direction') != 'out':
+-				in_args = in_args + 1
+-			else:
+-				out_args = out_args + 1
+-	if in_args == 0:
+-		# Takes no inputs, so just call it.
+-		m = i.get_dbus_method(method)
+-		if out_args == 0:
+-			m()
+-			print("[ %s: %s.%s ]\n" % (objpath, interface, method))
+-		elif out_args == 1:
+-			result = m()
+-			print("[ %s: %s.%s ]\n%s\n" % (objpath, interface, method, result))
+-		else:
+-			result = m()
+-			print("[ %s: %s.%s ]\n%s\n" % (objpath, interface, method, result))
+-	elif method == 'Get' or method == 'Set' or method == 'GetAll':
+-		# We check on properties elsewhere.
+-		return True
+-	# Per-method exercise.
+-	elif method == 'add_known_ca' or method == 'remove_known_ca':
+-		(result, path) = i.add_known_ca('Test CA', '/usr/bin/env', [])
+-		if not result:
+-			print("[ %s : %s.%s ]: add_known_ca error\n" % (objpath, interface, method))
+-			return False
+-		result = i.remove_known_ca(path)
+-		if not result:
+-			print("[ %s : %s.%s ]: remove_known_ca error\n" % (objpath, interface, method))
+-			return False
+-		print("[ %s : %s.%s ]\nOK\n" % (objpath, interface, method))
+-	elif method == 'add_request' or method == 'remove_request':
+-		tmpdir = os.getenv('TMPDIR')
+-		if not tmpdir or tmpdir == '':
+-			tmpdir = '/tmp'
+-		properties = {
+-			'nickname': 'foo',
+-			'cert-storage': 'file',
+-			'cert-file': tmpdir + "/028-certfile",
+-			'key-storage': 'file',
+-			'key-file': tmpdir + "/028-keyfile",
+-			'template-email': ['root@localhost', 'toor@localhost'],
+-		}
+-		(result, path) = i.add_request(properties)
+-		if not result:
+-			print("[ %s : %s.%s ]: add_request error\n" % (objpath, interface, method))
+-			return False
+-		result = i.remove_request(path)
+-		if not result:
+-			print("[ %s : %s.%s ]: remove_request error\n" % (objpath, interface, method))
+-			return False
+-		print("[ %s : %s.%s ]\nOK\n" % (objpath, interface, method))
+-	elif method == 'find_ca_by_nickname':
+-		capath = i.find_ca_by_nickname('local')
+-		o = bus.get_object('org.fedorahosted.certmonger', capath)
+-		i = dbus.Interface(o, 'org.freedesktop.DBus.Properties')
+-		if i.Get('org.fedorahosted.certmonger.ca', 'nickname') != 'local':
+-			print("[ %s : %s.%s ] error: %s\n" % (objpath, interface, method, i.Get('org.fedorahosted.certmonger.ca', 'nickname')))
+-			return False
+-		print("[ %s : %s.%s ]\nOK\n" % (objpath, interface, method))
+-	elif method == 'find_request_by_nickname':
+-		reqpath = i.find_request_by_nickname('Buddy')
+-		o = bus.get_object('org.fedorahosted.certmonger', reqpath)
+-		i = dbus.Interface(o, 'org.freedesktop.DBus.Properties')
+-		if i.Get('org.fedorahosted.certmonger.request', 'nickname') != 'Buddy':
+-			print("[ %s : %s.%s ] error: %s\n" % (objpath, interface, method, i.Get('org.fedorahosted.certmonger.request', 'nickname')))
+-			return False
+-		print("[ %s : %s.%s ]\nOK\n" % (objpath, interface, method))
+-	elif method == 'modify':
+-		mods = {}
+-		propname = "template-eku"
+-		propval = '1.2.3.4.5.6.7.8.9.10'
+-		mods[propname] = [propval,]
+-		status, path = i.modify(mods)
+-		if not status:
+-			print("[ %s : %s.%s ] error\n" % (objpath, interface, method))
+-			return False
+-		print("[ %s : %s.%s ]\n%d on %s" % (objpath, interface, method, status, path))
+-		props = dbus.Interface(o, 'org.freedesktop.DBus.Properties')
+-		prop = props.Get(interface, 'template-eku')
+-		print("After setting %s to %s, we got %s\n" % (propname, propval, prop))
+-	else:
+-		# We're in FIXME territory.
+-		print('FIXME: need support for "%s"' % method)
+-		return False
+-	# If we caused things to start churning, wait for them to settle.
++    in_args = 0
++    out_args = 0
++    o = bus.get_object('org.fedorahosted.certmonger', objpath)
++    i = dbus.Interface(o, interface)
++    for child in idata.getchildren():
++        if child.tag == 'arg':
++            if child.get('direction') != 'out':
++                in_args = in_args + 1
++            else:
++                out_args = out_args + 1
++    if in_args == 0:
++        # Takes no inputs, so just call it.
++        m = i.get_dbus_method(method)
++        if out_args == 0:
++            m()
++            print("[ %s: %s.%s ]\n" % (objpath, interface, method))
++        elif out_args == 1:
++            result = m()
++            print("[ %s: %s.%s ]\n%s\n" % (objpath, interface, method, result))
++        else:
++            result = m()
++            print("[ %s: %s.%s ]\n%s\n" % (objpath, interface, method, result))
++    elif method == 'Get' or method == 'Set' or method == 'GetAll':
++        # We check on properties elsewhere.
++        return True
++    # Per-method exercise.
++    elif method == 'add_known_ca' or method == 'remove_known_ca':
++        (result, path) = i.add_known_ca('Test CA', '/usr/bin/env', [])
++        if not result:
++            print("[ %s : %s.%s ]: add_known_ca error\n" % (objpath, interface, method))
++            return False
++        result = i.remove_known_ca(path)
++        if not result:
++            print("[ %s : %s.%s ]: remove_known_ca error\n" % (objpath, interface, method))
++            return False
++        print("[ %s : %s.%s ]\nOK\n" % (objpath, interface, method))
++    elif method == 'add_request' or method == 'remove_request':
++        tmpdir = os.getenv('TMPDIR')
++        if not tmpdir or tmpdir == '':
++            tmpdir = '/tmp'
++        properties = {
++            'nickname': 'foo',
++            'cert-storage': 'file',
++            'cert-file': tmpdir + "/028-certfile",
++            'key-storage': 'file',
++            'key-file': tmpdir + "/028-keyfile",
++            'template-email': ['root@localhost', 'toor@localhost'],
++        }
++        (result, path) = i.add_request(properties)
++        if not result:
++            print("[ %s : %s.%s ]: add_request error\n" % (objpath, interface, method))
++            return False
++        result = i.remove_request(path)
++        if not result:
++            print("[ %s : %s.%s ]: remove_request error\n" % (objpath, interface, method))
++            return False
++        print("[ %s : %s.%s ]\nOK\n" % (objpath, interface, method))
++    elif method == 'find_ca_by_nickname':
++        capath = i.find_ca_by_nickname('local')
++        o = bus.get_object('org.fedorahosted.certmonger', capath)
++        i = dbus.Interface(o, 'org.freedesktop.DBus.Properties')
++        if i.Get('org.fedorahosted.certmonger.ca', 'nickname') != 'local':
++            print("[ %s : %s.%s ] error: %s\n" % (objpath, interface, method, i.Get('org.fedorahosted.certmonger.ca', 'nickname')))
++            return False
++        print("[ %s : %s.%s ]\nOK\n" % (objpath, interface, method))
++    elif method == 'find_request_by_nickname':
++        reqpath = i.find_request_by_nickname('Buddy')
++        if not reqpath:
++            return False
++        o = bus.get_object('org.fedorahosted.certmonger', reqpath)
++        i = dbus.Interface(o, 'org.freedesktop.DBus.Properties')
++        if i.Get('org.fedorahosted.certmonger.request', 'nickname') != 'Buddy':
++            print("[ %s : %s.%s ] error: %s\n" % (objpath, interface, method, i.Get('org.fedorahosted.certmonger.request', 'nickname')))
++            return False
++        print("[ %s : %s.%s ]\nOK\n" % (objpath, interface, method))
++    elif method == 'modify':
++        mods = {}
++        propname = "template-eku"
++        propval = '1.2.3.4.5.6.7.8.9.10'
++        mods[propname] = [propval,]
++        status, path = i.modify(mods)
++        if not status:
++            print("[ %s : %s.%s ] error\n" % (objpath, interface, method))
++            return False
++        print("[ %s : %s.%s ]\n%d on %s" % (objpath, interface, method, status, path))
++        props = dbus.Interface(o, 'org.freedesktop.DBus.Properties')
++        prop = props.Get(interface, 'template-eku')
++        print("After setting %s to %s, we got %s\n" % (propname, propval, prop))
++    else:
++        # We're in FIXME territory.
++        print('FIXME: need support for "%s"' % method)
++        return False
++    # If we caused things to start churning, wait for them to settle.
+         if method == 'resubmit':
+             props = dbus.Interface(o, 'org.freedesktop.DBus.Properties')
+             prop = props.Get(interface, 'status')
+             while prop != 'MONITORING':
+                 time.sleep(1)
+                 prop = props.Get(interface, 'status')
+-	return True
++    return True
+ 
+ def iget(child, proxy, interface, prop):
+-	value = proxy.Get(interface, prop)
+-	if not value:
+-		if child.get('type') == 'b':
+-			value = False
+-		elif child.get('type') == 'n' or child.get('type') == 'x':
+-			value = 0
+-		elif child.get('type') == 's':
+-			value = ''
+-		elif child.get('type') == 'as':
+-			value = ['']
+-		else:
+-			print("%s.%s: %s" % (interface, prop, child.get('type')))
+-			return False
+-	return value
++    value = proxy.Get(interface, prop)
++    if not value:
++        if child.get('type') == 'b':
++            value = False
++        elif child.get('type') == 'n' or child.get('type') == 'x':
++            value = 0
++        elif child.get('type') == 's':
++            value = ''
++        elif child.get('type') == 'as':
++            value = ['']
++        else:
++            print("%s.%s: %s" % (interface, prop, child.get('type')))
++            return False
++    return value
+ 
+ def examine_interface(objpath, interface, idata):
+-	o = bus.get_object('org.fedorahosted.certmonger', objpath)
+-	i = dbus.Interface(o, 'org.freedesktop.DBus.Properties')
+-	for child in idata.getchildren():
+-		if child.tag == 'property':
+-			prop = child.get('name')
+-			if child.get('access') == 'read':
+-				# Check that we can read it.
+-				value = i.Get(interface, prop)
+-			elif child.get('access') == 'readwrite':
+-				if prop == 'external-helper' or prop == 'scep-ca-identifier':
+-					cai = dbus.Interface(o, 'org.fedorahosted.certmonger.ca')
+-					if cai.get_type() != 'EXTERNAL':
+-						print("%s: warning: property %s.%s not settable on this object" % (objpath, interface, prop))
+-						continue
+-				# Check that we can read it, tweak it, and then reset it.
+-				value = iget(child, i, interface, prop)
+-				i.Set(interface, prop, value)
+-				newvalue = None
+-				if child.get('type') == 'b':
+-					newvalue = not value
+-				elif child.get('type') == 'n' or child.get('type') == 'x':
+-					newvalue = value + 1
+-				elif child.get('type') == 's':
+-					newvalue = 'x' + value
+-				elif child.get('type') == 'as':
+-					newvalue = ['x'] + value
+-				else:
+-					print("%s.%s: %s" % (interface, prop, child.get('type')))
+-					return False
+-				if newvalue:
+-					if newvalue == value:
+-						print("%s: error determining new value: (%s, %s): %s" % (objpath, interface, prop, value))
+-						return False
+-					i.Set(interface, prop, newvalue)
+-					if newvalue != iget(child, i, interface, prop):
+-						print("%s: property %s.%s not set: (%s, %s)" % (objpath, interface, prop, value, newvalue))
+-						return False
+-					i.Set(interface, prop, value)
+-					if value != iget(child, i, interface, prop):
+-						print("%s: property %s.%s not reset: (%s, %s)" % (objpath, interface, prop, newvalue, value))
+-						return False
+-		elif child.tag == 'method':
+-			method = child.get('name')
+-			if not examine_method(objpath, interface, method, child):
+-				return False
+-		elif child.tag == 'signal':
+-			continue
+-		else:
+-			print "FIXME: handle child tag %s" % child.tag
+-			return False
+-	return True
++    o = bus.get_object('org.fedorahosted.certmonger', objpath)
++    i = dbus.Interface(o, 'org.freedesktop.DBus.Properties')
++    for child in idata.getchildren():
++        if child.tag == 'property':
++            prop = child.get('name')
++            if child.get('access') == 'read':
++                # Check that we can read it.
++                value = i.Get(interface, prop)
++            elif child.get('access') == 'readwrite':
++                if prop == 'external-helper' or prop == 'scep-ca-identifier':
++                    cai = dbus.Interface(o, 'org.fedorahosted.certmonger.ca')
++                    if cai.get_type() != 'EXTERNAL':
++                        print("%s: warning: property %s.%s not settable on this object" % (objpath, interface, prop))
++                        continue
++                # Check that we can read it, tweak it, and then reset it.
++                value = iget(child, i, interface, prop)
++                i.Set(interface, prop, value)
++                newvalue = None
++                if child.get('type') == 'b':
++                    newvalue = not value
++                elif child.get('type') == 'n' or child.get('type') == 'x':
++                    newvalue = value + 1
++                elif child.get('type') == 's':
++                    newvalue = 'x' + value
++                elif child.get('type') == 'as':
++                    newvalue = ['x'] + value
++                else:
++                    print("%s.%s: %s" % (interface, prop, child.get('type')))
++                    return False
++                if newvalue:
++                    if newvalue == value:
++                        print("%s: error determining new value: (%s, %s): %s" % (objpath, interface, prop, value))
++                        return False
++                    i.Set(interface, prop, newvalue)
++                    if newvalue != iget(child, i, interface, prop):
++                        print("%s: property %s.%s not set: (%s, %s)" % (objpath, interface, prop, value, newvalue))
++                        return False
++                    i.Set(interface, prop, value)
++                    if value != iget(child, i, interface, prop):
++                        print("%s: property %s.%s not reset: (%s, %s)" % (objpath, interface, prop, newvalue, value))
++                        return False
++        elif child.tag == 'method':
++            method = child.get('name')
++            if not examine_method(objpath, interface, method, child):
++                return False
++        elif child.tag == 'signal':
++            continue
++        else:
++            print("FIXME: handle child tag %s" % child.tag)
++            return False
++    return True
+ 
+ def examine_object(objpath):
+-	o = bus.get_object('org.fedorahosted.certmonger', objpath)
+-	i = dbus.Interface(o, 'org.freedesktop.DBus.Introspectable')
+-	idata = i.Introspect()
+-	x = xml.etree.ElementTree.XML(idata)
++    o = bus.get_object('org.fedorahosted.certmonger', objpath)
++    i = dbus.Interface(o, 'org.freedesktop.DBus.Introspectable')
++    idata = i.Introspect()
++    x = xml.etree.ElementTree.XML(idata)
+ 
+-	# Check if the object supports properties interfaces.
+-	props = False
+-	for child in x.getchildren():
+-		if child.tag == 'interface':
+-			if child.get('name') == 'org.freedesktop.DBus.Properties':
+-				props = True
++    # Check if the object supports properties interfaces.
++    props = False
++    for child in x.getchildren():
++        if child.tag == 'interface':
++            if child.get('name') == 'org.freedesktop.DBus.Properties':
++                props = True
+ 
+-	# Look at the interfaces and child nodes.
+-	for child in x.getchildren():
+-		if child.tag == 'interface':
+-			if props and not check_props(objpath, child.get('name')):
+-				return False
+-			if not examine_interface(objpath, child.get('name'), child):
+-				return False
+-		elif child.tag == 'node':
+-			if objpath == '/':
+-				childpath = '/' + child.get('name')
+-			else:
+-				childpath = objpath + '/' + child.get('name')
+-			examine_object(childpath)
+-		else:
+-			print "FIXME: handle child tag %s" % child.tag
+-			return False
+-	return True
++    # Look at the interfaces and child nodes.
++    for child in x.getchildren():
++        if child.tag == 'interface':
++            if props and not check_props(objpath, child.get('name')):
++                return False
++            if not examine_interface(objpath, child.get('name'), child):
++                return False
++        elif child.tag == 'node':
++            if objpath == '/':
++                childpath = '/' + child.get('name')
++            else:
++                childpath = objpath + '/' + child.get('name')
++            examine_object(childpath)
++        else:
++            print("FIXME: handle child tag %s" % child.tag)
++            return False
++    return True
+ 
+ if not examine_object('/'):
+-	sys.exit(1)
++    sys.exit(1)
+ sys.exit(0)
+diff --git a/tests/038-ms-v2-template/extract-extdata.py b/tests/038-ms-v2-template/extract-extdata.py
+index 1a845fd..9f9d910 100755
+--- a/tests/038-ms-v2-template/extract-extdata.py
++++ b/tests/038-ms-v2-template/extract-extdata.py
+@@ -1,10 +1,11 @@
+-#!/usr/bin/python2
++#!/usr/bin/python3
+ 
+ # Given `openssl asn1parse` output of a CSR, look for the V2 Template
+ # extension and output its data if found.  Nonzero exit status if
+ # not found.
+ 
+ import binascii
++import os
+ import re
+ import sys
+ 
+@@ -21,7 +22,7 @@ for line in sys.stdin:
+     #
+     if state == STATE_FOUND and 'OCTET STRING' in line:
+         result = re.search(r'\[HEX DUMP\]:(\w*)', line)
+-        sys.stdout.write(binascii.unhexlify(result.group(1)))
++        os.write(1, binascii.unhexlify(result.group(1)))
+         state = STATE_DONE
+         break
+ 
+-- 
+2.17.0
+
diff --git a/SOURCES/0003-Use-the-correct-slot-when-saving-certificates-in-NSS.patch b/SOURCES/0003-Use-the-correct-slot-when-saving-certificates-in-NSS.patch
new file mode 100644
index 0000000..a5a897f
--- /dev/null
+++ b/SOURCES/0003-Use-the-correct-slot-when-saving-certificates-in-NSS.patch
@@ -0,0 +1,1016 @@
+From 3da0e186904ad81dd87cf74bfae88270f14bb770 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Tue, 21 Aug 2018 17:25:21 -0400
+Subject: [PATCH 1/7] Use the correct slot when saving certificates in NSS
+
+Certificates were always stored in the NSS certdb.
+---
+ src/certsave-n.c | 915 ++++++++++++++++++++++++++++---------------------------
+ 1 file changed, 474 insertions(+), 441 deletions(-)
+
+diff --git a/src/certsave-n.c b/src/certsave-n.c
+index 8e15a18a..af176ce5 100644
+--- a/src/certsave-n.c
++++ b/src/certsave-n.c
+@@ -92,7 +92,11 @@ cm_certsave_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 	SECStatus error;
+ 	SECItem *item, subject;
+ 	char *p, *q, *pin;
++	const char *token;
+ 	const char *es;
++	PK11SlotList *slotlist;
++	PK11SlotListElement *sle;
++	CK_MECHANISM_TYPE mech;
+ 	NSSInitContext *ctx;
+ 	CERTCertDBHandle *certdb;
+ 	CERTCertList *certlist;
+@@ -192,231 +196,253 @@ cm_certsave_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 			}
+ 			_exit(CM_CERTSAVE_STATUS_INTERNAL_ERROR);
+ 		}
+-		/* Be ready to count our uses of a PIN. */
+-		memset(&cb_data, 0, sizeof(cb_data));
+-		cb_data.entry = entry;
+-		cb_data.n_attempts = 0;
+-		pin = NULL;
+-		if (cm_pin_read_for_key(entry, &pin) != 0) {
+-			cm_log(1, "Error reading PIN for key store, "
+-			       "failing to save certificate.\n");
++		/* Find the tokens that we might use for cert storage. */
++		mech = CKM_RSA_X_509;
++		slotlist = PK11_GetAllTokens(mech, PR_FALSE, PR_FALSE, NULL);
++		if (slotlist == NULL) {
++			cm_log(1, "Error getting list of tokens.\n");
+ 			PORT_FreeArena(arena, PR_TRUE);
+-			error = NSS_ShutdownContext(ctx);
+-			if (error != SECSuccess) {
++			if (NSS_ShutdownContext(ctx) != SECSuccess) {
+ 				cm_log(1, "Error shutting down NSS.\n");
+ 			}
+-			_exit(CM_CERTSAVE_STATUS_AUTH);
++			_exit(2);
+ 		}
+-		/* Set a PIN if we're supposed to be using one and aren't using
+-		 * one yet in this database. */
+-		if (PK11_NeedUserInit(PK11_GetInternalKeySlot())) {
+-			PK11_InitPin(PK11_GetInternalKeySlot(), NULL,
+-				     pin ? pin : "");
+-			ec = PORT_GetError();
+-			if (ec != 0) {
+-				es = PR_ErrorToName(ec);
++		/* Walk the list looking for the requested slot, or the first one if
++		 * none was requested. */
++		if (cm_pin_read_for_cert(entry, &pin) != 0) {
++			cm_log(1, "Error reading PIN for cert db.\n");
++			_exit(CM_SUB_STATUS_ERROR_AUTH);
++		}
++		PK11_SetPasswordFunc(&cm_pin_read_for_cert_nss_cb);
++		for (sle = slotlist->head;
++		     ((sle != NULL) && (sle->slot != NULL));
++		     sle = sle->next)
++		{
++			/* Log the slot's name. */
++			token = PK11_GetTokenName(sle->slot);
++			if (token != NULL) {
++				cm_log(3, "Found token '%s'.\n", token);
+ 			} else {
+-				es = NULL;
++				cm_log(3, "Found unnamed token.\n");
+ 			}
+-			if (PK11_NeedUserInit(PK11_GetInternalKeySlot())) {
+-				if (es != NULL) {
+-					cm_log(1, "Key storage slot still "
+-					       "needs user PIN to be set: "
+-					       "%s.\n", es);
+-				} else {
+-					cm_log(1, "Key storage slot still "
+-					       "needs user PIN to be set.\n");
+-				}
++			/* If we're looking for a specific slot, and this isn't it,
++			 * keep going. */
++			if ((entry->cm_cert_token != NULL) &&
++			    ((token == NULL) ||
++			     (strcmp(entry->cm_cert_token, token) != 0))) {
++					if (token != NULL) {
++						cm_log(1,
++						       "Token is named \"%s\", not \"%s\", "
++						       "skipping.\n",
++						       token, entry->cm_cert_token);
++					} else {
++						cm_log(1,
++						       "Token is unnamed, not \"%s\", "
++						       "skipping.\n",
++						       entry->cm_cert_token);
++					}
++					goto next_slot;
++			}
++			/* Be ready to count our uses of a PIN. */
++			memset(&cb_data, 0, sizeof(cb_data));
++			cb_data.entry = entry;
++			cb_data.n_attempts = 0;
++			pin = NULL;
++			if (cm_pin_read_for_key(entry, &pin) != 0) {
++				cm_log(1, "Error reading PIN for key store, "
++				       "failing to save certificate.\n");
+ 				PORT_FreeArena(arena, PR_TRUE);
+ 				error = NSS_ShutdownContext(ctx);
+ 				if (error != SECSuccess) {
+ 					cm_log(1, "Error shutting down NSS.\n");
+ 				}
+-				switch (ec) {
+-				case PR_NO_ACCESS_RIGHTS_ERROR: /* EACCES or EPERM */
+-					_exit(CM_CERTSAVE_STATUS_PERMS);
+-					break;
+-				default:
+-					_exit(CM_CERTSAVE_STATUS_AUTH);
+-					break;
+-				}
++				_exit(CM_CERTSAVE_STATUS_AUTH);
+ 			}
+-			/* We're authenticated now, so count this as a use of
+-			 * the PIN. */
+-			if ((pin != NULL) && (strlen(pin) > 0)) {
+-				cb_data.n_attempts++;
+-			}
+-		}
+-		/* Log in, if case we need to muck around with the key
+-		 * database. */
+-		PK11_SetPasswordFunc(&cm_pin_read_for_key_nss_cb);
+-		error = PK11_Authenticate(PK11_GetInternalKeySlot(), PR_TRUE,
+-					  &cb_data);
+-		ec = PORT_GetError();
+-		if (error != SECSuccess) {
+-			if (ec != 0) {
++			if (PK11_NeedUserInit(sle->slot)) {
++				PK11_InitPin(sle->slot, NULL, pin ? pin : "");
++				ec = PORT_GetError();
+ 				es = PR_ErrorToName(ec);
+-			} else {
+-				es = NULL;
+-			}
+-			if (es != NULL) {
+-				cm_log(1, "Error authenticating to key store: %s.\n",
+-				       es);
+-			} else {
+-				cm_log(1, "Error authenticating to key store.\n");
+-			}
+-			PORT_FreeArena(arena, PR_TRUE);
+-			error = NSS_ShutdownContext(ctx);
+-			if (error != SECSuccess) {
+-				cm_log(1, "Error shutting down NSS.\n");
+-			}
+-			_exit(CM_CERTSAVE_STATUS_AUTH);
+-		}
+-		if ((pin != NULL) &&
+-		    (strlen(pin) > 0) &&
+-		    (cb_data.n_attempts == 0)) {
+-			cm_log(1, "PIN was not needed to auth to key "
+-			       "store, though one was provided. "
+-			       "Treating this as an error.\n");
+-			PORT_FreeArena(arena, PR_TRUE);
+-			error = NSS_ShutdownContext(ctx);
+-			if (error != SECSuccess) {
+-				cm_log(1, "Error shutting down NSS.\n");
+-			}
+-			_exit(CM_CERTSAVE_STATUS_AUTH);
+-		}
+-		certdb = CERT_GetDefaultCertDB();
+-		if (certdb != NULL) {
+-			/* Strip the header and footer. */
+-			p = entry->cm_cert;
+-			q = NULL;
+-			if (p != NULL) {
+-				while (strncmp(p, "-----BEGIN ", 11) == 0) {
+-					p += strcspn(p, "\r\n");
+-					p += strspn(p, "\r\n");
++				if (PK11_NeedUserInit(sle->slot)) {
++					if (es != NULL) {
++						cm_log(1, "Key storage slot still "
++						   "needs user PIN to be set: "
++						   "%s.\n", es);
++						} else {
++						cm_log(1, "Key storage slot still "
++						   "needs user PIN to be set.\n");
++					}
++					PORT_FreeArena(arena, PR_TRUE);
++					error = NSS_ShutdownContext(ctx);
++					if (error != SECSuccess) {
++						cm_log(1, "Error shutting down NSS.\n");
++					}
++					switch (ec) {
++						case PR_NO_ACCESS_RIGHTS_ERROR: /* EACCES or EPERM */
++							_exit(CM_CERTSAVE_STATUS_PERMS);
++							break;
++						default:
++							_exit(CM_CERTSAVE_STATUS_AUTH);
++							break;
++					}
+ 				}
+-				q = strstr(p, "-----END");
++				/* count this as use of the PIN */
++				cb_data.n_attempts++;
+ 			}
+-			if ((q == NULL) || (*p == '\0')) {
+-				cm_log(1, "Unable to parse certificate.\n");
+-				PORT_FreeArena(arena, PR_TRUE);
+-				if (NSS_ShutdownContext(ctx) != SECSuccess) {
+-					cm_log(1, "Error shutting down NSS.\n");
++			if (PK11_NeedLogin(sle->slot)) {
++				error = PK11_Authenticate(sle->slot, PR_TRUE, &cb_data);
++				if (error != SECSuccess) {
++					cm_log(1, "Error authenticating to cert db for token "
++							  "%s.\n", token);
++					goto next_slot;
+ 				}
+-				_exit(CM_CERTSAVE_STATUS_INTERNAL_ERROR);
++			    cb_data.n_attempts++;
+ 			}
+-			/* Handle the base64 decode. */
+-			item = NSSBase64_DecodeBuffer(arena, NULL, p, q - p);
+-			if (item == NULL) {
+-				cm_log(1, "Unable to decode certificate "
+-				       "into buffer.\n");
++			if ((pin != NULL) &&
++			    (strlen(pin) > 0) &&
++			    (cb_data.n_attempts == 0)) {
++				cm_log(1, "PIN was not needed to auth to key "
++				       "store, though one was provided. "
++				       "Treating this as an error.\n");
+ 				PORT_FreeArena(arena, PR_TRUE);
+-				if (NSS_ShutdownContext(ctx) != SECSuccess) {
++				error = NSS_ShutdownContext(ctx);
++				if (error != SECSuccess) {
+ 					cm_log(1, "Error shutting down NSS.\n");
+ 				}
+-				_exit(CM_CERTSAVE_STATUS_INTERNAL_ERROR);
++				_exit(CM_CERTSAVE_STATUS_AUTH);
+ 			}
+-			/* Do a "shallow" decode to pull out the subject name
+-			 * so that we can check for a conflict. */
+-			memset(&csdata, 0, sizeof(csdata));
+-			if (SEC_ASN1DecodeItem(arena, &csdata,
+-					       CERT_SignedDataTemplate,
+-					       item) != SECSuccess) {
+-				cm_log(1, "Unable to decode certificate "
+-				       "signed data into buffer.\n");
+-				PORT_FreeArena(arena, PR_TRUE);
+-				if (NSS_ShutdownContext(ctx) != SECSuccess) {
+-					cm_log(1, "Error shutting down NSS.\n");
++			certdb = CERT_GetDefaultCertDB();
++			if (certdb != NULL) {
++				/* Strip the header and footer. */
++				p = entry->cm_cert;
++				q = NULL;
++				if (p != NULL) {
++					while (strncmp(p, "-----BEGIN ", 11) == 0) {
++						p += strcspn(p, "\r\n");
++						p += strspn(p, "\r\n");
++					}
++					q = strstr(p, "-----END");
+ 				}
+-				_exit(CM_CERTSAVE_STATUS_INTERNAL_ERROR);
+-			}
+-			memset(&cert, 0, sizeof(cert));
+-			if (SEC_ASN1DecodeItem(arena, &cert,
+-					       CERT_CertificateTemplate,
+-					       &csdata.data) != SECSuccess) {
+-				cm_log(1, "Unable to decode certificate "
+-				       "data into buffer.\n");
+-				PORT_FreeArena(arena, PR_TRUE);
+-				if (NSS_ShutdownContext(ctx) != SECSuccess) {
+-					cm_log(1, "Error shutting down NSS.\n");
++				if ((q == NULL) || (*p == '\0')) {
++					cm_log(1, "Unable to parse certificate.\n");
++					PORT_FreeArena(arena, PR_TRUE);
++					if (NSS_ShutdownContext(ctx) != SECSuccess) {
++						cm_log(1, "Error shutting down NSS.\n");
++					}
++					_exit(CM_CERTSAVE_STATUS_INTERNAL_ERROR);
+ 				}
+-				_exit(CM_CERTSAVE_STATUS_INTERNAL_ERROR);
+-			}
+-			subject = cert.derSubject;
+-			/* Ask NSS if there would be a conflict. */
+-			have_trust = PR_FALSE;
+-			if (SEC_CertNicknameConflict(entry->cm_cert_nickname,
+-						     &subject,
+-						     certdb)) {
+-				/* Delete the certificate that's already there
+-				 * with the nickname we want, otherwise our
+-				 * cert with a different subject name will be
+-				 * discarded. */
+-				certlist = PK11_FindCertsFromNickname(entry->cm_cert_nickname,
+-								      NULL);
++				/* Handle the base64 decode. */
++				item = NSSBase64_DecodeBuffer(arena, NULL, p, q - p);
++				if (item == NULL) {
++					cm_log(1, "Unable to decode certificate "
++					       "into buffer.\n");
++					PORT_FreeArena(arena, PR_TRUE);
++					if (NSS_ShutdownContext(ctx) != SECSuccess) {
++						cm_log(1, "Error shutting down NSS.\n");
++					}
++					_exit(CM_CERTSAVE_STATUS_INTERNAL_ERROR);
++				}
++				/* Do a "shallow" decode to pull out the subject name
++				 * so that we can check for a conflict. */
++				memset(&csdata, 0, sizeof(csdata));
++				if (SEC_ASN1DecodeItem(arena, &csdata,
++						       CERT_SignedDataTemplate,
++						       item) != SECSuccess) {
++					cm_log(1, "Unable to decode certificate "
++					       "signed data into buffer.\n");
++					PORT_FreeArena(arena, PR_TRUE);
++					if (NSS_ShutdownContext(ctx) != SECSuccess) {
++						cm_log(1, "Error shutting down NSS.\n");
++					}
++					_exit(CM_CERTSAVE_STATUS_INTERNAL_ERROR);
++				}
++				memset(&cert, 0, sizeof(cert));
++				if (SEC_ASN1DecodeItem(arena, &cert,
++						       CERT_CertificateTemplate,
++						       &csdata.data) != SECSuccess) {
++					cm_log(1, "Unable to decode certificate "
++					       "data into buffer.\n");
++					PORT_FreeArena(arena, PR_TRUE);
++					if (NSS_ShutdownContext(ctx) != SECSuccess) {
++						cm_log(1, "Error shutting down NSS.\n");
++					}
++					_exit(CM_CERTSAVE_STATUS_INTERNAL_ERROR);
++				}
++				subject = cert.derSubject;
++				/* Ask NSS if there would be a conflict. */
++				have_trust = PR_FALSE;
++				if (SEC_CertNicknameConflict(entry->cm_cert_nickname,
++							     &subject,
++							     certdb)) {
++					/* Delete the certificate that's already there
++					 * with the nickname we want, otherwise our
++					 * cert with a different subject name will be
++					 * discarded. */
++					certlist = PK11_FindCertsFromNickname(entry->cm_cert_nickname,
++									      NULL);
++					if (certlist != NULL) {
++						/* Look for certs with different
++						 * subject names but the same nickname,
++						 * because they've got to go. */
++						for (node = CERT_LIST_HEAD(certlist);
++						     (node != NULL) &&
++						     !CERT_LIST_EMPTY(certlist) &&
++						     !CERT_LIST_END(node, certlist);
++						     node = CERT_LIST_NEXT(node)) {
++							if (!SECITEM_ItemsAreEqual(&subject,
++										   &node->cert->derSubject)) {
++								cm_log(3, "Found a "
++								       "certificate "
++								       "with the same "
++								       "nickname but "
++								       "different "
++								       "subject, "
++								       "removing "
++								       "certificate "
++								       "\"%s\" with "
++								       "subject "
++								       "\"%s\".\n",
++								       node->cert->nickname,
++								       node->cert->subjectName ?
++								       node->cert->subjectName :
++								       "");
++								/* Get a handle for
++								 * this certificate's
++								 * private key, in case
++								 * we need to remove
++								 * it. */
++								privkey = PK11_FindKeyByAnyCert(node->cert, NULL);
++								privkeys = add_privkey_to_list(privkeys, privkey);
++								SEC_DeletePermCertificate(node->cert);
++							}
++						}
++						CERT_DestroyCertList(certlist);
++					}
++				} else {
++					cm_log(3, "No duplicate nickname entries.\n");
++				}
++				/* This certificate's subject may already be present
++				 * with a different nickname.  Delete those, too. */
++				certlist = CERT_CreateSubjectCertList(NULL, certdb,
++								      &subject,
++								      PR_FALSE,
++								      PR_FALSE);
+ 				if (certlist != NULL) {
+-					/* Look for certs with different
+-					 * subject names but the same nickname,
+-					 * because they've got to go. */
++					/* Look for certs with different nicknames but
++					 * the same subject name, because those have
++					 * got to go. */
++					i = 0;
+ 					for (node = CERT_LIST_HEAD(certlist);
+ 					     (node != NULL) &&
+ 					     !CERT_LIST_EMPTY(certlist) &&
+ 					     !CERT_LIST_END(node, certlist);
+ 					     node = CERT_LIST_NEXT(node)) {
+-						if (!SECITEM_ItemsAreEqual(&subject,
+-									   &node->cert->derSubject)) {
++						if ((node->cert->nickname != NULL) &&
++						    (strcmp(entry->cm_cert_nickname,
++							    node->cert->nickname) != 0))
++						{
++							i++;
+ 							cm_log(3, "Found a "
+-							       "certificate "
+-							       "with the same "
+-							       "nickname but "
+-							       "different "
+-							       "subject, "
+-							       "removing "
+-							       "certificate "
+-							       "\"%s\" with "
+-							       "subject "
+-							       "\"%s\".\n",
+-							       node->cert->nickname,
+-							       node->cert->subjectName ?
+-							       node->cert->subjectName :
+-							       "");
+-							/* Get a handle for
+-							 * this certificate's
+-							 * private key, in case
+-							 * we need to remove
+-							 * it. */
+-							privkey = PK11_FindKeyByAnyCert(node->cert, NULL);
+-							privkeys = add_privkey_to_list(privkeys, privkey);
+-							SEC_DeletePermCertificate(node->cert);
+-						}
+-					}
+-					CERT_DestroyCertList(certlist);
+-				}
+-			} else {
+-				cm_log(3, "No duplicate nickname entries.\n");
+-			}
+-			/* This certificate's subject may already be present
+-			 * with a different nickname.  Delete those, too. */
+-			certlist = CERT_CreateSubjectCertList(NULL, certdb,
+-							      &subject,
+-							      PR_FALSE,
+-							      PR_FALSE);
+-			if (certlist != NULL) {
+-				/* Look for certs with different nicknames but
+-				 * the same subject name, because those have
+-				 * got to go. */
+-				i = 0;
+-				for (node = CERT_LIST_HEAD(certlist);
+-				     (node != NULL) &&
+-				     !CERT_LIST_EMPTY(certlist) &&
+-				     !CERT_LIST_END(node, certlist);
+-				     node = CERT_LIST_NEXT(node)) {
+-					if ((node->cert->nickname != NULL) &&
+-					    (strcmp(entry->cm_cert_nickname,
+-						    node->cert->nickname) != 0)) {
+-						i++;
+-						cm_log(3, "Found a "
+-						       "certificate with a "
++							       "certificate with a "
+ 						       "different nickname but "
+ 						       "the same subject, "
+ 						       "removing certificate "
+@@ -426,284 +452,291 @@ cm_certsave_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 						       node->cert->subjectName ?
+ 						       node->cert->subjectName :
+ 						       "");
+-						/* Get a handle for this
+-						 * certificate's private key,
+-						 * in case we need to remove
+-						 * it. */
+-						privkey = PK11_FindKeyByAnyCert(node->cert, NULL);
+-						privkeys = add_privkey_to_list(privkeys, privkey);
+-						SEC_DeletePermCertificate(node->cert);
+-					} else {
+-						/* Same nickname, and we
+-						 * already know it has the same
+-						 * subject name.  Save its
+-						 * trust. */
+-						if (!have_trust) {
+-							if (CERT_GetCertTrust(node->cert,
++							/* Get a handle for this
++							 * certificate's private key,
++							 * in case we need to remove
++							 * it. */
++							privkey = PK11_FindKeyByAnyCert(node->cert, NULL);
++							privkeys = add_privkey_to_list(privkeys, privkey);
++							SEC_DeletePermCertificate(node->cert);
++						} else {
++							/* Same nickname, and we
++							 * already know it has the same
++							 * subject name.  Save its
++							 * trust. */
++							if (!have_trust) {
++								if (CERT_GetCertTrust(node->cert,
+ 									      &trust) == SECSuccess) {
+-								have_trust = PR_TRUE;
++									have_trust = PR_TRUE;
++								}
+ 							}
+ 						}
+ 					}
+-				}
+-				if (i == 0) {
+-					cm_log(3, "No duplicate subject name entries.\n");
+-				}
+-				CERT_DestroyCertList(certlist);
+-			} else {
+-				cm_log(3, "No duplicate subject name entries.\n");
+-			}
+-			/* Make one more attempt at finding an existing trust
+-			 * value. */
+-			if (!have_trust) {
+-				oldcert = PK11_FindCertFromNickname(entry->cm_cert_nickname, NULL);
+-				if (oldcert != NULL) {
+-					if (CERT_GetCertTrust(oldcert,
+-							      &trust) == SECSuccess) {
+-						have_trust = PR_TRUE;
++					if (i == 0) {
++						cm_log(3, "No duplicate subject name entries.\n");
+ 					}
+-					CERT_DestroyCertificate(oldcert);
++					CERT_DestroyCertList(certlist);
++				} else {
++					cm_log(3, "No duplicate subject name entries.\n");
+ 				}
+-			}
+-			/* Import the certificate. */
+-			returned = NULL;
+-			error = CERT_ImportCerts(certdb,
+-						 certUsageUserCertImport,
+-						 1, &item, &returned,
+-						 PR_TRUE,
+-						 PR_FALSE,
+-						 entry->cm_cert_nickname);
+-			ec = PORT_GetError();
+-			if (error == SECSuccess) {
+-				/* If NSS uses SQL DB storage, CERT_ImportCerts creates
+-				 * an incomplete internal state (the cert isn't
+-				 * associated with the private key, and calling
+-				 * PK11_FindKeyByAnyCert returns no result).
+-				 * As a workaround, we import the cert again using 
+-				 * PK11_ImportCert, which magically fixes the issue.
+-				 * See rhbz#1532188 */
+-				error = PK11_ImportCert(PK11_GetInternalKeySlot(),
+-					returned[0],
+-					CK_INVALID_HANDLE,
+-					returned[0]->nickname,
+-					PR_FALSE);
+-			}
+-			if (error == SECSuccess) {
+-				cm_log(1, "Imported certificate \"%s\", got "
+-				       "nickname \"%s\".\n",
+-				       entry->cm_cert_nickname,
+-				       returned[0]->nickname);
+-				status = 0;
+-				/* Set the trust on the new certificate,
+-				 * perhaps matching the trust on an
+-				 * already-present certificate with the same
+-				 * nickname. */
++				/* Make one more attempt at finding an existing trust
++				 * value. */
+ 				if (!have_trust) {
+-					memset(&trust, 0, sizeof(trust));
+-					trust.sslFlags = CERTDB_USER;
+-					trust.emailFlags = CERTDB_USER;
+-					trust.objectSigningFlags = CERTDB_USER;
++					oldcert = PK11_FindCertFromNickname(entry->cm_cert_nickname, NULL);
++					if (oldcert != NULL) {
++						if (CERT_GetCertTrust(oldcert,
++								      &trust) == SECSuccess) {
++							have_trust = PR_TRUE;
++						}
++						CERT_DestroyCertificate(oldcert);
++					}
+ 				}
+-				error = CERT_ChangeCertTrust(certdb,
+-							     returned[0],
+-							     &trust);
++				/* Import the certificate. */
++				returned = NULL;
++				error = CERT_ImportCerts(certdb,
++							 certUsageUserCertImport,
++							 1, &item, &returned,
++							 PR_TRUE,
++							 PR_FALSE,
++							 entry->cm_cert_nickname);
+ 				ec = PORT_GetError();
+-				if (error != SECSuccess) {
++				if (error == SECSuccess) {
++					/* If NSS uses SQL DB storage, CERT_ImportCerts creates
++					 * an incomplete internal state (the cert isn't
++					 * associated with the private key, and calling
++					 * PK11_FindKeyByAnyCert returns no result).
++					 * As a workaround, we import the cert again using
++					 * PK11_ImportCert, which magically fixes the issue.
++					 * See rhbz#1532188 */
++					error = PK11_ImportCert(sle->slot,
++						returned[0],
++						CK_INVALID_HANDLE,
++						returned[0]->nickname,
++						PR_FALSE);
++				}
++				if (error == SECSuccess) {
++					cm_log(1, "Imported certificate \"%s\", got "
++					       "nickname \"%s\".\n",
++					       entry->cm_cert_nickname,
++					       returned[0]->nickname);
++					status = 0;
++					/* Set the trust on the new certificate,
++					 * perhaps matching the trust on an
++					 * already-present certificate with the same
++					 * nickname. */
++					if (!have_trust) {
++						memset(&trust, 0, sizeof(trust));
++						trust.sslFlags = CERTDB_USER;
++						trust.emailFlags = CERTDB_USER;
++						trust.objectSigningFlags = CERTDB_USER;
++					}
++					error = CERT_ChangeCertTrust(certdb,
++								     returned[0],
++								     &trust);
++					ec = PORT_GetError();
++					if (error != SECSuccess) {
++						if (ec != 0) {
++							es = PR_ErrorToName(ec);
++						} else {
++							es = NULL;
++						}
++						if (es != NULL) {
++							cm_log(0, "Error setting trust "
++							       "on certificate \"%s\": "
++							       "%s.\n",
++							       entry->cm_cert_nickname, es);
++						} else {
++							cm_log(0, "Error setting trust "
++							       "on certificate \"%s\".\n",
++							       entry->cm_cert_nickname);
++						}
++					}
++					/* Delete any other certificates that are there
++					 * with the same nickname.  While NSS's
++					 * database allows duplicates so long as they
++					 * have the same subject name and nickname,
++					 * several APIs and many applications can't
++					 * dependably find the right one among more
++					 * than one.  So bye-bye, old certificates. */
++					certlist = PK11_FindCertsFromNickname(entry->cm_cert_nickname,
++									      NULL);
++					if (certlist != NULL) {
++						/* Look for certs with contents. */
++						for (node = CERT_LIST_HEAD(certlist);
++						     (node != NULL) &&
++						     !CERT_LIST_EMPTY(certlist) &&
++						     !CERT_LIST_END(node, certlist);
++						     node = CERT_LIST_NEXT(node)) {
++							if (!SECITEM_ItemsAreEqual(item,
++										   &node->cert->derCert)) {
++								cm_log(3, "Found a "
++								       "certificate "
++								       "with the same "
++								       "nickname and "
++								       "subject, but "
++								       "different "
++								       "contents, "
++								       "removing it.\n");
++								/* Get a handle for
++								 * this certificate's
++								 * private key, in case
++								 * we need to remove
++								 * it. */
++								privkey = PK11_FindKeyByAnyCert(node->cert, NULL);
++								privkeys = add_privkey_to_list(privkeys, privkey);
++								SEC_DeletePermCertificate(node->cert);
++							}
++						}
++						CERT_DestroyCertList(certlist);
++					}
++				} else {
+ 					if (ec != 0) {
+ 						es = PR_ErrorToName(ec);
+ 					} else {
+ 						es = NULL;
+ 					}
+ 					if (es != NULL) {
+-						cm_log(0, "Error setting trust "
+-						       "on certificate \"%s\": "
+-						       "%s.\n",
+-						       entry->cm_cert_nickname, es);
++						cm_log(0, "Error importing certificate "
++						       "into NSSDB \"%s\": %s.\n",
++						       entry->cm_cert_storage_location,
++						       es);
+ 					} else {
+-						cm_log(0, "Error setting trust "
+-						       "on certificate \"%s\".\n",
+-						       entry->cm_cert_nickname);
++						cm_log(0, "Error importing certificate "
++						       "into NSSDB \"%s\".\n",
++						       entry->cm_cert_storage_location);
+ 					}
+-				}
+-				/* Delete any other certificates that are there
+-				 * with the same nickname.  While NSS's
+-				 * database allows duplicates so long as they
+-				 * have the same subject name and nickname,
+-				 * several APIs and many applications can't
+-				 * dependably find the right one among more
+-				 * than one.  So bye-bye, old certificates. */
+-				certlist = PK11_FindCertsFromNickname(entry->cm_cert_nickname,
+-								      NULL);
+-				if (certlist != NULL) {
+-					/* Look for certs with contents. */
+-					for (node = CERT_LIST_HEAD(certlist);
+-					     (node != NULL) &&
+-					     !CERT_LIST_EMPTY(certlist) &&
+-					     !CERT_LIST_END(node, certlist);
+-					     node = CERT_LIST_NEXT(node)) {
+-						if (!SECITEM_ItemsAreEqual(item,
+-									   &node->cert->derCert)) {
+-							cm_log(3, "Found a "
+-							       "certificate "
+-							       "with the same "
+-							       "nickname and "
+-							       "subject, but "
+-							       "different "
+-							       "contents, "
+-							       "removing it.\n");
+-							/* Get a handle for
+-							 * this certificate's
+-							 * private key, in case
+-							 * we need to remove
+-							 * it. */
+-							privkey = PK11_FindKeyByAnyCert(node->cert, NULL);
+-							privkeys = add_privkey_to_list(privkeys, privkey);
+-							SEC_DeletePermCertificate(node->cert);
+-						}
++					switch (ec) {
++					case PR_NO_ACCESS_RIGHTS_ERROR: /* ACCES/PERM */
++						status = CM_CERTSAVE_STATUS_PERMS;
++						break;
++					default:
++						status = CM_CERTSAVE_STATUS_INTERNAL_ERROR;
++						break;
+ 					}
+-					CERT_DestroyCertList(certlist);
+-				}
+-			} else {
+-				if (ec != 0) {
+-					es = PR_ErrorToName(ec);
+-				} else {
+-					es = NULL;
+ 				}
+-				if (es != NULL) {
+-					cm_log(0, "Error importing certificate "
+-					       "into NSSDB \"%s\": %s.\n",
+-					       entry->cm_cert_storage_location,
+-					       es);
+-				} else {
+-					cm_log(0, "Error importing certificate "
+-					       "into NSSDB \"%s\".\n",
+-					       entry->cm_cert_storage_location);
+-				}
+-				switch (ec) {
+-				case PR_NO_ACCESS_RIGHTS_ERROR: /* ACCES/PERM */
+-					status = CM_CERTSAVE_STATUS_PERMS;
+-					break;
+-				default:
+-					status = CM_CERTSAVE_STATUS_INTERNAL_ERROR;
+-					break;
++				/* If we managed to import the certificate, mark its
++				 * key for having its nickname removed. */
++				if ((returned != NULL) && (returned[0] != NULL)) {
++					privkey = PK11_FindKeyByAnyCert(returned[0], NULL);
++					privkeys = add_privkey_to_list(privkeys, privkey);
++					CERT_DestroyCertArray(returned, 1);
+ 				}
+-			}
+-			/* If we managed to import the certificate, mark its
+-			 * key for having its nickname removed. */
+-			if ((returned != NULL) && (returned[0] != NULL)) {
+-				privkey = PK11_FindKeyByAnyCert(returned[0], NULL);
+-				privkeys = add_privkey_to_list(privkeys, privkey);
+-				CERT_DestroyCertArray(returned, 1);
+-			}
+-			/* In case we're rekeying, but failed, mark the
+-			 * candidate key for name-clearing or removal, too. */
+-			if ((entry->cm_key_next_marker != NULL) &&
+-			    (strlen(entry->cm_key_next_marker) > 0)) {
+-				p = util_build_next_nickname(entry->cm_key_nickname,
+-							     entry->cm_key_next_marker);
+-				privkeylist = PK11_ListPrivKeysInSlot(PK11_GetInternalKeySlot(), p, NULL);
+-				if (privkeylist != NULL) {
+-					for (knode = PRIVKEY_LIST_HEAD(privkeylist);
+-					     !PRIVKEY_LIST_EMPTY(privkeylist) &&
+-					     !PRIVKEY_LIST_END(knode, privkeylist);
+-					     knode = PRIVKEY_LIST_NEXT(knode)) {
+-						q = PK11_GetPrivateKeyNickname(knode->key);
+-						if ((q != NULL) &&
+-						    (strcmp(p, q) == 0)) {
+-							privkey = SECKEY_CopyPrivateKey(knode->key);
+-							privkeys = add_privkey_to_list(privkeys, privkey);
+-							break;
++				/* In case we're rekeying, but failed, mark the
++				 * candidate key for name-clearing or removal, too. */
++				if ((entry->cm_key_next_marker != NULL) &&
++				    (strlen(entry->cm_key_next_marker) > 0)) {
++					p = util_build_next_nickname(entry->cm_key_nickname,
++								     entry->cm_key_next_marker);
++					privkeylist = PK11_ListPrivKeysInSlot(sle->slot, p, NULL);
++					if (privkeylist != NULL) {
++						for (knode = PRIVKEY_LIST_HEAD(privkeylist);
++						     !PRIVKEY_LIST_EMPTY(privkeylist) &&
++						     !PRIVKEY_LIST_END(knode, privkeylist);
++						     knode = PRIVKEY_LIST_NEXT(knode)) {
++							q = PK11_GetPrivateKeyNickname(knode->key);
++							if ((q != NULL) &&
++							    (strcmp(p, q) == 0)) {
++								privkey = SECKEY_CopyPrivateKey(knode->key);
++								privkeys = add_privkey_to_list(privkeys, privkey);
++								break;
++							}
+ 						}
++						SECKEY_DestroyPrivateKeyList(privkeylist);
+ 					}
+-					SECKEY_DestroyPrivateKeyList(privkeylist);
+ 				}
+-			}
+-			if (privkeys != NULL) {
+-				/* Check if any certificates are still using
+-				 * the keys that correspond to certificates
+-				 * that we removed. */
+-				for (i = 0; privkeys[i] != NULL; i++) {
+-					privkey = privkeys[i];
+-					oldcert = PK11_GetCertFromPrivateKey(privkey);
+-					if (!entry->cm_key_preserve && (oldcert == NULL)) {
+-						/* We're not preserving
+-						 * orphaned keys, so remove
+-						 * this one.  No need to mess
+-						 * with its nickname first. */
+-						PK11_DeleteTokenPrivateKey(privkey, PR_FALSE);
+-						if (error == SECSuccess) {
+-							cm_log(3, "Removed old key.\n");
+-						} else {
+-							ec = PORT_GetError();
+-							if (ec != 0) {
+-								es = PR_ErrorToName(ec);
++				if (privkeys != NULL) {
++					/* Check if any certificates are still using
++					 * the keys that correspond to certificates
++					 * that we removed. */
++					for (i = 0; privkeys[i] != NULL; i++) {
++						privkey = privkeys[i];
++						oldcert = PK11_GetCertFromPrivateKey(privkey);
++						if (!entry->cm_key_preserve && (oldcert == NULL)) {
++							/* We're not preserving
++							 * orphaned keys, so remove
++							 * this one.  No need to mess
++							 * with its nickname first. */
++							PK11_DeleteTokenPrivateKey(privkey, PR_FALSE);
++							if (error == SECSuccess) {
++								cm_log(3, "Removed old key.\n");
+ 							} else {
+-								es = NULL;
++								ec = PORT_GetError();
++								if (ec != 0) {
++									es = PR_ErrorToName(ec);
++								} else {
++									es = NULL;
++								}
++								if (es != NULL) {
++									cm_log(0, "Failed "
++									       "to remove "
++									       "old key: "
++									       "%s.\n", es);
++								} else {
++									cm_log(0, "Failed "
++									       "to remove "
++									       "old key.\n");
++								}
+ 							}
+-							if (es != NULL) {
+-								cm_log(0, "Failed "
+-								       "to remove "
+-								       "old key: "
+-								       "%s.\n", es);
+-							} else {
+-								cm_log(0, "Failed "
+-								       "to remove "
+-								       "old key.\n");
+-							}
+-						}
+-					} else {
+-						/* Remove the explicit
+-						 * nickname, so that the key
+-						 * will have to be found using
+-						 * the certificate's nickname,
+-						 * and certutil will display
+-						 * the matching certificate's
+-						 * nickname when it's asked to
+-						 * list the keys in the
+-						 * database. */
+-						error = PK11_SetPrivateKeyNickname(privkey, "");
+-						if (error == SECSuccess) {
+-							cm_log(3, "Removed "
+-							       "name from old "
+-							       "key.\n");
+ 						} else {
+-							ec = PORT_GetError();
+-							if (ec != 0) {
+-								es = PR_ErrorToName(ec);
++							/* Remove the explicit
++							 * nickname, so that the key
++							 * will have to be found using
++							 * the certificate's nickname,
++							 * and certutil will display
++							 * the matching certificate's
++							 * nickname when it's asked to
++							 * list the keys in the
++							 * database. */
++							error = PK11_SetPrivateKeyNickname(privkey, "");
++							if (error == SECSuccess) {
++								cm_log(3, "Removed "
++								       "name from old "
++								       "key.\n");
+ 							} else {
+-								es = NULL;
+-							}
+-							if (es != NULL) {
+-								cm_log(0, "Failed "
+-								       "to unname "
+-								       "old key: "
+-								       "%s.\n", es);
+-							} else {
+-								cm_log(0, "Failed "
+-								       "to unname "
+-								       "old key.\n");
++								ec = PORT_GetError();
++								if (ec != 0) {
++									es = PR_ErrorToName(ec);
++								} else {
++									es = NULL;
++								}
++								if (es != NULL) {
++									cm_log(0, "Failed "
++									       "to unname "
++									       "old key: "
++									       "%s.\n", es);
++								} else {
++									cm_log(0, "Failed "
++									       "to unname "
++									       "old key.\n");
++								}
+ 							}
++							SECKEY_DestroyPrivateKey(privkey);
++						}
++						if (oldcert != NULL) {
++							CERT_DestroyCertificate(oldcert);
+ 						}
+-						SECKEY_DestroyPrivateKey(privkey);
+-					}
+-					if (oldcert != NULL) {
+-						CERT_DestroyCertificate(oldcert);
+ 					}
++					free(privkeys);
+ 				}
+-				free(privkeys);
++			} else {
++				cm_log(1, "Error getting handle to default NSS DB.\n");
+ 			}
+-		} else {
+-			cm_log(1, "Error getting handle to default NSS DB.\n");
+-		}
+-		PORT_FreeArena(arena, PR_TRUE);
+-		if (NSS_ShutdownContext(ctx) != SECSuccess) {
+-			cm_log(1, "Error shutting down NSS.\n");
+-		}
+-		/* Fixup the ownership and permissions on the key and
+-		 * certificate databases. */
+-		util_set_db_entry_key_owner(entry->cm_key_storage_location, entry);
+-		util_set_db_entry_cert_owner(entry->cm_cert_storage_location, entry);
+-	}
++			PORT_FreeArena(arena, PR_TRUE);
++			if (NSS_ShutdownContext(ctx) != SECSuccess) {
++				cm_log(1, "Error shutting down NSS.\n");
++			}
++			/* Fixup the ownership and permissions on the key and
++			 * certificate databases. */
++			util_set_db_entry_key_owner(entry->cm_key_storage_location, entry);
++			util_set_db_entry_cert_owner(entry->cm_cert_storage_location, entry);
++			break;
++next_slot:
++			if (sle == slotlist->tail) {
++				break;
++			}
++		} /* for slot loop */
++	} /* ctx == NULL */
++
+ 	if (status != 0) {
+ 		_exit(status);
+ 	}
+-- 
+2.14.4
+
diff --git a/SOURCES/0004-Include-the-token-name-when-a-PIN-is-provided-but-is.patch b/SOURCES/0004-Include-the-token-name-when-a-PIN-is-provided-but-is.patch
new file mode 100644
index 0000000..bba736c
--- /dev/null
+++ b/SOURCES/0004-Include-the-token-name-when-a-PIN-is-provided-but-is.patch
@@ -0,0 +1,49 @@
+From c029b32c04a9a5993b9c8715fb82421fee613137 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Fri, 31 Aug 2018 10:37:12 -0400
+Subject: [PATCH 2/7] Include the token name when a PIN is provided but is
+ unused
+
+This improves the output so the user will know which token
+the PIN is missing for. Theoretically it should be the token
+they asked for but this will show certmogner's view of it.
+---
+ src/certread-n.c | 6 +++---
+ src/keygen-n.c   | 4 ++--
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/src/certread-n.c b/src/certread-n.c
+index f2e78c07..57a38dcf 100644
+--- a/src/certread-n.c
++++ b/src/certread-n.c
+@@ -259,9 +259,9 @@ cm_certread_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 			if ((pin != NULL) &&
+ 			    (strlen(pin) > 0) &&
+ 			    (cb_data.n_attempts == 0)) {
+-				cm_log(1, "PIN was not needed to auth to cert "
+-				       "db, though one was provided. "
+-				       "Treating this as an error.\n");
++				cm_log(1, "PIN was not needed to auth to token "
++				       "%s, though one was provided. "
++				       "Treating this as an error.\n", token);
+ 				goto next_slot;
+ 			}
+ 		}
+diff --git a/src/keygen-n.c b/src/keygen-n.c
+index 8078a520..84b0bbd3 100644
+--- a/src/keygen-n.c
++++ b/src/keygen-n.c
+@@ -400,8 +400,8 @@ next_slot:
+ 	    (strlen(pin) > 0) &&
+ 	    (cb_data.n_attempts == 0)) {
+ 		cm_log(1, "PIN was not needed to auth to key "
+-		       "store, though one was provided. "
+-		       "Treating this as an error.\n");
++		       "store token %s, though one was provided. "
++		       "Treating this as an error.\n", token);
+ 		PK11_FreeSlotList(slotlist);
+ 		error = NSS_ShutdownContext(ctx);
+ 		if (error != SECSuccess) {
+-- 
+2.14.4
+
diff --git a/SOURCES/0005-Add-utility-function-to-get-the-internal-token-name.patch b/SOURCES/0005-Add-utility-function-to-get-the-internal-token-name.patch
new file mode 100644
index 0000000..ed3abde
--- /dev/null
+++ b/SOURCES/0005-Add-utility-function-to-get-the-internal-token-name.patch
@@ -0,0 +1,134 @@
+From f396b19b2c222fa0a50e9bb9704059af4578e678 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Fri, 31 Aug 2018 12:08:35 -0400
+Subject: [PATCH 3/7] Add utility function to get the internal token name
+
+The NSS internal token is the default if no token is specified for
+the cert or the key.
+---
+ src/certread-n.c | 6 +++++-
+ src/certsave-n.c | 3 +++
+ src/keygen-n.c   | 3 +++
+ src/keyiread-n.c | 3 +++
+ src/submit-n.c   | 5 ++++-
+ src/util-n.c     | 6 ++++++
+ src/util-n.h     | 1 +
+ 7 files changed, 25 insertions(+), 2 deletions(-)
+
+diff --git a/src/certread-n.c b/src/certread-n.c
+index 57a38dcf..1d9217c6 100644
+--- a/src/certread-n.c
++++ b/src/certread-n.c
+@@ -190,6 +190,9 @@ cm_certread_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 		cm_log(1, "Error reading PIN for cert db.\n");
+ 		_exit(CM_SUB_STATUS_ERROR_AUTH);
+ 	}
++	if (entry->cm_cert_token == NULL) {
++		entry->cm_cert_token = util_internal_token_name();
++	}
+ 	PK11_SetPasswordFunc(&cm_pin_read_for_cert_nss_cb);
+ 	for (sle = slotlist->head;
+ 	     ((sle != NULL) && (sle->slot != NULL));
+@@ -253,7 +256,8 @@ cm_certread_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 			}
+ 			error = PK11_Authenticate(sle->slot, PR_TRUE, &cb_data);
+ 			if (error != SECSuccess) {
+-				cm_log(1, "Error authenticating to cert db.\n");
++				cm_log(1, "certread-n: Error authenticating to cert db "
++					   "slot %s.\n", PK11_GetTokenName(sle->slot));
+ 				goto next_slot;
+ 			}
+ 			if ((pin != NULL) &&
+diff --git a/src/certsave-n.c b/src/certsave-n.c
+index af176ce5..193309c5 100644
+--- a/src/certsave-n.c
++++ b/src/certsave-n.c
+@@ -214,6 +214,9 @@ cm_certsave_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 			_exit(CM_SUB_STATUS_ERROR_AUTH);
+ 		}
+ 		PK11_SetPasswordFunc(&cm_pin_read_for_cert_nss_cb);
++		if (entry->cm_cert_token == NULL) {
++			entry->cm_cert_token = util_internal_token_name();
++		}
+ 		for (sle = slotlist->head;
+ 		     ((sle != NULL) && (sle->slot != NULL));
+ 		     sle = sle->next)
+diff --git a/src/keygen-n.c b/src/keygen-n.c
+index 84b0bbd3..f7fdf6c0 100644
+--- a/src/keygen-n.c
++++ b/src/keygen-n.c
+@@ -272,6 +272,9 @@ cm_keygen_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 		cm_log(1, "Error locating token for key generation.\n");
+ 		_exit(CM_SUB_STATUS_ERROR_NO_TOKEN);
+ 	}
++	if (entry->cm_cert_token == NULL) {
++		entry->cm_cert_token = util_internal_token_name();
++	}
+ 	/* Walk the list looking for the requested slot, or the first one if
+ 	 * none was requested. */
+ 	slot = NULL;
+diff --git a/src/keyiread-n.c b/src/keyiread-n.c
+index 89913aa2..b8408bf1 100644
+--- a/src/keyiread-n.c
++++ b/src/keyiread-n.c
+@@ -152,6 +152,9 @@ cm_keyiread_n_get_keys(struct cm_store_entry *entry, int readwrite)
+ 		_exit(CM_SUB_STATUS_ERROR_AUTH);
+ 	}
+ 	PK11_SetPasswordFunc(&cm_pin_read_for_cert_nss_cb);
++	if (entry->cm_key_token == NULL) {
++		entry->cm_key_token = util_internal_token_name();
++	}
+ 	n_tokens = 0;
+ 	pubkey = NULL;
+ 	/* In practice, the internal slot is either a non-storage slot (in
+diff --git a/src/submit-n.c b/src/submit-n.c
+index 872153ea..da07d253 100644
+--- a/src/submit-n.c
++++ b/src/submit-n.c
+@@ -346,6 +346,9 @@ cm_submit_n_decrypt_envelope(const unsigned char *envelope,
+ 		cm_log(1, "Error reading PIN for key storage.\n");
+ 		goto done;
+ 	}
++	if (args->entry->cm_key_token == NULL) {
++		args->entry->cm_key_token = util_internal_token_name();
++	}
+ 	PK11_SetPasswordFunc(&cm_pin_read_for_cert_nss_cb);
+ 	n_tokens = 0;
+ 	/* In practice, the internal slot is either a non-storage slot (in
+@@ -402,7 +405,7 @@ cm_submit_n_decrypt_envelope(const unsigned char *envelope,
+ 		}
+ 		error = PK11_Authenticate(slot, PR_TRUE, &cb_data);
+ 		if (error != SECSuccess) {
+-			cm_log(1, "Error authenticating to token "
++			cm_log(1, "submit-n: Error authenticating to token "
+ 			       "\"%s\".\n", token);
+ 			goto done;
+ 		}
+diff --git a/src/util-n.c b/src/util-n.c
+index 7805e58e..293e2583 100644
+--- a/src/util-n.c
++++ b/src/util-n.c
+@@ -287,3 +287,9 @@ util_set_db_entry_cert_owner(const char *dbdir, struct cm_store_entry *entry)
+ 	util_set_db_owner_perms(dbdir, secmoddb, entry->cm_cert_owner,
+ 				entry->cm_cert_perms);
+ }
++
++char *
++util_internal_token_name()
++{
++	return strdup(PK11_GetTokenName(PK11_GetInternalKeySlot()));
++}
+diff --git a/src/util-n.h b/src/util-n.h
+index 8a918d5c..637fd4b1 100644
+--- a/src/util-n.h
++++ b/src/util-n.h
+@@ -29,5 +29,6 @@ void util_set_db_entry_key_owner(const char *dbdir,
+ 				 struct cm_store_entry *entry);
+ void util_set_db_entry_cert_owner(const char *dbdir,
+ 				  struct cm_store_entry *entry);
++char * util_internal_token_name();
+ 
+ #endif
+-- 
+2.14.4
+
diff --git a/SOURCES/0006-Only-de-duplicate-certificates-within-the-same-token.patch b/SOURCES/0006-Only-de-duplicate-certificates-within-the-same-token.patch
new file mode 100644
index 0000000..fb892c6
--- /dev/null
+++ b/SOURCES/0006-Only-de-duplicate-certificates-within-the-same-token.patch
@@ -0,0 +1,41 @@
+From 6ebe5695a626c6cd254b249bbebf9846bcb936c0 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Tue, 4 Sep 2018 11:06:13 -0400
+Subject: [PATCH 4/7] Only de-duplicate certificates within the same token
+
+certmonger may not have read/write access to tokens other than
+the one it is examining so don't try to de-duplicate certificates
+on other tokens.
+---
+ src/certsave-n.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/src/certsave-n.c b/src/certsave-n.c
+index 193309c5..d0152cad 100644
+--- a/src/certsave-n.c
++++ b/src/certsave-n.c
+@@ -391,8 +391,9 @@ cm_certsave_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 						     !CERT_LIST_EMPTY(certlist) &&
+ 						     !CERT_LIST_END(node, certlist);
+ 						     node = CERT_LIST_NEXT(node)) {
+-							if (!SECITEM_ItemsAreEqual(&subject,
+-										   &node->cert->derSubject)) {
++							if ((!SECITEM_ItemsAreEqual(&subject,
++									   &node->cert->derSubject)) &&
++										(sle->slot == node->cert->slot)) {
+ 								cm_log(3, "Found a "
+ 								       "certificate "
+ 								       "with the same "
+@@ -441,7 +442,8 @@ cm_certsave_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 					     node = CERT_LIST_NEXT(node)) {
+ 						if ((node->cert->nickname != NULL) &&
+ 						    (strcmp(entry->cm_cert_nickname,
+-							    node->cert->nickname) != 0))
++							    node->cert->nickname) != 0) &&
++								(sle->slot == node->cert->slot))
+ 						{
+ 							i++;
+ 							cm_log(3, "Found a "
+-- 
+2.14.4
+
diff --git a/SOURCES/0007-Ensure-that-an-OpenSSL-random-seed-file-exists-when-.patch b/SOURCES/0007-Ensure-that-an-OpenSSL-random-seed-file-exists-when-.patch
new file mode 100644
index 0000000..184a651
--- /dev/null
+++ b/SOURCES/0007-Ensure-that-an-OpenSSL-random-seed-file-exists-when-.patch
@@ -0,0 +1,30 @@
+From 697dd085e7b2ce15eefc454509987270131d7f1e Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Tue, 4 Sep 2018 16:59:28 -0400
+Subject: [PATCH 5/7] Ensure that an OpenSSL random seed file exists when
+ testing
+
+Otherwise some openssl command-line invocations will fail and
+because of the way the tests are done the error message is not
+shown.
+---
+ tests/Makefile.am | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/tests/Makefile.am b/tests/Makefile.am
+index 4e407434..fe368dc0 100644
+--- a/tests/Makefile.am
++++ b/tests/Makefile.am
+@@ -433,6 +433,9 @@ subdirs += \
+ endif
+ 
+ check: all
++	if [ ! -e $$HOME/.rnd ] ; then \
++		openssl rand -writerand $$HOME/.rnd; \
++	fi
+ 	for required in certutil cmsutil pk12util openssl diff cmp mktemp \
+ 			dos2unix unix2dos dbus-launch ; do \
+ 		which $$required || exit 1; \
+-- 
+2.14.4
+
diff --git a/SOURCES/0008-Log-test-failures-of-bad-pin.patch b/SOURCES/0008-Log-test-failures-of-bad-pin.patch
new file mode 100644
index 0000000..45fa77b
--- /dev/null
+++ b/SOURCES/0008-Log-test-failures-of-bad-pin.patch
@@ -0,0 +1,29 @@
+From e93ecadec7c868f4227e084ffb65c70a6efd7314 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Tue, 4 Sep 2018 18:12:18 -0400
+Subject: [PATCH 6/7] Log test failures of bad pin
+
+Previously this would show a "don't know why" failure.
+---
+ tests/tools/certsave.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/tests/tools/certsave.c b/tests/tools/certsave.c
+index ac0f73ec..fd86a4c1 100644
+--- a/tests/tools/certsave.c
++++ b/tests/tools/certsave.c
+@@ -106,6 +106,11 @@ main(int argc, char **argv)
+ 				printf("Failed to save (%s:%s), "
+ 				       "filesystem permissions error.\n",
+ 				       ctype, entry->cm_cert_storage_location);
++			} else
++			if (cm_certsave_pin_error(state) == 0) {
++				printf("Failed to save (%s:%s), "
++				       "pin error.\n",
++				       ctype, entry->cm_cert_storage_location);
+ 			} else {
+ 				printf("Failed to save (%s:%s), "
+ 				       "don't know why.\n",
+-- 
+2.14.4
+
diff --git a/SOURCES/0009-Use-only-PK11_ImportCert-to-import-certs-not-CERT_Im.patch b/SOURCES/0009-Use-only-PK11_ImportCert-to-import-certs-not-CERT_Im.patch
new file mode 100644
index 0000000..dd0c3fc
--- /dev/null
+++ b/SOURCES/0009-Use-only-PK11_ImportCert-to-import-certs-not-CERT_Im.patch
@@ -0,0 +1,95 @@
+From 15d406ee3afbb52832d5c61a1afb735724d109a2 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Tue, 18 Sep 2018 10:21:28 -0400
+Subject: [PATCH 7/7] Use only PK11_ImportCert to import certs, not
+ CERT_ImportCerts
+
+CERT_ImportCerts always imports a given certificate into the
+certificate database, whether a token is requested or not.
+
+Using PK11_ImportCert will import the cert, associate the key
+properly and will only add the certificate to the appropriate
+token.
+---
+ src/certsave-n.c | 37 +++++++++++--------------------------
+ 1 file changed, 11 insertions(+), 26 deletions(-)
+
+diff --git a/src/certsave-n.c b/src/certsave-n.c
+index d0152cad..fcb43148 100644
+--- a/src/certsave-n.c
++++ b/src/certsave-n.c
+@@ -100,7 +100,7 @@ cm_certsave_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 	NSSInitContext *ctx;
+ 	CERTCertDBHandle *certdb;
+ 	CERTCertList *certlist;
+-	CERTCertificate **returned, *oldcert, cert;
++	CERTCertificate *oldcert, *newcert, cert;
+ 	CERTCertTrust trust;
+ 	CERTSignedData csdata;
+ 	CERTCertListNode *node;
+@@ -497,33 +497,18 @@ cm_certsave_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 					}
+ 				}
+ 				/* Import the certificate. */
+-				returned = NULL;
+-				error = CERT_ImportCerts(certdb,
+-							 certUsageUserCertImport,
+-							 1, &item, &returned,
+-							 PR_TRUE,
+-							 PR_FALSE,
+-							 entry->cm_cert_nickname);
+-				ec = PORT_GetError();
+-				if (error == SECSuccess) {
+-					/* If NSS uses SQL DB storage, CERT_ImportCerts creates
+-					 * an incomplete internal state (the cert isn't
+-					 * associated with the private key, and calling
+-					 * PK11_FindKeyByAnyCert returns no result).
+-					 * As a workaround, we import the cert again using
+-					 * PK11_ImportCert, which magically fixes the issue.
+-					 * See rhbz#1532188 */
++				newcert = CERT_DecodeCertFromPackage((char *)item->data, item->len);
++				if (newcert != NULL) {
+ 					error = PK11_ImportCert(sle->slot,
+-						returned[0],
++						newcert,
+ 						CK_INVALID_HANDLE,
+-						returned[0]->nickname,
++						entry->cm_cert_nickname,
+ 						PR_FALSE);
+ 				}
+ 				if (error == SECSuccess) {
+-					cm_log(1, "Imported certificate \"%s\", got "
++					cm_log(1, "Imported certificate with "
+ 					       "nickname \"%s\".\n",
+-					       entry->cm_cert_nickname,
+-					       returned[0]->nickname);
++					       entry->cm_cert_nickname);
+ 					status = 0;
+ 					/* Set the trust on the new certificate,
+ 					 * perhaps matching the trust on an
+@@ -536,7 +521,7 @@ cm_certsave_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 						trust.objectSigningFlags = CERTDB_USER;
+ 					}
+ 					error = CERT_ChangeCertTrust(certdb,
+-								     returned[0],
++								     newcert,
+ 								     &trust);
+ 					ec = PORT_GetError();
+ 					if (error != SECSuccess) {
+@@ -621,10 +606,10 @@ cm_certsave_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 				}
+ 				/* If we managed to import the certificate, mark its
+ 				 * key for having its nickname removed. */
+-				if ((returned != NULL) && (returned[0] != NULL)) {
+-					privkey = PK11_FindKeyByAnyCert(returned[0], NULL);
++				if (newcert != NULL) {
++					privkey = PK11_FindKeyByAnyCert(newcert, NULL);
+ 					privkeys = add_privkey_to_list(privkeys, privkey);
+-					CERT_DestroyCertArray(returned, 1);
++					CERT_DestroyCertificate(newcert);
+ 				}
+ 				/* In case we're rekeying, but failed, mark the
+ 				 * candidate key for name-clearing or removal, too. */
+-- 
+2.14.4
+
diff --git a/SOURCES/0010-Fix-memory-leak-in-util_internal_token_name.patch b/SOURCES/0010-Fix-memory-leak-in-util_internal_token_name.patch
new file mode 100644
index 0000000..57bb556
--- /dev/null
+++ b/SOURCES/0010-Fix-memory-leak-in-util_internal_token_name.patch
@@ -0,0 +1,95 @@
+From 5d2554ed31fa6bc121d94efe533f9e4fea3900aa Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Thu, 4 Oct 2018 08:21:35 -0400
+Subject: [PATCH 10/17] Fix memory leak in util_internal_token_name()
+
+Allocate memory using the talloc context instead of relying on
+the caller to call free().
+---
+ src/certread-n.c | 2 +-
+ src/certsave-n.c | 2 +-
+ src/keygen-n.c   | 2 +-
+ src/keyiread-n.c | 2 +-
+ src/submit-n.c   | 2 +-
+ src/util-n.c     | 2 +-
+ 6 files changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/src/certread-n.c b/src/certread-n.c
+index 1d9217c6..d535030b 100644
+--- a/src/certread-n.c
++++ b/src/certread-n.c
+@@ -191,7 +191,7 @@ cm_certread_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 		_exit(CM_SUB_STATUS_ERROR_AUTH);
+ 	}
+ 	if (entry->cm_cert_token == NULL) {
+-		entry->cm_cert_token = util_internal_token_name();
++		entry->cm_cert_token = talloc_strdup(entry, util_internal_token_name());
+ 	}
+ 	PK11_SetPasswordFunc(&cm_pin_read_for_cert_nss_cb);
+ 	for (sle = slotlist->head;
+diff --git a/src/certsave-n.c b/src/certsave-n.c
+index fcb43148..49b28324 100644
+--- a/src/certsave-n.c
++++ b/src/certsave-n.c
+@@ -215,7 +215,7 @@ cm_certsave_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 		}
+ 		PK11_SetPasswordFunc(&cm_pin_read_for_cert_nss_cb);
+ 		if (entry->cm_cert_token == NULL) {
+-			entry->cm_cert_token = util_internal_token_name();
++			entry->cm_cert_token = talloc_strdup(entry, util_internal_token_name());
+ 		}
+ 		for (sle = slotlist->head;
+ 		     ((sle != NULL) && (sle->slot != NULL));
+diff --git a/src/keygen-n.c b/src/keygen-n.c
+index f7fdf6c0..76a5c1d3 100644
+--- a/src/keygen-n.c
++++ b/src/keygen-n.c
+@@ -273,7 +273,7 @@ cm_keygen_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 		_exit(CM_SUB_STATUS_ERROR_NO_TOKEN);
+ 	}
+ 	if (entry->cm_cert_token == NULL) {
+-		entry->cm_cert_token = util_internal_token_name();
++		entry->cm_cert_token = talloc_strdup(entry, util_internal_token_name());
+ 	}
+ 	/* Walk the list looking for the requested slot, or the first one if
+ 	 * none was requested. */
+diff --git a/src/keyiread-n.c b/src/keyiread-n.c
+index b8408bf1..8f46ec0f 100644
+--- a/src/keyiread-n.c
++++ b/src/keyiread-n.c
+@@ -153,7 +153,7 @@ cm_keyiread_n_get_keys(struct cm_store_entry *entry, int readwrite)
+ 	}
+ 	PK11_SetPasswordFunc(&cm_pin_read_for_cert_nss_cb);
+ 	if (entry->cm_key_token == NULL) {
+-		entry->cm_key_token = util_internal_token_name();
++		entry->cm_key_token = talloc_strdup(entry, util_internal_token_name());
+ 	}
+ 	n_tokens = 0;
+ 	pubkey = NULL;
+diff --git a/src/submit-n.c b/src/submit-n.c
+index da07d253..ee6f3105 100644
+--- a/src/submit-n.c
++++ b/src/submit-n.c
+@@ -347,7 +347,7 @@ cm_submit_n_decrypt_envelope(const unsigned char *envelope,
+ 		goto done;
+ 	}
+ 	if (args->entry->cm_key_token == NULL) {
+-		args->entry->cm_key_token = util_internal_token_name();
++		args->entry->cm_key_token = talloc_strdup(args->entry, util_internal_token_name());
+ 	}
+ 	PK11_SetPasswordFunc(&cm_pin_read_for_cert_nss_cb);
+ 	n_tokens = 0;
+diff --git a/src/util-n.c b/src/util-n.c
+index 293e2583..4ab3d47b 100644
+--- a/src/util-n.c
++++ b/src/util-n.c
+@@ -291,5 +291,5 @@ util_set_db_entry_cert_owner(const char *dbdir, struct cm_store_entry *entry)
+ char *
+ util_internal_token_name()
+ {
+-	return strdup(PK11_GetTokenName(PK11_GetInternalKeySlot()));
++	return PK11_GetTokenName(PK11_GetInternalKeySlot());
+ }
+-- 
+2.14.4
+
diff --git a/SOURCES/0011-clang-Dead-assignment.patch b/SOURCES/0011-clang-Dead-assignment.patch
new file mode 100644
index 0000000..8aa4645
--- /dev/null
+++ b/SOURCES/0011-clang-Dead-assignment.patch
@@ -0,0 +1,266 @@
+From 648fe74986f2a84416805cfd73206e9e67166ae2 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Thu, 13 Sep 2018 15:40:23 -0400
+Subject: [PATCH 11/17] clang: Dead assignment
+
+---
+ src/casave.c           |  4 +++-
+ src/keygen-n.c         |  1 -
+ src/keyiread-n.c       |  1 -
+ src/store-files.c      |  2 --
+ src/store-gen.c        |  3 ---
+ src/submit-e.c         | 54 ++++++++++++++++++++++++++------------------------
+ src/submit-u.c         |  2 --
+ src/tdbush.c           |  8 ++++++--
+ tests/tools/addcinfo.c |  1 -
+ tests/tools/certsave.c |  4 +++-
+ 10 files changed, 40 insertions(+), 40 deletions(-)
+
+diff --git a/src/casave.c b/src/casave.c
+index 5fb31b8d..bde63f99 100644
+--- a/src/casave.c
++++ b/src/casave.c
+@@ -163,7 +163,6 @@ cm_casave_main_n(int fd, struct cm_store_ca *ca, struct cm_store_entry *e,
+ 			decoded = CERT_DecodeCertFromPackage(package,
+ 							     strlen(package));
+ 			p = state->certs[i]->nickname;
+-			ttrust = ",,";
+ 			switch (state->certs[i]->level) {
+ 			case root:
+ 			case other_root:
+@@ -178,6 +177,9 @@ cm_casave_main_n(int fd, struct cm_store_ca *ca, struct cm_store_entry *e,
+ 					ttrust = ",,";
+ 				}
+ 				break;
++			default:
++				ttrust = ",,";
++				break;
+ 			}
+ 			memset(&trust, 0, sizeof(trust));
+ 			CERT_DecodeTrustString(&trust, ttrust);
+diff --git a/src/keygen-n.c b/src/keygen-n.c
+index 76a5c1d3..061bd2af 100644
+--- a/src/keygen-n.c
++++ b/src/keygen-n.c
+@@ -591,7 +591,6 @@ retry_gen:
+ 			break;
+ 		}
+ 	}
+-	generated_size = SECKEY_PublicKeyStrengthInBits(pubkey);
+ 	cm_log(1, "Ended up with %d bit public key.\n",
+ 	       SECKEY_PublicKeyStrengthInBits(pubkey));
+ 	/* Check for keys with the desired name, selecting a new name if
+diff --git a/src/keyiread-n.c b/src/keyiread-n.c
+index 8f46ec0f..91b1be41 100644
+--- a/src/keyiread-n.c
++++ b/src/keyiread-n.c
+@@ -492,7 +492,6 @@ cm_keyiread_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 	readwrite = settings->readwrite;
+ 	keys = cm_keyiread_n_get_keys(entry, readwrite);
+ 	alg = "";
+-	size = 0;
+ 	if (keys != NULL) {
+ 		switch (SECKEY_GetPrivateKeyType(keys->privkey)) {
+ 		case rsaKey:
+diff --git a/src/store-files.c b/src/store-files.c
+index 06a17485..df1fa336 100644
+--- a/src/store-files.c
++++ b/src/store-files.c
+@@ -2182,7 +2182,6 @@ cm_store_entry_delete(struct cm_store_entry *entry)
+ 	} else {
+ 		cm_log(3, "No file to remove for \"%s\".\n",
+ 		       entry->cm_nickname);
+-		ret = 0;
+ 	}
+ 	return 0;
+ }
+@@ -2469,7 +2468,6 @@ cm_store_ca_delete(struct cm_store_ca *ca)
+ 		}
+ 	} else {
+ 		cm_log(3, "No file to remove for \"%s\".\n", ca->cm_nickname);
+-		ret = 0;
+ 	}
+ 	return 0;
+ }
+diff --git a/src/store-gen.c b/src/store-gen.c
+index 5ce4ab84..da32afc8 100644
+--- a/src/store-gen.c
++++ b/src/store-gen.c
+@@ -530,8 +530,6 @@ cm_store_hex_to_bin(const char *serial, unsigned char *buf, int length)
+ 	const char *p, *q, *chars = "0123456789abcdef";
+ 	unsigned char *b, u;
+ 
+-	p = serial;
+-	b = buf;
+ 	u = 0;
+ 	for (p = serial, b = buf;
+ 	     ((*p != '\0') && ((b - buf) < length));
+@@ -606,7 +604,6 @@ cm_store_canonicalize_path(void *parent, const char *path)
+ 		for (p = tmp; *p != '\0'; p++) {
+ 			if ((strncmp(p, "/.", 2) == 0) &&
+ 			    ((p[2] == '/') || (p[2] == '\0'))) {
+-				q = p - 1;
+ 				memmove(p, p + 2, strlen(p + 2) + 1);
+ 			}
+ 		}
+diff --git a/src/submit-e.c b/src/submit-e.c
+index 8ba8e44c..d6158d7a 100644
+--- a/src/submit-e.c
++++ b/src/submit-e.c
+@@ -587,32 +587,34 @@ cm_submit_e_postprocess_main(int fd, struct cm_store_ca *ca,
+ 				   estate->msg_length, NULL);
+ 		msg = cm_json_new_object(estate);
+ 		chain = cm_json_new_array(msg);
+-		if (leaf != NULL) {
+-			cert = cm_json_new_string(msg, leaf, -1);
+-			cm_json_set(msg, CM_SUBMIT_E_CERTIFICATE, cert);
+-		}
+-		for (i = 0;
+-		     (others != NULL) && (others[i] != NULL);
+-		     i++) {
+-			cert = cm_json_new_object(chain);
+-			val = cm_json_new_string(cert, others[i], -1);
+-			cm_json_set(cert, CM_SUBMIT_E_CERTIFICATE, val);
+-			nthnick = talloc_asprintf(cert, "chain #%d", i + 1);
+-			nick = cm_json_new_string(cert, nthnick, -1);
+-			cm_json_set(cert, CM_SUBMIT_E_NICKNAME, nick);
+-			cm_json_append(chain, cert);
+-		}
+-		if (top!= NULL) {
+-			cert = cm_json_new_object(chain);
+-			val = cm_json_new_string(cert, top, -1);
+-			cm_json_set(cert, CM_SUBMIT_E_CERTIFICATE, val);
+-			nthnick = talloc_asprintf(cert, "chain #%d", i + 1);
+-			nick = cm_json_new_string(cert, nthnick, -1);
+-			cm_json_set(cert, CM_SUBMIT_E_NICKNAME, nick);
+-			cm_json_append(chain, cert);
+-		}
+-		if (cm_json_array_size(chain) > 0) {
+-			cm_json_set(msg, CM_SUBMIT_E_CHAIN, chain);
++		if (i == 0) {
++			if (leaf != NULL) {
++				cert = cm_json_new_string(msg, leaf, -1);
++				cm_json_set(msg, CM_SUBMIT_E_CERTIFICATE, cert);
++			}
++			for (i = 0;
++			     (others != NULL) && (others[i] != NULL);
++			     i++) {
++				cert = cm_json_new_object(chain);
++				val = cm_json_new_string(cert, others[i], -1);
++				cm_json_set(cert, CM_SUBMIT_E_CERTIFICATE, val);
++				nthnick = talloc_asprintf(cert, "chain #%d", i + 1);
++				nick = cm_json_new_string(cert, nthnick, -1);
++				cm_json_set(cert, CM_SUBMIT_E_NICKNAME, nick);
++				cm_json_append(chain, cert);
++			}
++			if (top!= NULL) {
++				cert = cm_json_new_object(chain);
++				val = cm_json_new_string(cert, top, -1);
++				cm_json_set(cert, CM_SUBMIT_E_CERTIFICATE, val);
++				nthnick = talloc_asprintf(cert, "chain #%d", i + 1);
++				nick = cm_json_new_string(cert, nthnick, -1);
++				cm_json_set(cert, CM_SUBMIT_E_NICKNAME, nick);
++				cm_json_append(chain, cert);
++			}
++			if (cm_json_array_size(chain) > 0) {
++				cm_json_set(msg, CM_SUBMIT_E_CHAIN, chain);
++			}
+ 		}
+ 	}
+ 	/* Get ready to build an output message. */
+diff --git a/src/submit-u.c b/src/submit-u.c
+index dda2edbc..b0b45baf 100644
+--- a/src/submit-u.c
++++ b/src/submit-u.c
+@@ -120,14 +120,12 @@ cm_submit_u_from_file_single(const char *filename)
+ 	if (csr == NULL) {
+ 		return NULL;
+ 	}
+-	p = csr;
+ 	for (i = 0; i < sizeof(strip) / sizeof(strip[0]); i++) {
+ 		while ((p = strstr(csr, strip[i])) != NULL) {
+ 			q = p + strcspn(p, "\r\n");
+ 			memmove(p, q, strlen(q) + 1);
+ 		}
+ 	}
+-	p = csr;
+ 	q = strdup(csr);
+ 	for (p = csr, i = 0; *p != '\0'; p++) {
+ 		if (strchr("\r\n\t ", *p) == NULL) {
+diff --git a/src/tdbush.c b/src/tdbush.c
+index 1d487222..3184e67a 100644
+--- a/src/tdbush.c
++++ b/src/tdbush.c
+@@ -2911,7 +2911,6 @@ request_get_key_type_and_size(DBusConnection *conn, DBusMessage *msg,
+ 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ 	}
+ 	rep = dbus_message_new_method_return(msg);
+-	type = "UNKNOWN";
+ 	switch (entry->cm_key_type.cm_key_algorithm) {
+ 	case cm_key_unspecified:
+ 		type = "UNKNOWN";
+@@ -2929,6 +2928,9 @@ request_get_key_type_and_size(DBusConnection *conn, DBusMessage *msg,
+ 		type = "EC";
+ 		break;
+ #endif
++	default:
++		type = "UNKNOWN";
++		break;
+ 	}
+ 	if (rep != NULL) {
+ 		size = entry->cm_key_type.cm_key_size;
+@@ -4790,7 +4792,6 @@ cm_tdbush_introspect_method(void *parent,
+ 			      method->cm_name);
+ 	arg = method->cm_args;
+ 	while (arg != NULL) {
+-		direction = "unknown";
+ 		switch (arg->cm_direction) {
+ 		case cm_tdbush_method_arg_in:
+ 			direction = "in";
+@@ -4798,6 +4799,9 @@ cm_tdbush_introspect_method(void *parent,
+ 		case cm_tdbush_method_arg_out:
+ 			direction = "out";
+ 			break;
++		default:
++			direction = "unknown";
++			break;
+ 		}
+ 		ret = talloc_asprintf(parent,
+ 				      "%s\n   <arg name=\"%s\" type=\"%s\" "
+diff --git a/tests/tools/addcinfo.c b/tests/tools/addcinfo.c
+index d3cea2ca..f016acb4 100644
+--- a/tests/tools/addcinfo.c
++++ b/tests/tools/addcinfo.c
+@@ -98,7 +98,6 @@ main(int argc, char **argv)
+ 		       PR_ErrorToName(PORT_GetError()));
+ 		return 1;
+ 	}
+-	n = encoded.len;
+ 	j = 0;
+ 	while ((i = write(STDOUT_FILENO, encoded.data + j, encoded.len - j)) > 0) {
+ 		j += i;
+diff --git a/tests/tools/certsave.c b/tests/tools/certsave.c
+index fd86a4c1..8ec60ddd 100644
+--- a/tests/tools/certsave.c
++++ b/tests/tools/certsave.c
+@@ -83,7 +83,6 @@ main(int argc, char **argv)
+ 		if (cm_certsave_saved(state) == 0) {
+ 			ret = 0;
+ 		} else {
+-			ctype = "unknown";
+ 			switch (entry->cm_cert_storage_type) {
+ 			case cm_cert_storage_file:
+ 				ctype = "FILE";
+@@ -91,6 +90,9 @@ main(int argc, char **argv)
+ 			case cm_cert_storage_nssdb:
+ 				ctype = "NSS";
+ 				break;
++			default:
++				ctype = "unknown";
++				break;
+ 			}
+ 			if (cm_certsave_conflict_subject(state) == 0) {
+ 				printf("Failed to save (%s:%s), "
+-- 
+2.14.4
+
diff --git a/SOURCES/0012-clang-Memory-leak.patch b/SOURCES/0012-clang-Memory-leak.patch
new file mode 100644
index 0000000..d2fc9e0
--- /dev/null
+++ b/SOURCES/0012-clang-Memory-leak.patch
@@ -0,0 +1,437 @@
+From 3310a25181e94f5e05e671acc12d008cbac339ab Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Thu, 13 Sep 2018 15:50:53 -0400
+Subject: [PATCH 12/17] clang: Memory leak
+
+---
+ src/certmaster.c       |  3 +++
+ src/certsave-o.c       |  1 +
+ src/dogtag.c           |  3 +++
+ src/ipa.c              |  9 ++++++++-
+ src/local.c            |  5 +++++
+ src/scep.c             |  5 +++++
+ src/srvloc.c           |  1 +
+ src/store-files.c      |  2 +-
+ src/submit-x.c         | 22 ++++++++++++++++++++++
+ src/util.c             |  8 +++++++-
+ tests/tools/addcinfo.c |  3 +++
+ tests/tools/base2pem.c |  1 +
+ tests/tools/pem2base.c |  1 +
+ 13 files changed, 61 insertions(+), 3 deletions(-)
+
+diff --git a/src/certmaster.c b/src/certmaster.c
+index 7e0bed90..4a5cf6af 100644
+--- a/src/certmaster.c
++++ b/src/certmaster.c
+@@ -160,6 +160,7 @@ main(int argc, const char **argv)
+ 			       CM_SUBMIT_CSR_ENV);
+ 		}
+ 		poptPrintUsage(pctx, stdout, 0);
++		free(csr);
+ 		return CM_SUBMIT_STATUS_UNCONFIGURED;
+ 	}
+ 
+@@ -185,11 +186,13 @@ main(int argc, const char **argv)
+ 	if (ctx == NULL) {
+ 		fprintf(stderr, "Error setting up for XMLRPC.\n");
+ 		printf(_("Error setting up for XMLRPC.\n"));
++		free(csr);
+ 		return CM_SUBMIT_STATUS_UNCONFIGURED;
+ 	}
+ 
+ 	/* Add the CSR as the sole argument. */
+ 	cm_submit_x_add_arg_s(ctx, csr);
++	free(csr);
+ 
+ 	/* Submit the request. */
+ 	fprintf(stderr, "Submitting request to \"%s\".\n", uri);
+diff --git a/src/certsave-o.c b/src/certsave-o.c
+index 77f54d7e..3d4018d8 100644
+--- a/src/certsave-o.c
++++ b/src/certsave-o.c
+@@ -258,6 +258,7 @@ cm_certsave_o_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 					if (bin != NULL) {
+ 						BN_bn2bin(bn, bin);
+ 						serial = cm_store_hex_from_bin(NULL, bin, BN_num_bytes(bn));
++						free(bin);
+ 					}
+ 				}
+ 				if (serial != NULL) {
+diff --git a/src/dogtag.c b/src/dogtag.c
+index cd0b38b7..55607f3d 100644
+--- a/src/dogtag.c
++++ b/src/dogtag.c
+@@ -536,6 +536,7 @@ main(int argc, const char **argv)
+ 					       CM_SUBMIT_CSR_ENV);
+ 				}
+ 				poptPrintUsage(pctx, stdout, 0);
++				free(csr);
+ 				return CM_SUBMIT_STATUS_UNCONFIGURED;
+ 			}
+ 			csr = cm_submit_u_url_encode(csr);
+@@ -588,6 +589,8 @@ main(int argc, const char **argv)
+ 			params = talloc_asprintf(ctx,
+ 						 "%s&%s=%s",
+ 						 params, p, q);
++			free(p);
++			free(q);
+ 		}
+ 		use_agent_approval = FALSE;
+ 		break;
+diff --git a/src/ipa.c b/src/ipa.c
+index 67a0c651..acd1a4e2 100644
+--- a/src/ipa.c
++++ b/src/ipa.c
+@@ -226,6 +226,7 @@ cm_locate_xmlrpc_service(const char *server,
+ 	if (basedn == NULL) {
+ 		i = cm_find_default_naming_context(ld, &basedn);
+ 		if (i != 0) {
++			free(basedn);
+ 			return i;
+ 		}
+ 	}
+@@ -526,6 +527,7 @@ fetch_roots(const char *server, int ldap_uri_cmd, const char *ldap_uri,
+ 	if (basedn == NULL) {
+ 		i = cm_find_default_naming_context(ld, &basedn);
+ 		if (i != 0) {
++			free(basedn);
+ 			return i;
+ 		}
+ 	}
+@@ -802,6 +804,7 @@ main(int argc, const char **argv)
+ 				printf(_("Unable to read signing request from environment variable \"%s\".\n"),
+ 				       CM_SUBMIT_CSR_ENV);
+ 			}
++			free(csr);
+ 			poptPrintUsage(pctx, stdout, 0);
+ 			return CM_SUBMIT_STATUS_UNCONFIGURED;
+ 		}
+@@ -903,12 +906,16 @@ main(int argc, const char **argv)
+ 
+ 	if ((strcasecmp(mode, CM_OP_SUBMIT) == 0) ||
+ 	    (strcasecmp(mode, CM_OP_POLL) == 0)) {
+-		return submit_or_poll(uri, cainfo, capath, server,
++		int ret;
++		ret = submit_or_poll(uri, cainfo, capath, server,
+ 				      ldap_uri_cmd, ldap_uri, host, domain,
+ 				      basedn, uid, pwd, csr, reqprinc, profile,
+ 				      issuer);
++		free(csr);
++		return ret;
+ 	} else
+ 	if (strcasecmp(mode, CM_OP_FETCH_ROOTS) == 0) {
++		free(csr);
+ 		return fetch_roots(server, ldap_uri_cmd, ldap_uri, host,
+ 				   uid, pwd, domain, basedn);
+ 	}
+diff --git a/src/local.c b/src/local.c
+index f437d62e..92bea144 100644
+--- a/src/local.c
++++ b/src/local.c
+@@ -559,6 +559,7 @@ main(int argc, const char **argv)
+ 			printf(_("Unable to read signing request.\n"));
+ 			cm_log(1, "Unable to read signing request.\n");
+ 			poptPrintUsage(pctx, stdout, 0);
++			free(csr);
+ 			return CM_SUBMIT_STATUS_UNCONFIGURED;
+ 		}
+ 		/* Take the lock. */
+@@ -568,6 +569,7 @@ main(int argc, const char **argv)
+ 				    &signer, &key);
+ 		if ((i != 0) || (signer == NULL)) {
+ 			cm_log(1, "Error reading signer info.\n");
++			free(csr);
+ 			/* Try again sometime later. */
+ 			return CM_SUBMIT_STATUS_UNREACHABLE;
+ 		}
+@@ -577,11 +579,13 @@ main(int argc, const char **argv)
+ 		if ((fp == NULL) && (errno != ENOENT)) {
+ 			cm_log(1, "Error reading '%s': %s.\n", serial,
+ 			       strerror(errno));
++			free(csr);
+ 			return CM_SUBMIT_STATUS_UNREACHABLE;
+ 		}
+ 		if (fp != NULL) {
+ 			if (fgets(buf, sizeof(buf), fp) == NULL) {
+ 				fclose(fp);
++				free(csr);
+ 				return CM_SUBMIT_STATUS_UNREACHABLE;
+ 			}
+ 			buf[strcspn(buf, "\r\n")] = '\0';
+@@ -601,6 +605,7 @@ main(int argc, const char **argv)
+ 		/* Actually sign the request. */
+ 		i = cm_submit_o_sign(parent, csr, signer, key, hexserial,
+ 				     now, 0, &cert);
++		free(csr);
+ 		if ((i == 0) && (cert != NULL)) {
+ 			/* Roll the serial number up. */
+ 			hexserial = cm_store_increment_serial(parent,
+diff --git a/src/scep.c b/src/scep.c
+index 72dff3d5..68eae788 100644
+--- a/src/scep.c
++++ b/src/scep.c
+@@ -338,6 +338,7 @@ main(int argc, const char **argv)
+ 	}
+ 	if (c != -1) {
+ 		poptPrintUsage(pctx, stdout, 0);
++		free(cainfo);
+ 		return CM_SUBMIT_STATUS_UNCONFIGURED;
+ 	}
+ 
+@@ -386,6 +387,7 @@ main(int argc, const char **argv)
+ 			}
+ 			if ((message == NULL) || (strlen(message) == 0)) {
+ 				printf(_("Error reading request.  Expected PKCS7 data containing a GetInitialCert pkiMessage, got nothing.\n"));
++				free(cainfo);
+ 				return CM_SUBMIT_STATUS_NEED_SCEP_MESSAGES;
+ 			}
+ 			/* First step: read capabilities for our use. */
+@@ -405,6 +407,7 @@ main(int argc, const char **argv)
+ 			}
+ 			if ((message == NULL) || (strlen(message) == 0)) {
+ 				printf(_("Error reading request.  Expected PKCS7 data containing a PKCSReq pkiMessage, got nothing.\n"));
++				free(cainfo);
+ 				return CM_SUBMIT_STATUS_NEED_SCEP_MESSAGES;
+ 			}
+ 			/* First step: read capabilities for our use. */
+@@ -416,6 +419,7 @@ main(int argc, const char **argv)
+ 	/* Supply help output, if it's needed. */
+ 	if (missing_args) {
+ 		poptPrintUsage(pctx, stdout, 0);
++		free(cainfo);
+ 		return CM_SUBMIT_STATUS_UNCONFIGURED;
+ 	}
+ 
+@@ -492,6 +496,7 @@ main(int argc, const char **argv)
+ 				verbose > 1 ?
+ 				cm_submit_h_curl_verbose_on :
+ 				cm_submit_h_curl_verbose_off);
++	free(cainfo);
+ 	cm_submit_h_run(hctx);
+ 	content_type = cm_submit_h_result_type(hctx);
+ 	if (content_type == NULL) {
+diff --git a/src/srvloc.c b/src/srvloc.c
+index acab55bf..e8f3f5a5 100644
+--- a/src/srvloc.c
++++ b/src/srvloc.c
+@@ -189,6 +189,7 @@ cm_srvloc_resolve(void *parent, const char *name, const char *udomain,
+ 	domain = strdup(udomain);
+ #endif
+ 	i = res_querydomain(name, domain, C_IN, T_SRV, answer, answer_len);
++	free(domain);
+ 	if (i == -1) {
+ 		return -1;
+ 	}
+diff --git a/src/store-files.c b/src/store-files.c
+index df1fa336..b97ba5ff 100644
+--- a/src/store-files.c
++++ b/src/store-files.c
+@@ -558,8 +558,8 @@ cm_store_file_read_lines(void *parent, FILE *fp)
+ 		case ';':
+ 			break;
+ 		}
++		free(buf);
+ 	}
+-	free(buf);
+ 	/* If we were reading a line, append it to the list. */
+ 	if (s != NULL) {
+ 		tlines = talloc_realloc(parent, lines, char *, n_lines + 2);
+diff --git a/src/submit-x.c b/src/submit-x.c
+index 60bcf78a..fa81e9aa 100644
+--- a/src/submit-x.c
++++ b/src/submit-x.c
+@@ -75,6 +75,8 @@ cm_submit_x_ccache_realm(char **msg)
+ 			ret = get_error_message(ctx, kret));
+ 		if (msg != NULL) {
+ 			*msg = ret;
++		} else {
++			free(ret);
+ 		}
+ 		return NULL;
+ 	}
+@@ -84,6 +86,8 @@ cm_submit_x_ccache_realm(char **msg)
+ 			ret = get_error_message(ctx, kret));
+ 		if (msg != NULL) {
+ 			*msg = ret;
++		} else {
++			free(ret);
+ 		}
+ 		return NULL;
+ 	}
+@@ -93,6 +97,8 @@ cm_submit_x_ccache_realm(char **msg)
+ 			ret = get_error_message(ctx, kret));
+ 		if (msg != NULL) {
+ 			*msg = ret;
++		} else {
++			free(ret);
+ 		}
+ 		return NULL;
+ 	}
+@@ -139,6 +145,8 @@ cm_submit_x_make_ccache(const char *ktname, const char *principal, char **msg)
+ 		fprintf(stderr, "Error initializing Kerberos: %s.\n", ret);
+ 		if (msg != NULL) {
+ 			*msg = ret;
++		} else {
++			free(ret);
+ 		}
+ 		return kret;
+ 	}
+@@ -152,6 +160,8 @@ cm_submit_x_make_ccache(const char *ktname, const char *principal, char **msg)
+ 			ret = get_error_message(ctx, kret));
+ 		if (msg != NULL) {
+ 			*msg = ret;
++		} else {
++			free(ret);
+ 		}
+ 		return kret;
+ 	}
+@@ -163,6 +173,8 @@ cm_submit_x_make_ccache(const char *ktname, const char *principal, char **msg)
+ 				principal, ret = get_error_message(ctx, kret));
+ 			if (msg != NULL) {
+ 				*msg = ret;
++			} else {
++				free(ret);
+ 			}
+ 			return kret;
+ 		}
+@@ -174,6 +186,8 @@ cm_submit_x_make_ccache(const char *ktname, const char *principal, char **msg)
+ 				ret = get_error_message(ctx, kret));
+ 			if (msg != NULL) {
+ 				*msg = ret;
++			} else {
++				free(ret);
+ 			}
+ 			return kret;
+ 		}
+@@ -195,6 +209,8 @@ cm_submit_x_make_ccache(const char *ktname, const char *principal, char **msg)
+ 			ret = get_error_message(ctx, kret));
+ 		if (msg != NULL) {
+ 			*msg = ret;
++		} else {
++			free(ret);
+ 		}
+ 		return kret;
+ 	}
+@@ -213,6 +229,8 @@ cm_submit_x_make_ccache(const char *ktname, const char *principal, char **msg)
+ 			ret = get_error_message(ctx, kret));
+ 		if (msg != NULL) {
+ 			*msg = ret;
++		} else {
++			free(ret);
+ 		}
+ 		return kret;
+ 	}
+@@ -227,6 +245,8 @@ cm_submit_x_make_ccache(const char *ktname, const char *principal, char **msg)
+ 			ret = get_error_message(ctx, kret));
+ 		if (msg != NULL) {
+ 			*msg = ret;
++		} else {
++			free(ret);
+ 		}
+ 		return kret;
+ 	}
+@@ -237,6 +257,8 @@ cm_submit_x_make_ccache(const char *ktname, const char *principal, char **msg)
+ 			ret = get_error_message(ctx, kret));
+ 		if (msg != NULL) {
+ 			*msg = ret;
++		} else {
++			free(ret);
+ 		}
+ 		return kret;
+ 	}
+diff --git a/src/util.c b/src/util.c
+index 67143d52..373bb533 100644
+--- a/src/util.c
++++ b/src/util.c
+@@ -98,7 +98,7 @@ read_config_file(const char *filename)
+ char *
+ get_config_entry(char * in_data, const char *section, const char *key)
+ {
+-    char *ptr = NULL, *p, *tmp;
++    char *ptr = NULL, *p, *tmp = NULL;
+     char *line;
+     int in_section = 0;
+     char * data = strdup(in_data);
+@@ -129,9 +129,12 @@ get_config_entry(char * in_data, const char *section, const char *key)
+                 }
+                 if (strcmp(section, tmp) == 0) {
+                     free(tmp);
++                    tmp = NULL;
+                     in_section = 1;
+                     continue;
+                 }
++                free(tmp);
++                tmp = NULL;
+             }
+         } /* [ */
+ 
+@@ -145,8 +148,10 @@ get_config_entry(char * in_data, const char *section, const char *key)
+             tmp = strndup(line, p - line);
+             if (strcmp(key, tmp) != 0) {
+                 free(tmp);
++				tmp = NULL;
+             } else {
+                 free(tmp);
++				tmp = NULL;
+ 
+                 /* Skip over any whitespace after the equal sign. */
+                 line = strchr(line, '=');
+@@ -168,5 +173,6 @@ get_config_entry(char * in_data, const char *section, const char *key)
+         }
+     }
+     free(data);
++    free(tmp);
+     return NULL;
+ }
+diff --git a/tests/tools/addcinfo.c b/tests/tools/addcinfo.c
+index f016acb4..939005c2 100644
+--- a/tests/tools/addcinfo.c
++++ b/tests/tools/addcinfo.c
+@@ -86,6 +86,7 @@ main(int argc, char **argv)
+ 	if (enveloped == NULL) {
+ 		cm_log(0, "Internal error: %s.\n",
+ 		       PR_ErrorToName(PORT_GetError()));
++		free(buffer);
+ 		return 1;
+ 	}
+ 	ci.content_type = enveloped->oid;
+@@ -96,6 +97,7 @@ main(int argc, char **argv)
+ 			       content_info_template) != &encoded) {
+ 		cm_log(0, "Encoding error: %s.\n",
+ 		       PR_ErrorToName(PORT_GetError()));
++		free(buffer);
+ 		return 1;
+ 	}
+ 	j = 0;
+@@ -105,5 +107,6 @@ main(int argc, char **argv)
+ 			break;
+ 		}
+ 	}
++	free(buffer);
+ 	return 0;
+ }
+diff --git a/tests/tools/base2pem.c b/tests/tools/base2pem.c
+index 40e74201..31359684 100644
+--- a/tests/tools/base2pem.c
++++ b/tests/tools/base2pem.c
+@@ -76,5 +76,6 @@ main(int argc, const char **argv)
+ 		}
+ 	}
+ 	printf("%s", cm_submit_u_pem_from_base64(type, dos, p));
++	free(p);
+ 	return 0;
+ }
+diff --git a/tests/tools/pem2base.c b/tests/tools/pem2base.c
+index 0607c162..bb686c0e 100644
+--- a/tests/tools/pem2base.c
++++ b/tests/tools/pem2base.c
+@@ -46,5 +46,6 @@ main(int argc, char **argv)
+ 		}
+ 	}
+ 	printf("%s\n", cm_submit_u_base64_from_text(p));
++	free(p);
+ 	return 0;
+ }
+-- 
+2.14.4
+
diff --git a/SOURCES/0013-clang-Uninitialized-initial-value.patch b/SOURCES/0013-clang-Uninitialized-initial-value.patch
new file mode 100644
index 0000000..aee4628
--- /dev/null
+++ b/SOURCES/0013-clang-Uninitialized-initial-value.patch
@@ -0,0 +1,25 @@
+From db0f835829b739cf843d44b08c22407194aadd71 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Thu, 13 Sep 2018 17:57:21 -0400
+Subject: [PATCH 13/17] clang: Uninitialized initial value
+
+---
+ src/submit-n.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/submit-n.c b/src/submit-n.c
+index ee6f3105..b07ea23a 100644
+--- a/src/submit-n.c
++++ b/src/submit-n.c
+@@ -281,7 +281,7 @@ cm_submit_n_decrypt_envelope(const unsigned char *envelope,
+ 	PLArenaPool *arena = NULL;
+ 	SECStatus error;
+ 	NSSInitContext *ctx = NULL;
+-	PK11SlotInfo *slot;
++	PK11SlotInfo *slot = NULL;
+ 	PK11SlotList *slotlist = NULL;
+ 	PK11SlotListElement *sle;
+ 	SECKEYPrivateKeyList *keylist = NULL;
+-- 
+2.14.4
+
diff --git a/SOURCES/0014-clang-Null-pointer-passed-as-an-argument-to-a-nonnul.patch b/SOURCES/0014-clang-Null-pointer-passed-as-an-argument-to-a-nonnul.patch
new file mode 100644
index 0000000..49e488f
--- /dev/null
+++ b/SOURCES/0014-clang-Null-pointer-passed-as-an-argument-to-a-nonnul.patch
@@ -0,0 +1,99 @@
+From 753d98b3e70f34a52caabbe8db30bf06fc917f38 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Thu, 13 Sep 2018 11:46:51 -0400
+Subject: [PATCH 14/17] clang: Null pointer passed as an argument to a
+ 'nonnull' parameter
+
+---
+ src/certsave-n.c | 3 ++-
+ src/getcert.c    | 7 ++++---
+ src/scep.c       | 8 ++++----
+ src/submit-sn.c  | 7 +++++--
+ 4 files changed, 15 insertions(+), 10 deletions(-)
+
+diff --git a/src/certsave-n.c b/src/certsave-n.c
+index 49b28324..972a1dfa 100644
+--- a/src/certsave-n.c
++++ b/src/certsave-n.c
+@@ -72,7 +72,8 @@ add_privkey_to_list(SECKEYPrivateKey **list, SECKEYPrivateKey *key)
+ 		if ((list == NULL) || (list[i] == NULL)) {
+ 			newlist = malloc(sizeof(newlist[0]) * (i + 2));
+ 			if (newlist != NULL) {
+-				memcpy(newlist, list, sizeof(newlist[0]) * i);
++				if (list != NULL)
++					memcpy(newlist, list, sizeof(newlist[0]) * i);
+ 				newlist[i] = key;
+ 				newlist[i + 1] = NULL;
+ 				list = newlist;
+diff --git a/src/getcert.c b/src/getcert.c
+index 6417cd44..ddb28de2 100644
+--- a/src/getcert.c
++++ b/src/getcert.c
+@@ -291,7 +291,8 @@ add_string(void *parent, char ***dest, const char *value)
+ 		printf(_("Out of memory.\n"));
+ 		exit(1);
+ 	}
+-	memcpy(tmp, *dest, sizeof(tmp[0]) * i);
++	if (*dest)
++		memcpy(tmp, *dest, sizeof(tmp[0]) * i);
+ 	tmp[i] = talloc_strdup(tmp, value);
+ 	i++;
+ 	tmp[i] = NULL;
+@@ -1582,8 +1583,8 @@ add_basic_request(enum cm_tdbus_type bus, char *id,
+ {
+ 	DBusMessage *req, *rep;
+ 	int i;
+-	struct cm_tdbusm_dict param[28];
+-	const struct cm_tdbusm_dict *params[29];
++	struct cm_tdbusm_dict param[30];
++	const struct cm_tdbusm_dict *params[30];
+ 	dbus_bool_t b;
+ 	const char *capath;
+ 	char *p;
+diff --git a/src/scep.c b/src/scep.c
+index 68eae788..b0bd214b 100644
+--- a/src/scep.c
++++ b/src/scep.c
+@@ -793,8 +793,8 @@ main(int argc, const char **argv)
+ 				fprintf(stderr, "code_text = \"%s\"\n", cm_submit_h_result_code_text(hctx));
+ 				syslog(LOG_DEBUG, "%s %s?%s\n", "GET", url, params2);
+ 			}
+-			if (strcasecmp(content_type2,
+-				       "application/x-x509-ca-cert") != 0) {
++			if ((content_type2 != NULL) && (strcasecmp(content_type2,
++				       "application/x-x509-ca-cert") != 0)) {
+ 				if (verbose > 0) {
+ 					fprintf(stderr, "Content is not "
+ 						"\"application/x-x509-ca-cert\""
+@@ -882,8 +882,8 @@ main(int argc, const char **argv)
+ 		break;
+ 	case op_get_cert_initial:
+ 	case op_pkcsreq:
+-		if (strcasecmp(content_type2,
+-			       "application/x-pki-message") == 0) {
++		if ((content_type2 != NULL) && (strcasecmp(content_type2,
++			       "application/x-pki-message") == 0)) {
+ 			memset(&cacerts, 0, sizeof(cacerts));
+ 			cacerts[0] = cacert ? cacert : racert;
+ 			cacerts[1] = cacert ? racert : NULL;
+diff --git a/src/submit-sn.c b/src/submit-sn.c
+index e9c62b22..ecd78dc0 100644
+--- a/src/submit-sn.c
++++ b/src/submit-sn.c
+@@ -258,8 +258,11 @@ cm_submit_sn_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 	/* Allocate space for one more extension. */
+ 	extensions = PORT_ArenaZAlloc(arena, (i + 2) * sizeof(extensions[0]));
+ 	if (extensions != NULL) {
+-		memcpy(extensions, ucert->extensions,
+-		       i * sizeof(extensions[0]));
++		if (i != 0) {
++			/* Note that C99 says copy of 0 items is ok, quieting clang */
++			memcpy(extensions, ucert->extensions,
++			       i * sizeof(extensions[0]));
++		}
+ 		if (found_basic) {
+ 			extensions[i] = NULL;
+ 		} else {
+-- 
+2.14.4
+
diff --git a/SOURCES/0015-clang-Dead-increment.patch b/SOURCES/0015-clang-Dead-increment.patch
new file mode 100644
index 0000000..783b366
--- /dev/null
+++ b/SOURCES/0015-clang-Dead-increment.patch
@@ -0,0 +1,24 @@
+From 9e44680dbd207cef48beb7598114ea59aa457055 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Fri, 14 Sep 2018 16:15:23 -0400
+Subject: [PATCH 15/17] clang: Dead increment
+
+---
+ src/store-gen.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/src/store-gen.c b/src/store-gen.c
+index da32afc8..653767a1 100644
+--- a/src/store-gen.c
++++ b/src/store-gen.c
+@@ -363,7 +363,6 @@ cm_store_time_from_timestamp(const char *timestamp)
+ 	buf[2] = '\0';
+ 	stamp.tm_min = atoi(buf);
+ 	memcpy(buf, timestamp + i, 2);
+-	i += 2;
+ 	buf[2] = '\0';
+ 	stamp.tm_sec = atoi(buf);
+ 	t = timegm(&stamp);
+-- 
+2.14.4
+
diff --git a/SOURCES/0016-clang-Dereference-of-null-pointer.patch b/SOURCES/0016-clang-Dereference-of-null-pointer.patch
new file mode 100644
index 0000000..af96433
--- /dev/null
+++ b/SOURCES/0016-clang-Dereference-of-null-pointer.patch
@@ -0,0 +1,83 @@
+From 319858127df42c1a95b9b3282705c90ecd6754a5 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Fri, 14 Sep 2018 16:16:55 -0400
+Subject: [PATCH 16/17] clang: Dereference of null pointer
+
+---
+ src/tdbush.c | 56 +++++++++++++++++++++++++++++---------------------------
+ 1 file changed, 29 insertions(+), 27 deletions(-)
+
+diff --git a/src/tdbush.c b/src/tdbush.c
+index 3184e67a..d1bbe4da 100644
+--- a/src/tdbush.c
++++ b/src/tdbush.c
+@@ -3655,37 +3655,39 @@ request_modify(DBusConnection *conn, DBusMessage *msg,
+ 				break;
+ 			}
+ 		}
+-		if (d[i] == NULL) {
+-			new_request_path = talloc_asprintf(parent, "%s/%s",
+-							   CM_DBUS_REQUEST_PATH,
+-							   entry->cm_busname);
+-			if ((n_propname > 0) &&
+-			    (n_propname + 1 < sizeof(propname) / sizeof(propname[0]))) {
+-				propname[n_propname] = NULL;
+-				cm_tdbush_property_emit_changed(ctx, new_request_path,
+-								CM_DBUS_REQUEST_INTERFACE,
+-								propname);
+-			}
+-			cm_tdbusm_set_bp(rep,
+-					 cm_restart_entry(ctx,
+-							  entry->cm_nickname),
+-					 new_request_path);
+-			dbus_connection_send(conn, rep, NULL);
+-			dbus_message_unref(rep);
+-			talloc_free(new_request_path);
+-			return DBUS_HANDLER_RESULT_HANDLED;
+-		} else {
+-			dbus_message_unref(rep);
+-			rep = dbus_message_new_error(msg,
+-						     CM_DBUS_ERROR_REQUEST_BAD_ARG,
+-						     _("Unrecognized parameter or wrong value type."));
+-			if (rep != NULL) {
+-				cm_tdbusm_set_s(rep, d[i]->key);
++		if (d != NULL) {
++			if (d[i] == NULL) {
++				new_request_path = talloc_asprintf(parent, "%s/%s",
++								   CM_DBUS_REQUEST_PATH,
++								   entry->cm_busname);
++				if ((n_propname > 0) &&
++				    (n_propname + 1 < sizeof(propname) / sizeof(propname[0]))) {
++					propname[n_propname] = NULL;
++					cm_tdbush_property_emit_changed(ctx, new_request_path,
++									CM_DBUS_REQUEST_INTERFACE,
++									propname);
++				}
++				cm_tdbusm_set_bp(rep,
++						 cm_restart_entry(ctx,
++								  entry->cm_nickname),
++						 new_request_path);
+ 				dbus_connection_send(conn, rep, NULL);
+ 				dbus_message_unref(rep);
++				talloc_free(new_request_path);
+ 				return DBUS_HANDLER_RESULT_HANDLED;
++			} else {
++				dbus_message_unref(rep);
++				rep = dbus_message_new_error(msg,
++							     CM_DBUS_ERROR_REQUEST_BAD_ARG,
++							     _("Unrecognized parameter or wrong value type."));
++				if (rep != NULL) {
++					cm_tdbusm_set_s(rep, d[i]->key);
++					dbus_connection_send(conn, rep, NULL);
++					dbus_message_unref(rep);
++					return DBUS_HANDLER_RESULT_HANDLED;
++				}
++				return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ 			}
+-			return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ 		}
+ 	} else {
+ 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+-- 
+2.14.4
+
diff --git a/SOURCES/0017-Add-missing-case-for-cm_prefs_aes192.patch b/SOURCES/0017-Add-missing-case-for-cm_prefs_aes192.patch
new file mode 100644
index 0000000..f6a2e8a
--- /dev/null
+++ b/SOURCES/0017-Add-missing-case-for-cm_prefs_aes192.patch
@@ -0,0 +1,26 @@
+From f17b7c0a22f4d49dca001d984673046e133577d1 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Fri, 14 Sep 2018 16:41:19 -0400
+Subject: [PATCH 17/17] Add missing case for cm_prefs_aes192
+
+---
+ src/prefs-o.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/prefs-o.c b/src/prefs-o.c
+index 64542f85..ac68164d 100644
+--- a/src/prefs-o.c
++++ b/src/prefs-o.c
+@@ -75,6 +75,9 @@ cm_prefs_ossl_cipher_by_pref(enum cm_prefs_cipher cipher)
+ 	case cm_prefs_aes128:
+ 		return EVP_aes_128_cbc();
+ 		break;
++	case cm_prefs_aes192:
++		return EVP_aes_192_cbc();
++		break;
+ 	case cm_prefs_aes256:
+ 		return EVP_aes_256_cbc();
+ 		break;
+-- 
+2.14.4
+
diff --git a/SOURCES/0018-clang-more-Dead-assignment.patch b/SOURCES/0018-clang-more-Dead-assignment.patch
new file mode 100644
index 0000000..0cb3021
--- /dev/null
+++ b/SOURCES/0018-clang-more-Dead-assignment.patch
@@ -0,0 +1,41 @@
+From 20d569b57edf2f859aeb48d32bbb91801a45fb91 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Mon, 8 Oct 2018 12:48:41 -0400
+Subject: [PATCH 18/26] clang: more Dead assignment
+
+---
+ src/submit-x.c | 5 ++---
+ src/tdbus.c    | 1 -
+ 2 files changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/src/submit-x.c b/src/submit-x.c
+index fa81e9aa..abebc610 100644
+--- a/src/submit-x.c
++++ b/src/submit-x.c
+@@ -914,9 +914,8 @@ main(int argc, const char **argv)
+ 
+ 	/* Maybe we need a ccache. */
+ 	if (k5 || (kpname != NULL) || (ktname != NULL)) {
+-		if (!make_ccache ||
+-		    (cm_submit_x_make_ccache(ktname, kpname, NULL) == 0)) {
+-			k5 = TRUE;
++		if (make_ccache) {
++		    cm_submit_x_make_ccache(ktname, kpname, NULL);
+ 		}
+ 	}
+ 
+diff --git a/src/tdbus.c b/src/tdbus.c
+index cb0a8ad7..a81b5349 100644
+--- a/src/tdbus.c
++++ b/src/tdbus.c
+@@ -757,7 +757,6 @@ cm_tdbus_setup_public(struct tevent_context *ec, enum cm_tdbus_type bus_type,
+ 	/* Connect to the right bus. */
+ 	bus_desc = NULL;
+ 	conn = NULL;
+-	exit_on_disconnect = TRUE;
+ 	if (error != NULL) {
+ 		dbus_error_init(error);
+ 	}
+-- 
+2.14.4
+
diff --git a/SOURCES/0019-clang-more-Memory-leaks.patch b/SOURCES/0019-clang-more-Memory-leaks.patch
new file mode 100644
index 0000000..ea6d709
--- /dev/null
+++ b/SOURCES/0019-clang-more-Memory-leaks.patch
@@ -0,0 +1,321 @@
+From 83a701de85a6b22cc5ad3cec8cb2ddb54d0b2aae Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Mon, 8 Oct 2018 12:53:57 -0400
+Subject: [PATCH 19/26] clang: more Memory leaks
+
+Fix leaks in tests/tools/addcinfo.c, dogtag.c and submit-x.c
+---
+ src/dogtag.c           | 17 +++++++++++++----
+ src/getcert.c          |  3 ++-
+ src/store-files.c      |  1 +
+ src/submit-d.c         |  6 ++++++
+ src/submit-x.c         | 39 ++++++++++-----------------------------
+ tests/tools/addcinfo.c |  8 +++++---
+ 6 files changed, 37 insertions(+), 37 deletions(-)
+
+diff --git a/src/dogtag.c b/src/dogtag.c
+index 55607f3d..8e3890a5 100644
+--- a/src/dogtag.c
++++ b/src/dogtag.c
+@@ -117,7 +117,7 @@ main(int argc, const char **argv)
+ 	const char *ssldir = NULL, *cainfo = NULL, *capath = NULL;
+ 	const char *sslcert = NULL, *sslkey = NULL;
+ 	const char *sslpin = NULL, *sslpinfile = NULL;
+-	const char *csr = NULL, *serial = NULL, *template = NULL;
++	const char *csr = NULL, *csre = NULL, *serial = NULL, *template = NULL;
+ 	const char *uid = NULL, *pwd = NULL, *pwdfile = NULL;
+ 	const char *udn = NULL, *pin = NULL, *pinfile = NULL;
+ 	char *poptarg;
+@@ -127,7 +127,7 @@ main(int argc, const char **argv)
+ 	} *aoptions = NULL, *soptions = NULL;
+ 	size_t num_aoptions = 0, num_soptions = 0, j;
+ 	char *savedstate = NULL;
+-	char *p, *q, *params = NULL, *params2 = NULL;
++	char *p = NULL, *q = NULL, *params = NULL, *params2 = NULL;
+ 	const char *lasturl = NULL, *lastparams = NULL;
+ 	const char *tmp = NULL, *results = NULL;
+ 	struct cm_submit_h_context *hctx;
+@@ -537,16 +537,19 @@ main(int argc, const char **argv)
+ 				}
+ 				poptPrintUsage(pctx, stdout, 0);
+ 				free(csr);
++				free(p);
+ 				return CM_SUBMIT_STATUS_UNCONFIGURED;
+ 			}
+-			csr = cm_submit_u_url_encode(csr);
++			csre = cm_submit_u_url_encode(csr);
+ 			params = talloc_asprintf(ctx,
+ 						 "profileId=%s&"
+ 						 "cert_request_type=pkcs10&"
+ 						 "cert_request=%s&"
+ 						 "xml=true",
+ 						 template,
+-						 csr);
++						 csre);
++			free(csr);
++			free(csre);
+ 		}
+ 		/* Check for creds specified as options. */
+ 		for (j = 0; j < num_soptions; j++) {
+@@ -608,12 +611,16 @@ main(int argc, const char **argv)
+ 			printf(_("No agent URL (-A) given, and no default "
+ 				 "known.\n"));
+ 			poptPrintUsage(pctx, stdout, 0);
++			free(p);
++			free(q);
+ 			return CM_SUBMIT_STATUS_UNCONFIGURED;
+ 		}
+ 		if ((sslcert == NULL) || (strlen(sslcert) == 0)) {
+ 			printf(_("No agent credentials (-n) given, but they "
+ 				 "are needed.\n"));
+ 			poptPrintUsage(pctx, stdout, 0);
++			free(p);
++			free(q);
+ 			return CM_SUBMIT_STATUS_UNCONFIGURED;
+ 		}
+ 		/* Reading profile defaults for this certificate, then applying
+@@ -778,12 +785,14 @@ main(int argc, const char **argv)
+ 			       lasturl);
+ 		}
+ 		talloc_free(ctx);
++		free(p);
+ 		return CM_SUBMIT_STATUS_UNREACHABLE;
+ 	}
+ 	if (results == NULL) {
+ 		printf(_("Internal error: no response to \"%s?%s\".\n"),
+ 		       lasturl, lastparams);
+ 		talloc_free(ctx);
++		free(p);
+ 		return CM_SUBMIT_STATUS_REJECTED;
+ 	}
+ 	switch (op) {
+diff --git a/src/getcert.c b/src/getcert.c
+index ddb28de2..0d527ab0 100644
+--- a/src/getcert.c
++++ b/src/getcert.c
+@@ -4042,11 +4042,12 @@ thumbprint(const char *s, SECOidTag tag, int bits)
+ 	}
+ 	u = malloc(length);
+ 	if (u == NULL) {
++		free(t);
+ 		goto done;
+ 	}
+ 	length = cm_store_base64_to_bin(t, -1, u, length);
++	free(t);
+ 	if (PK11_HashBuf(tag, digest, u, length) == SECSuccess) {
+-		free(t);
+ 		t = malloc(bits / 4 + howmany(bits, 32));
+ 		if (t != NULL) {
+ 			ret = t;
+diff --git a/src/store-files.c b/src/store-files.c
+index b97ba5ff..4e57ae16 100644
+--- a/src/store-files.c
++++ b/src/store-files.c
+@@ -573,6 +573,7 @@ cm_store_file_read_lines(void *parent, FILE *fp)
+ 			lines = tlines;
+ 		}
+ 	}
++	free(buf);
+ 	return lines;
+ }
+ 
+diff --git a/src/submit-d.c b/src/submit-d.c
+index 5a4edb3f..36cc9828 100644
+--- a/src/submit-d.c
++++ b/src/submit-d.c
+@@ -1204,6 +1204,9 @@ restart:
+ 		} else {
+ 			printf("Error %d.\n", c);
+ 		}
++		if (defaults != nodefault) {
++			free(defaults);
++		}
+ 		return 1;
+ 	}
+ 	result = cm_submit_h_results(hctx, NULL) ?: "";
+@@ -1365,6 +1368,9 @@ restart:
+ 		/* never reached */
+ 		break;
+ 	}
++	if (defaults != nodefault) {
++		free(defaults);
++	}
+ 	return 0;
+ }
+ #endif
+diff --git a/src/submit-x.c b/src/submit-x.c
+index abebc610..58d007ef 100644
+--- a/src/submit-x.c
++++ b/src/submit-x.c
+@@ -45,14 +45,17 @@ get_error_message(krb5_context ctx, krb5_error_code kcode)
+ {
+ 	const char *ret;
+ #ifdef HAVE_KRB5_GET_ERROR_MESSAGE
+-	ret = ctx ? krb5_get_error_message(ctx, kcode) : NULL;
+-	if (ret == NULL) {
+-		ret = error_message(kcode);
++	if (ctx) {
++		const char *msg = krb5_get_error_message(ctx, kcode);
++		ret = strdup(msg);
++		krb5_free_error_message(ctx, msg);
++	} else {
++		ret = strdup(error_message(kcode));
+ 	}
+ #else
+-	ret = error_message(kcode);
++	ret = strdup(error_message(kcode));
+ #endif
+-	return strdup(ret);
++	return ret;
+ }
+ 
+ char *
+@@ -75,8 +78,6 @@ cm_submit_x_ccache_realm(char **msg)
+ 			ret = get_error_message(ctx, kret));
+ 		if (msg != NULL) {
+ 			*msg = ret;
+-		} else {
+-			free(ret);
+ 		}
+ 		return NULL;
+ 	}
+@@ -86,8 +87,6 @@ cm_submit_x_ccache_realm(char **msg)
+ 			ret = get_error_message(ctx, kret));
+ 		if (msg != NULL) {
+ 			*msg = ret;
+-		} else {
+-			free(ret);
+ 		}
+ 		return NULL;
+ 	}
+@@ -97,8 +96,6 @@ cm_submit_x_ccache_realm(char **msg)
+ 			ret = get_error_message(ctx, kret));
+ 		if (msg != NULL) {
+ 			*msg = ret;
+-		} else {
+-			free(ret);
+ 		}
+ 		return NULL;
+ 	}
+@@ -106,7 +103,7 @@ cm_submit_x_ccache_realm(char **msg)
+ 	if (data == NULL) {
+ 		fprintf(stderr, "Error retrieving principal realm.\n");
+ 		if (msg != NULL) {
+-			*msg = "Error retrieving principal realm.\n";
++			*msg = strdup("Error retrieving principal realm.\n");
+ 		}
+ 		return NULL;
+ 	}
+@@ -114,7 +111,7 @@ cm_submit_x_ccache_realm(char **msg)
+ 	if (ret == NULL) {
+ 		fprintf(stderr, "Out of memory for principal realm.\n");
+ 		if (msg != NULL) {
+-			*msg = "Out of memory for principal realm.\n";
++			*msg = strdup("Out of memory for principal realm.\n");
+ 		}
+ 		return NULL;
+ 	}
+@@ -145,8 +142,6 @@ cm_submit_x_make_ccache(const char *ktname, const char *principal, char **msg)
+ 		fprintf(stderr, "Error initializing Kerberos: %s.\n", ret);
+ 		if (msg != NULL) {
+ 			*msg = ret;
+-		} else {
+-			free(ret);
+ 		}
+ 		return kret;
+ 	}
+@@ -160,8 +155,6 @@ cm_submit_x_make_ccache(const char *ktname, const char *principal, char **msg)
+ 			ret = get_error_message(ctx, kret));
+ 		if (msg != NULL) {
+ 			*msg = ret;
+-		} else {
+-			free(ret);
+ 		}
+ 		return kret;
+ 	}
+@@ -173,8 +166,6 @@ cm_submit_x_make_ccache(const char *ktname, const char *principal, char **msg)
+ 				principal, ret = get_error_message(ctx, kret));
+ 			if (msg != NULL) {
+ 				*msg = ret;
+-			} else {
+-				free(ret);
+ 			}
+ 			return kret;
+ 		}
+@@ -186,8 +177,6 @@ cm_submit_x_make_ccache(const char *ktname, const char *principal, char **msg)
+ 				ret = get_error_message(ctx, kret));
+ 			if (msg != NULL) {
+ 				*msg = ret;
+-			} else {
+-				free(ret);
+ 			}
+ 			return kret;
+ 		}
+@@ -209,8 +198,6 @@ cm_submit_x_make_ccache(const char *ktname, const char *principal, char **msg)
+ 			ret = get_error_message(ctx, kret));
+ 		if (msg != NULL) {
+ 			*msg = ret;
+-		} else {
+-			free(ret);
+ 		}
+ 		return kret;
+ 	}
+@@ -229,8 +216,6 @@ cm_submit_x_make_ccache(const char *ktname, const char *principal, char **msg)
+ 			ret = get_error_message(ctx, kret));
+ 		if (msg != NULL) {
+ 			*msg = ret;
+-		} else {
+-			free(ret);
+ 		}
+ 		return kret;
+ 	}
+@@ -245,8 +230,6 @@ cm_submit_x_make_ccache(const char *ktname, const char *principal, char **msg)
+ 			ret = get_error_message(ctx, kret));
+ 		if (msg != NULL) {
+ 			*msg = ret;
+-		} else {
+-			free(ret);
+ 		}
+ 		return kret;
+ 	}
+@@ -257,8 +240,6 @@ cm_submit_x_make_ccache(const char *ktname, const char *principal, char **msg)
+ 			ret = get_error_message(ctx, kret));
+ 		if (msg != NULL) {
+ 			*msg = ret;
+-		} else {
+-			free(ret);
+ 		}
+ 		return kret;
+ 	}
+diff --git a/tests/tools/addcinfo.c b/tests/tools/addcinfo.c
+index 939005c2..e34612a5 100644
+--- a/tests/tools/addcinfo.c
++++ b/tests/tools/addcinfo.c
+@@ -63,7 +63,7 @@ content_info_template[] = {
+ int
+ main(int argc, char **argv)
+ {
+-	unsigned char *buffer = NULL, buf[BUFSIZ];
++	unsigned char *buffer = NULL, *newbuffer = NULL, buf[BUFSIZ];
+ 	int i, n = 0;
+ 	unsigned int j;
+ 	SECItem encoded;
+@@ -73,11 +73,13 @@ main(int argc, char **argv)
+ 	cm_log_set_method(cm_log_stderr);
+ 	cm_log_set_level(3);
+ 	while ((i = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
+-		buffer = realloc(buffer, n + i);
+-		if (buffer == NULL) {
++		newbuffer = realloc(buffer, n + i);
++		if (newbuffer == NULL) {
++			free(buffer);
+ 			cm_log(0, "Out of memory.\n");
+ 			return 1;
+ 		}
++		buffer = newbuffer;
+ 		memcpy(buffer + n, buf, i);
+ 		n += i;
+ 	}
+-- 
+2.14.4
+
diff --git a/SOURCES/0020-clang-Avoid-buffer-overflow.patch b/SOURCES/0020-clang-Avoid-buffer-overflow.patch
new file mode 100644
index 0000000..4f7294d
--- /dev/null
+++ b/SOURCES/0020-clang-Avoid-buffer-overflow.patch
@@ -0,0 +1,29 @@
+From e9f16cf50ab3438a6e9ea50669854c93c8a399f2 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Mon, 8 Oct 2018 13:16:08 -0400
+Subject: [PATCH 20/26] clang: Avoid buffer overflow
+
+This shouldn't be possible because the caller would never allow
+it all to be passed in but quiet static analyzers.
+---
+ src/getcert.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/getcert.c b/src/getcert.c
+index 0d527ab0..bbc45479 100644
+--- a/src/getcert.c
++++ b/src/getcert.c
+@@ -1839,8 +1839,8 @@ set_tracking(const char *argv0, const char *category,
+ 	enum cm_tdbus_type bus = CM_DBUS_DEFAULT_BUS;
+ 	DBusMessage *req, *rep;
+ 	const char *request, *capath;
+-	struct cm_tdbusm_dict param[28];
+-	const struct cm_tdbusm_dict *params[29];
++	struct cm_tdbusm_dict param[30];
++	const struct cm_tdbusm_dict *params[30];
+ 	char *nss_scheme, *dbdir = NULL, *token = NULL, *nickname = NULL;
+ 	char **anchor_dbs = NULL, **anchor_files = NULL;
+ 	char *id = NULL, *new_id = NULL, *new_request;
+-- 
+2.14.4
+
diff --git a/SOURCES/0021-clang-Garbage-value-possible.patch b/SOURCES/0021-clang-Garbage-value-possible.patch
new file mode 100644
index 0000000..8bb7bfd
--- /dev/null
+++ b/SOURCES/0021-clang-Garbage-value-possible.patch
@@ -0,0 +1,43 @@
+From bfe2b956c1a9f83bd3d998924788942716767a65 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Mon, 8 Oct 2018 14:44:05 -0400
+Subject: [PATCH 21/26] clang: Garbage value possible
+
+Need to add guard so that error was only considered if the
+certificate was decodable and an import was attempted.
+---
+ src/certsave-n.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/src/certsave-n.c b/src/certsave-n.c
+index 972a1dfa..30e242c1 100644
+--- a/src/certsave-n.c
++++ b/src/certsave-n.c
+@@ -498,6 +498,7 @@ cm_certsave_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 					}
+ 				}
+ 				/* Import the certificate. */
++				error = SECFailure;
+ 				newcert = CERT_DecodeCertFromPackage((char *)item->data, item->len);
+ 				if (newcert != NULL) {
+ 					error = PK11_ImportCert(sle->slot,
+@@ -506,7 +507,7 @@ cm_certsave_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 						entry->cm_cert_nickname,
+ 						PR_FALSE);
+ 				}
+-				if (error == SECSuccess) {
++				if ((newcert != NULL) && (error == SECSuccess)) {
+ 					cm_log(1, "Imported certificate with "
+ 					       "nickname \"%s\".\n",
+ 					       entry->cm_cert_nickname);
+@@ -581,6 +582,7 @@ cm_certsave_n_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 						CERT_DestroyCertList(certlist);
+ 					}
+ 				} else {
++					ec = PORT_GetError();
+ 					if (ec != 0) {
+ 						es = PR_ErrorToName(ec);
+ 					} else {
+-- 
+2.14.4
+
diff --git a/SOURCES/0022-Uninitialized-variable.patch b/SOURCES/0022-Uninitialized-variable.patch
new file mode 100644
index 0000000..6eb7583
--- /dev/null
+++ b/SOURCES/0022-Uninitialized-variable.patch
@@ -0,0 +1,25 @@
+From a5fef9f676334c6b373f9739a2687dc64ad2c0c0 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Mon, 8 Oct 2018 14:48:43 -0400
+Subject: [PATCH 22/26] Uninitialized variable
+
+---
+ src/csrgen-o.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/csrgen-o.c b/src/csrgen-o.c
+index 55b0a598..7ca7065d 100644
+--- a/src/csrgen-o.c
++++ b/src/csrgen-o.c
+@@ -94,7 +94,7 @@ cm_csrgen_o_main(int fd, struct cm_store_ca *ca, struct cm_store_entry *entry,
+ 	BIGNUM *serialbn;
+ 	char buf[LINE_MAX], *p, *q, *s, *nickname, *pin, *password, *filename;
+ 	unsigned char *extensions, *upassword, *bmp, *name, *up, *uq, md[CM_DIGEST_MAX];
+-	char *spkidec, *mcb64, *nows;
++	char *spkidec = NULL, *mcb64, *nows;
+ 	const char *default_cn = CM_DEFAULT_CERT_SUBJECT_CN, *spkihex = NULL;
+ 	const unsigned char *nametmp;
+ 	struct tm *now;
+-- 
+2.14.4
+
diff --git a/SOURCES/0023-merge-into-clang-more-Memory-leaks.patch b/SOURCES/0023-merge-into-clang-more-Memory-leaks.patch
new file mode 100644
index 0000000..6a47651
--- /dev/null
+++ b/SOURCES/0023-merge-into-clang-more-Memory-leaks.patch
@@ -0,0 +1,39 @@
+From b0766cfdfd8bbac9109a2846c6ac3802e60cb56f Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Mon, 8 Oct 2018 15:43:02 -0400
+Subject: [PATCH 23/26] merge into  clang: more Memory leaks
+
+---
+ src/getcert.c  | 2 +-
+ src/submit-x.c | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/getcert.c b/src/getcert.c
+index bbc45479..4713dd15 100644
+--- a/src/getcert.c
++++ b/src/getcert.c
+@@ -4040,7 +4040,7 @@ thumbprint(const char *s, SECOidTag tag, int bits)
+ 	if (length == 0) {
+ 		goto done;
+ 	}
+-	u = malloc(length);
++	u = malloc(length+1);
+ 	if (u == NULL) {
+ 		free(t);
+ 		goto done;
+diff --git a/src/submit-x.c b/src/submit-x.c
+index 58d007ef..467e67e4 100644
+--- a/src/submit-x.c
++++ b/src/submit-x.c
+@@ -43,7 +43,7 @@
+ static char *
+ get_error_message(krb5_context ctx, krb5_error_code kcode)
+ {
+-	const char *ret;
++	char *ret;
+ #ifdef HAVE_KRB5_GET_ERROR_MESSAGE
+ 	if (ctx) {
+ 		const char *msg = krb5_get_error_message(ctx, kcode);
+-- 
+2.14.4
+
diff --git a/SOURCES/0024-Add-missing-return-type-declaration.patch b/SOURCES/0024-Add-missing-return-type-declaration.patch
new file mode 100644
index 0000000..e0455b5
--- /dev/null
+++ b/SOURCES/0024-Add-missing-return-type-declaration.patch
@@ -0,0 +1,24 @@
+From daaca020810962c568caa49514f5159e1592aaf0 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Mon, 8 Oct 2018 15:44:07 -0400
+Subject: [PATCH 24/26] Add missing return type declaration
+
+---
+ src/tdbush.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/tdbush.c b/src/tdbush.c
+index d1bbe4da..a10a1aff 100644
+--- a/src/tdbush.c
++++ b/src/tdbush.c
+@@ -2129,6 +2129,7 @@ ca_get_serial(DBusConnection *conn, DBusMessage *msg,
+ }
+ 
+ /* org.fedorahosted.certonger.ca.get_config_file_path */
++static DBusHandlerResult
+ ca_get_config_file_path(DBusConnection *conn, DBusMessage *msg,
+ 		struct cm_client_info *ci, struct cm_context *ctx)
+ {
+-- 
+2.14.4
+
diff --git a/SOURCES/0025-Discards-const-qualifier.patch b/SOURCES/0025-Discards-const-qualifier.patch
new file mode 100644
index 0000000..954edae
--- /dev/null
+++ b/SOURCES/0025-Discards-const-qualifier.patch
@@ -0,0 +1,43 @@
+From b12dfc9d43128f05b7e0b9e83c2a6100f808fe94 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Mon, 8 Oct 2018 15:46:50 -0400
+Subject: [PATCH 25/26] Discards const qualifier
+
+---
+ src/dogtag.c | 3 ++-
+ src/scep.c   | 3 ++-
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/src/dogtag.c b/src/dogtag.c
+index 8e3890a5..962a8bf4 100644
+--- a/src/dogtag.c
++++ b/src/dogtag.c
+@@ -117,9 +117,10 @@ main(int argc, const char **argv)
+ 	const char *ssldir = NULL, *cainfo = NULL, *capath = NULL;
+ 	const char *sslcert = NULL, *sslkey = NULL;
+ 	const char *sslpin = NULL, *sslpinfile = NULL;
+-	const char *csr = NULL, *csre = NULL, *serial = NULL, *template = NULL;
++	const char *serial = NULL, *template = NULL;
+ 	const char *uid = NULL, *pwd = NULL, *pwdfile = NULL;
+ 	const char *udn = NULL, *pin = NULL, *pinfile = NULL;
++	char *csr = NULL, *csre = NULL;
+ 	char *poptarg;
+ 	struct {
+ 		char *name;
+diff --git a/src/scep.c b/src/scep.c
+index b0bd214b..b37711cf 100644
+--- a/src/scep.c
++++ b/src/scep.c
+@@ -204,7 +204,8 @@ main(int argc, const char **argv)
+ 	int prefer_non_renewal = 0, can_renewal = 0;
+ 	int response_code = 0, response_code2 = 0;
+ 	enum known_ops op = op_unset;
+-	const char *id = NULL, *cainfo = NULL;
++	const char *id = NULL;
++	char *cainfo = NULL;
+ 	char *poptarg;
+ 	char *message = NULL, *rekey_message = NULL;
+ 	const char *mode = NULL, *content_type = NULL, *content_type2 = NULL;
+-- 
+2.14.4
+
diff --git a/SOURCES/0026-Add-missing-case-for-cm_prefs_aes192.patch b/SOURCES/0026-Add-missing-case-for-cm_prefs_aes192.patch
new file mode 100644
index 0000000..4801a46
--- /dev/null
+++ b/SOURCES/0026-Add-missing-case-for-cm_prefs_aes192.patch
@@ -0,0 +1,28 @@
+From f1a328159d46149513e32950284e5dd33525e8e1 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Mon, 8 Oct 2018 15:57:35 -0400
+Subject: [PATCH 26/26] Add missing case for cm_prefs_aes192
+
+---
+ src/prefs.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/src/prefs.c b/src/prefs.c
+index ab363bbc..20e2ecf8 100644
+--- a/src/prefs.c
++++ b/src/prefs.c
+@@ -102,6 +102,11 @@ cm_prefs_preferred_cipher(void)
+ 			free(cipher);
+ 			return cm_prefs_aes128;
+ 		}
++		if ((strcasecmp(cipher, "aes192") == 0) ||
++		    (strcasecmp(cipher, "aes-192") == 0)) {
++			free(cipher);
++			return cm_prefs_aes192;
++		}
+ 		if ((strcasecmp(cipher, "aes256") == 0) ||
+ 		    (strcasecmp(cipher, "aes-256") == 0)) {
+ 			free(cipher);
+-- 
+2.14.4
+
diff --git a/SPECS/certmonger.spec b/SPECS/certmonger.spec
new file mode 100644
index 0000000..846284d
--- /dev/null
+++ b/SPECS/certmonger.spec
@@ -0,0 +1,1331 @@
+%global systemd 1
+%global	sysvinit 0
+
+%global systemdsysv 0
+
+%global tmpfiles 1
+
+%global sysvinitdir %{_initddir}
+
+Name:		certmonger
+Version:	0.79.6
+Release:	5%{?dist}
+Summary:	Certificate status monitor and PKI enrollment client
+
+Group:		System Environment/Daemons
+License:	GPLv3+
+URL:		http://pagure.io/certmonger/
+Source0:	http://releases.pagure.org/certmonger/certmonger-%{version}.tar.gz
+
+BuildRequires:	autoconf
+BuildRequires:	automake
+BuildRequires:	gettext-devel
+BuildRequires:	gcc
+BuildRequires:	openldap-devel
+BuildRequires:	libidn2-devel
+BuildRequires:	python3-dbus
+BuildRequires:	dbus-devel
+BuildRequires:	nspr-devel
+BuildRequires:	nss-devel
+BuildRequires:	openssl-devel
+BuildRequires:	libuuid-devel
+BuildRequires:	libtalloc-devel, libtevent-devel
+BuildRequires:	libcurl-devel
+BuildRequires:	libxml2-devel, xmlrpc-c-devel
+# Required for 'make check':
+#  for diff and cmp
+BuildRequires:	diffutils
+#  for expect
+BuildRequires:	expect
+#  for certutil and pk12util
+BuildRequires:	nss-tools
+#  for openssl
+BuildRequires:	openssl
+#  for dbus-launch
+BuildRequires:	/usr/bin/dbus-launch
+#  for dos2unix
+BuildRequires:	/usr/bin/dos2unix
+BuildRequires:	/usr/bin/unix2dos
+#  for which
+BuildRequires:	/usr/bin/which
+BuildRequires:	popt-devel
+#  for make check
+BuildRequires:	python3-devel
+
+# we need a running system bus
+Requires:	dbus
+Requires(post):	%{_bindir}/dbus-send
+
+%if %{systemd}
+BuildRequires:	systemd-units
+Requires(post):	systemd-units
+Requires(preun):	systemd-units, dbus, sed
+Requires(postun):	systemd-units
+%endif
+
+%if %{systemdsysv}
+Requires(post):	systemd-sysv
+%global systemdsysvsave \
+# Save the current service runlevel info, in case the user wants \
+# to apply the enabled status manually later, by running \
+#   "systemd-sysv-convert --apply certmonger". \
+%{_bindir}/systemd-sysv-convert --save certmonger >/dev/null 2>&1 ||:
+%else
+%global systemdsysvsave %{nil}
+%endif
+
+%if %{sysvinit}
+Requires(post):	/sbin/chkconfig, /sbin/service
+Requires(preun):	/sbin/chkconfig, /sbin/service, dbus, sed
+%endif
+
+Patch1:	0001-NSS-crypto-policy-sets-minimum-RSA-and-DSA-key-size-.patch
+Patch2:	0002-Convert-tests-to-use-python3.patch
+Patch3:	0003-Use-the-correct-slot-when-saving-certificates-in-NSS.patch
+Patch4:	0004-Include-the-token-name-when-a-PIN-is-provided-but-is.patch
+Patch5:	0005-Add-utility-function-to-get-the-internal-token-name.patch
+Patch6:	0006-Only-de-duplicate-certificates-within-the-same-token.patch
+Patch7:	0007-Ensure-that-an-OpenSSL-random-seed-file-exists-when-.patch
+Patch8:	0008-Log-test-failures-of-bad-pin.patch
+Patch9:	0009-Use-only-PK11_ImportCert-to-import-certs-not-CERT_Im.patch
+Patch10:	0010-Fix-memory-leak-in-util_internal_token_name.patch
+Patch11:	0011-clang-Dead-assignment.patch
+Patch12:	0012-clang-Memory-leak.patch
+Patch13:	0013-clang-Uninitialized-initial-value.patch
+Patch14:	0014-clang-Null-pointer-passed-as-an-argument-to-a-nonnul.patch
+Patch15:	0015-clang-Dead-increment.patch
+Patch16:	0016-clang-Dereference-of-null-pointer.patch
+Patch17:	0017-Add-missing-case-for-cm_prefs_aes192.patch
+Patch18:	0018-clang-more-Dead-assignment.patch
+Patch19:	0019-clang-more-Memory-leaks.patch
+Patch20:	0020-clang-Avoid-buffer-overflow.patch
+Patch21:	0021-clang-Garbage-value-possible.patch
+Patch22:	0022-Uninitialized-variable.patch
+Patch23:	0023-merge-into-clang-more-Memory-leaks.patch
+Patch24:	0024-Add-missing-return-type-declaration.patch
+Patch25:	0025-Discards-const-qualifier.patch
+Patch26:	0026-Add-missing-case-for-cm_prefs_aes192.patch
+
+%description
+Certmonger is a service which is primarily concerned with getting your
+system enrolled with a certificate authority (CA) and keeping it enrolled.
+
+%prep
+%setup -q
+%patch1 -p1
+%patch2 -p1
+%patch3 -p1
+%patch4 -p1
+%patch5 -p1
+%patch6 -p1
+%patch7 -p1
+%patch8 -p1
+%patch9 -p1
+%patch10 -p1
+%patch11 -p1
+%patch12 -p1
+%patch13 -p1
+%patch14 -p1
+%patch15 -p1
+%patch16 -p1
+%patch17 -p1
+%patch18 -p1
+%patch19 -p1
+%patch20 -p1
+%patch21 -p1
+%patch22 -p1
+%patch23 -p1
+%patch24 -p1
+%patch25 -p1
+%patch26 -p1
+
+%build
+autoreconf -i -f
+%configure \
+%if %{systemd}
+	--enable-systemd \
+%endif
+%if %{sysvinit}
+	--enable-sysvinit=%{sysvinitdir} \
+%endif
+%if %{tmpfiles}
+	--enable-tmpfiles \
+%endif
+	--with-homedir=/var/run/certmonger \
+	--with-tmpdir=/var/run/certmonger --enable-pie --enable-now
+# For some reason, some versions of xmlrpc-c-config in Fedora and RHEL just
+# tell us about libxmlrpc_client, but we need more.  Work around.
+make %{?_smp_mflags} XMLRPC_LIBS="-lxmlrpc_client -lxmlrpc_util -lxmlrpc"
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make install DESTDIR=$RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT/%{_localstatedir}/lib/certmonger/{cas,requests}
+install -m755 -d $RPM_BUILD_ROOT/var/run/certmonger
+%{find_lang} %{name}
+
+%check
+# Seed then openssl RNG if not set
+if [ ! -e $HOME/.rnd ] ; then
+	openssl rand -writerand $HOME/.rnd
+fi
+make check
+
+%post
+if test $1 -eq 1 ; then
+	%{_bindir}/dbus-send --system --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig 2>&1 || :
+fi
+%if %{systemd}
+if test $1 -eq 1 ; then
+	/bin/systemctl daemon-reload >/dev/null 2>&1 || :
+fi
+%endif
+%if %{sysvinit}
+/sbin/chkconfig --add certmonger
+%endif
+
+%triggerin -- certmonger < 0.58
+if test $1 -gt 1 ; then
+	# If the daemon is running, remove knowledge of the dogtag renewer.
+	objpath=`dbus-send --system --reply-timeout=10000 --dest=org.fedorahosted.certmonger --print-reply=o /org/fedorahosted/certmonger org.fedorahosted.certmonger.find_ca_by_nickname string:dogtag-ipa-renew-agent 2> /dev/null | sed -r 's,^ +,,g' || true`
+	if test -n "$objpath" ; then
+		dbus-send --system --dest=org.fedorahosted.certmonger --print-reply /org/fedorahosted/certmonger org.fedorahosted.certmonger.remove_known_ca objpath:"$objpath" >/dev/null 2> /dev/null
+	fi
+	# Remove the data file, in case it isn't running.
+	for cafile in %{_localstatedir}/lib/certmonger/cas/* ; do
+		if grep -q '^id=dogtag-ipa-renew-agent$' "$cafile" ; then
+			rm -f "$cafile"
+		fi
+	done
+fi
+exit 0
+
+%postun
+%if %{systemd}
+/bin/systemctl daemon-reload >/dev/null 2>&1 || :
+if [ $1 -ge 1 ] ; then
+	/bin/systemctl try-restart certmonger.service >/dev/null 2>&1 || :
+fi
+%endif
+%if %{sysvinit}
+if test $1 -gt 0 ; then
+	/sbin/service certmonger condrestart 2>&1 > /dev/null
+fi
+%endif
+exit 0
+
+%preun
+%if %{systemd}
+if test $1 -eq 0 ; then
+	/bin/systemctl --no-reload disable certmonger.service > /dev/null 2>&1 || :
+	/bin/systemctl stop certmonger.service > /dev/null 2>&1 || :
+fi
+%endif
+%if %{sysvinit}
+if test $1 -eq 0 ; then
+	/sbin/service certmonger stop 2>&1 > /dev/null
+	/sbin/chkconfig --del certmonger
+fi
+%endif
+exit 0
+
+%if %{systemd}
+%triggerun -- certmonger < 0.43
+%{systemdsysvsave}
+# Do this because the old package's %%postun doesn't know we need to do it.
+/sbin/chkconfig --del certmonger >/dev/null 2>&1 || :
+# Do this because the old package's %%postun wouldn't have tried.
+/bin/systemctl try-restart certmonger.service >/dev/null 2>&1 || :
+exit 0
+%endif
+
+%files -f %{name}.lang
+%defattr(-,root,root,-)
+%doc README.md LICENSE STATUS doc/*.txt
+%config(noreplace) %{_sysconfdir}/dbus-1/system.d/*
+%{_datadir}/dbus-1/services/*
+%dir %{_sysconfdir}/certmonger
+%config(noreplace) %{_sysconfdir}/certmonger/certmonger.conf
+%dir /var/run/certmonger
+%{_bindir}/*
+%{_sbindir}/certmonger
+%{_mandir}/man*/*
+%{_libexecdir}/%{name}
+%{_localstatedir}/lib/certmonger
+%if %{sysvinit}
+%{sysvinitdir}/certmonger
+%endif
+%if %{tmpfiles}
+%attr(0644,root,root) %config(noreplace) %{_tmpfilesdir}/certmonger.conf
+%endif
+%if %{systemd}
+%{_unitdir}/*
+%{_datadir}/dbus-1/system-services/*
+%endif
+
+%changelog
+* Mon Oct  8 2018 Rob Crittenden <rcritten@redhat.com> - 0.79.6-5
+- Address more issues uncovered by static analysis (#1632449)
+
+* Tue Oct  2 2018 Rob Crittenden <rcritten@redhat.com> - 0.79.6-4
+- Improve handling of NSS tokens (#1624930)
+- Pull in upstream fixes discovered in coverity and clang (#1632449)
+
+* Mon Aug 13 2018 Rob Crittenden <rcritten@redhat.com> - 0.79.6-3
+- Add BuildRequires on python3-devel (#1615507)
+
+* Thu Aug  2 2018 Rob Crittenden <rcritten@redhat.com> - 0.79.6-2
+- Fix test failure on some platforms
+
+* Wed Aug  1 2018 Rob Crittenden <rcritten@redhat.com> - 0.79.6-1
+- Update to upstream 0.79.6
+- Fix unit tests to work with python 3
+
+* Fri Feb 23 2018 Rob Crittenden <rcritten@redhat.com> 0.79.5-6
+- Fix unit tests. NSS crypto policy disallows keys < 1024
+
+* Wed Feb 21 2018 Rob Crittenden <rcritten@redhat.com> 0.79.5-5
+- Add BuildRequires on gcc
+
+* Wed Feb 07 2018 Fedora Release Engineering <releng@fedoraproject.org> - 0.79.5-4
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
+
+* Wed Jan 10 2018 Rob Crittenden <rcritten@redhat.com> 0.79.5-3
+- Remove BR on mktemp. It is now provided by coreutils.
+- Patch to fix NSS handling of keys in sqlite databases
+- Patches to fix tests now that sqlite is the NSS default.
+
+* Wed Oct  4 2017 Rob Crittenden <rcritten@redhat.com> 0.79.5-2
+- Switch BR from /usr/include/popt.h to popt-devel
+
+* Fri Sep  1 2017 Rob Crittenden <rcritten@redhat.com> 0.79.5-1
+- update to 0.79.5:
+   - getcert start-tracking: use issuer option when specified
+   - add support for specifying the MS certificate template
+   - Reformat certificates returned by Dogtag to strip extra newline
+
+* Wed Aug 16 2017 Rob Crittenden <rcritten@redhat.com> 0.79.4-2
+- Reformat certificates returned by Dogtag. Dogtag was including
+  a spurious newline before -----END CERTIFICATE-----
+
+* Mon Aug  7 2017 Rob Crittenden <rcritten@redhat.com> 0.79.4-1
+- update to 0.79.4
+  - fix CA option name for ipa cert-request
+  - fix minor memory leak
+  - fix build warnings
+  - fix an incorrect date in the .spec changelog
+  - bump gettext version to avoid warning
+
+* Wed Aug 02 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.79.3-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild
+
+* Wed Jul 26 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.79.3-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
+
+* Tue Feb 28 2017 Nalin Dahyabhai <nalin@redhat.com> 0.79.3-1
+- update to 0.79.3:
+  - fix self-signing self-test cases that used DSA or EC keys
+
+* Mon Feb 27 2017 Nalin Dahyabhai <nalin@redhat.com> 0.79.2-2
+- update %%docs list because README is now README.md
+
+* Mon Feb 27 2017 Nalin Dahyabhai <nalin@redhat.com> 0.79.2-1
+- update to 0.79.2:
+  - fix 'make distcheck' target
+
+* Sun Feb 19 2017 Nalin Dahyabhai <nalin@redhat.com> 0.79.1-1
+- update to 0.79.1:
+  - update translations
+  - fix 'make archive' target
+
+* Sun Feb 19 2017 Nalin Dahyabhai <nalin@redhat.com> 0.79-1
+- update to 0.79:
+  - getcert now offers an option (-X) for requesting processing by a particular
+    CA if the server we're contacting is running more than one
+  - getcert also offers options (--for-ca, --not-for-ca, --ca-path-length) for
+    requesting BasicConstraints values
+  - getcert now displays times in local time instead of UTC, which was
+    previously the only way they were displayed; the --utc option can often be
+    used to switch back to its previous behavior
+  - the SCEP enrollment helper now correctly issues GetCACertChain requests to
+    SCEP servers, instead of issuing a GetCAChain request, which isn't part of
+    the protocol; from report by Jason Garland
+  - when issuing SCEP requests, the ID of the CA included in the HTTP request
+    is now URL-encoded, as it should be
+  - renewal or notification-of-impending-expiration logic is now triggered
+    closer to TTL thresholds rather than waiting for a periodic check to pass a
+    threshold
+  - properly builds with OpenSSL 1.1, thanks to Lukas Slebodnik and Tomas Mraz
+    for a lot of the legwork
+- resync .spec file with Fedora
+- upstream project migrated from fedorahosted.org to pagure.io
+
+* Fri Feb 10 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.78.6-6
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
+
+* Sat Jan 21 2017 Igor Gnatenko <ignatenko@redhat.com> - 0.78.6-5
+- Rebuild for xmlrpc-c
+
+* Wed Jul  6 2016 Nalin Dahyabhai <nalin@redhat.com> 0.78.6-4
+- add backported fix to wait a reasonable amount of time after calling the
+  'resubmit' method for a new certificate to be issued when we're exercising
+  the D-Bus API during tests (Jan Cholasta, #1351052)
+
+* Wed Jul  6 2016 Nalin Dahyabhai <nalin@redhat.com> 0.78.6-3
+- instead of using killall to send a SIGHUP to the system bus daemon in %%post
+  to get it to reload its configuration, use dbus-send to send a ReloadConfig
+  request over the bus (should fix #1277573)
+
+* Wed Feb 03 2016 Fedora Release Engineering <releng@fedoraproject.org> - 0.78.6-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
+
+* Wed Jan 13 2016 Nalin Dahyabhai <nalin@redhat.com> 0.78.6-1
+- document the -R, -N, -o, and -t flags for dogtag-ipa-renew-agent-submit
+- stop checking that we can generate 512 bit keys during self-tests
+
+* Thu Nov 12 2015 Nalin Dahyabhai <nalin@redhat.com> 0.78.5-1
+- fix a possible uninitialized memory read (possibly #1260871)
+- log a diagnostic error when we fail to initialize libkrb5
+
+* Tue Aug  4 2015 Nalin Dahyabhai <nalin@redhat.com> 0.78.4-1
+- fix the "getcert start-tracking" -L and -l options (#1249753)
+- output diagnostics about the second request when scep-submit encounters an
+  error during a second request to the SCEP server
+
+* Mon Jul 20 2015 Nalin Dahyabhai <nalin@redhat.com> 0.78.3-1
+- call poptGetOptArg() correctly, to fix parsing of the -R flag to scep-submit
+  and the -O and -o flags to dogtag-submit (#1244914)
+
+* Thu Jul  9 2015 Nalin Dahyabhai <nalin@redhat.com> 0.78.2-1
+- tweak initialization so that we set up for providing our D-Bus API before we
+  register our name with the bus, so that we can handle any requests that
+  arrive before the acknowledgement of that registration
+- on systems that run systemd, add the right data file so that the service gets
+  started when someone tries to talk to the daemon (ticket #38)
+- correctly check for error responses when sending GetCAChain requests to SCEP
+  servers
+
+* Sun Jun 21 2015 Nalin Dahyabhai <nalin@redhat.com> 0.78.1-1
+- self-tests: assume that certutil won't generate DSA keys with more than 1024
+  bits, and will often short us by a few
+
+* Sat Jun 20 2015 Nalin Dahyabhai <nalin@redhat.com> 0.78-1
+- switch to using popt for parsing command line arguments, continuing to
+  use old help text for now so that we can catch up with translations (print
+  old text for --help, new text (with longopts!) for -H)
+- add some plumbing for eventually receiving per-certificate roots in
+  addition to issued certificates and chain certificates
+- add a "rekey" command to getcert, for triggering enrollment using a new
+  key pair (#1087932)
+- scep-submit: check for the Renewal capability, and default to taking
+  advantage of it during rekeying, unless the new -n flag is specified to it
+- dogtag-submit: add flags for passing user names, UDNs, passwords, and PINs
+  to the helper (part of ticket #12)
+- dogtag-submit: add a flag for using the agent creds to do TLS client auth
+  while submitting enrollment requests (more of ticket #12)
+- dogtag-submit: handle cases where we submit a request and the server
+  returns a success code rather than just queuing the request (#12 again)
+- ipa-submit: pass requested profile names to the server as an argument
+  named "profile_id"; if the server gives us an "unrecognized argument"
+  error, retry without it for compatibility's sake (part of IPA ticket #57)
+- keygen: fix a possible crash if keygen fails to return a key from NSS
+- correct the certmonger(8) man page's description of the -c flag, which it
+  used to call the -C flag
+- add logic for setting ownership and permissions on certificates and keys
+  when saving them to disk
+- add configuration options "max_key_lifetime" and "max_key_use_count" for
+  making automatic renewal prefer rekeying
+
+* Wed Jun 17 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.77.5-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
+
+* Thu May 28 2015 Nalin Dahyabhai <nalin@redhat.com> 0.77.5-1
+- pass $CERTMONGER_REQ_IP_ADDRESS to enrollment helpers if the signing request
+  includes IP address subjectAltName values
+- correctly verify signatures on SCEP server replies when the signer is neither
+  the top-level CA nor the RA (feedback in #1161768)
+- correctly verify signatures on SCEP server replies when there is more than
+  one certificate in the chain between the RA and the top-level CA (feedback in
+  #1161768)
+
+* Fri May 15 2015 Nalin Dahyabhai <nalin@redhat.com> 0.77.4-1
+- don't display PINs in "getcert list" output (#42)
+- clean up launching of a private instance in "getcert"
+- expand on the don't-delete-private-key fix from 0.77.3 by letting NSS's
+  own safety checks have an effect
+- backport record-keeping of key generation dates and counts of how many
+  times we've gotten certificates using a given key pair
+
+* Thu May  7 2015 Nalin Dahyabhai <nalin@redhat.com> 0.77.3-1
+- fix a data loss bug when saving renewed certificates to NSS databases - the
+  private key could be removed in error since 0.77
+- fixes for bugs found by static analysis
+- fix self-tests when built with OpenSSL 1.0.2
+
+* Tue Apr 14 2015 Nalin Dahyabhai <nalin@redhat.com> 0.77.2-1
+- expose the certificate's not-valid-before and not-valid-after dates as a
+  property over D-Bus (ticket #41)
+- give the local signer its own configuration option to set the lifetime
+  of its signing certificate, falling back to the lifetime configured for
+  the self-signer as a default to match the previous behavior
+- fix a potential read segfault parsing the output of an enrollment helper,
+  introduced in 0.77 (thanks to Steve Neuharth)
+- read the ns-certtype extension value in certificates
+- request an enrollment certtype extension to CSRs if we have a profile name
+  that we want to use (ticket #17, possibly part of IPA ticket #57)
+
+* Fri Feb 27 2015 Nalin Dahyabhai <nalin@redhat.com> 0.77.1-1
+- update to 0.77
+  - add initial, still rough, SCEP support (#1140241,#1161768)
+    - add an scep-submit helper to handle part of it
+  - getcert: add add-ca/add-scep-ca/modify-ca/remove-ca commands
+  - getcert: add -l, -L flags to request/resubmit/start-tracking commands
+    to provide a way to set a ChallengePassword in signing requests
+  - lay some groundwork for rekeying support
+  - bundled dogtag enrollment helpers now output debugging info to stderr (#)
+  - ipa-getcert: fix a crash when using DNS discovery to locate servers (#39)
+  - getcert: fix displaying of pre-request pre-/post-save commands (#1178190,
+    #1181022, patch by David Kupka)
+  - use Zanata for translations
+  - getcert list: list the certificate's profile name, if it contains one
+
+* Tue Nov 18 2014 Nalin Dahyabhai <nalin@redhat.com> 0.76.8-1
+- dogtag-submit: accept additional options to pass to the server when
+  approving requests using agent creds (#1165155, patch by Jan Cholasta)
+- getcert: print help output when 'status' isn't given any args (#1163541)
+
+* Tue Nov 11 2014 Nalin Dahyabhai <nalin@redhat.com> 0.76.7-1
+- correctly read CA not-valid-after dates on 32-bit machines (also reported by
+  Natxo Asenjo), so that we don't spin on polling them (#1163023)
+
+* Mon Nov 10 2014 Nalin Dahyabhai <nalin@redhat.com> 0.76.6-1
+- don't discard the priority value in DNS SRV records
+
+* Mon Nov 10 2014 Nalin Dahyabhai <nalin@redhat.com> 0.76.5-1
+- avoid premature exit on CA data analysis failures (should fix an issue
+  reported by Natxo Asenjo)
+
+* Mon Nov 10 2014 Nalin Dahyabhai <nalin@redhat.com> 0.76.4-1
+- fix a failure in self-tests
+
+* Mon Nov 10 2014 Nalin Dahyabhai <nalin@redhat.com> 0.76.3-1
+- fixes for bugs found by static analysis
+- handle IDN correctly when doing service location using SRV records
+- documentation updates
+
+* Wed Nov  5 2014 Nalin Dahyabhai <nalin@redhat.com>
+- rework the state machine so that we save an issued certificate's associated
+  CA certificates, then re-read the certificate, then run the post hook and
+  issue notifications, in that order, instead of saving CA certificates after
+  running the post hook, which was always a surprising order (#1131700)
+- add a generic dogtag-submit helper that doesn't include any IPA defaults,
+  to make it easier to know the difference between paramenters it requires
+  and parameters which are optional (#12)
+
+* Tue Nov  4 2014 Nalin Dahyabhai <nalin@redhat.com> 0.76.2-1
+- ipa-submit: when we fail to locate/contact LDAP or XML-RPC servers,
+  use discovery to find them (#1136900)
+
+* Fri Oct 31 2014 Nalin Dahyabhai <nalin@redhat.com> 0.76.1-1
+- allow for 'certmonger -P abstract:...' to work, too
+
+* Fri Oct 31 2014 Nalin Dahyabhai <nalin@redhat.com> 0.76-1
+- require a single certificate to be specified to 'getcert status' (#1148001,
+  #1163541, #1163539)
+- shorten the default help message which getcert prints when it's not given
+  a specific command (#1131704)
+- add private listener (-l, -L, -P) mode to certmonger, to allow it to listen
+  for connections directly from clients running under the same UID
+- add a command mode (-c) to certmonger, in which once it's started, it
+  launches a specified command, and after that command exits, the daemon exits
+- when getcert is invoked with no bus running, if it's running as root, run
+  certmonger in private listener mode with the same invocation of getcert as
+  the command to start and wait for (#1134497)
+
+* Thu Aug 28 2014 Nalin Dahyabhai <nalin@redhat.com> 0.75.14-1
+- make pathname canonicalization slightly smarter, to handle ".." in
+  locations (#1131758)
+- updates to self-tests (#1144082)
+
+* Thu Aug 21 2014 Kevin Fenzi <kevin@scrye.com> - 0.75.13-2
+- Rebuild for rpm bug 1131960
+
+* Mon Aug 18 2014 Nalin Dahyabhai <nalin@redhat.com> 0.75.13-1
+- add a missing test case file (whoops)
+
+* Mon Aug 18 2014 Nalin Dahyabhai <nalin@redhat.com> 0.75.12-1
+- correct encoding/decoding of variant-typed data which we receive and send
+  as part of the org.freedesktop.DBus.Properties interface over the bus, and
+  add some tests for them (based on patch from David Kupka, ticket #36)
+
+* Fri Aug 15 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.75.10-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild
+
+* Tue Aug 12 2014 Nalin Dahyabhai <nalin@redhat.com> 0.75.11-1
+- when getcert is passed a -a flag, to indicate that CA root certificates
+  should be stored in the specified database, don't ignore locations which
+  don't include a storage scheme (#1129537)
+- when called to 'start-tracking' with the -a or -F flags, if we have
+  applicable certificates on-hand for a CA that we're either told to use
+  or which we decide is the correct one, save the certificates (#1129696)
+
+* Tue Aug  5 2014 Nalin Dahyabhai <nalin@redhat.com> 0.75.10-1
+- when attempting to contact an IPA LDAP server, if no "ldap_uri" is set in
+  default.conf, and no "host" is set either, try to construct the server URI
+  using the "server" setting (#1126985)
+
+* Thu Jul 31 2014 Nalin Dahyabhai <nalin@redhat.com> 0.75.9-1
+- avoid potential use-after-free after a CA is removed dynamically (thanks to
+  Keenan Brock) (#1125342)
+- add a "external-helper" property to CA objects
+
+* Mon Jul 21 2014 Nalin Dahyabhai <nalin@redhat.com> 0.75.8-1
+- add a 'refresh' option to the getcert command
+- add a '-a' flag to the getcert command's 'refresh-ca' option
+
+* Thu Jul 17 2014 Nalin Dahyabhai <nalin@redhat.com> 0.75.7-2
+- reintroduce package Requires: on systemd-sysv on F19 and EL6 and older,
+  conditionalized it so that it's ignored on newer releases, and make
+  whether or not we call systemd-sysv-convert in triggers depend on that,
+  too (#1104138)
+
+* Thu Jul 17 2014 Nalin Dahyabhai <nalin@redhat.com> 0.75.7-1
+- fix an inconsistency in how we parse cookie values returned by CA helpers,
+  in that single-line values would lose the end-of-line after a daemon
+  restart, but not before
+- handle timeout values and exit status values when calling CA helpers
+  in non-SUBMIT, non-POLL modes (#1118468)
+- rework how we save CA certificates so that we save CA certificates associated
+  with end-entity certificates when we save that end-entity certificate, which
+  requires running all of the involved pre- and post-save commands
+- drop package Requires: on systemd-sysv (#1104138)
+
+* Thu Jun 26 2014 Nalin Dahyabhai <nalin@redhat.com> 0.75.6-1
+- avoid potential use-after-free and read overrun after a CA is added
+  dynamically (thanks to Jan Cholasta)
+
+* Fri Jun 20 2014 Nalin Dahyabhai <nalin@redhat.com> 0.75.5-1
+- documentation updates
+
+* Fri Jun 20 2014 Nalin Dahyabhai <nalin@redhat.com> 0.75.4-2
+- add a %%trigger to remove knowledge of the "dogtag-ipa-renew-agent" CA
+  when we detect certmonger versions prior to 0.58 being installed, to
+  avoid cases where some older versions choke on CAs with nicknames that
+  contain characters that can't legally be part of a D-Bus name (#948993)
+
+* Thu Jun 19 2014 Nalin Dahyabhai <nalin@redhat.com> 0.75.4-1
+- fix creation and packaging of the "local" CA's data directory
+
+* Wed Jun 18 2014 Nalin Dahyabhai <nalin@redhat.com> 0.75.3-1
+- read and cache whether or not we saw a noOCSPcheck extension in certificates
+- documentation updates
+
+* Mon Jun 16 2014 Nalin Dahyabhai <nalin@redhat.com> 0.75.2-1
+- when generating keys using OpenSSL, if key generation fails, try
+  again with the default key size, in case we're in FIPS mode
+- documentation updates
+
+* Sat Jun 14 2014 Nalin Dahyabhai <nalin@redhat.com> 0.75.1-1
+- log the state in 'getcert status' verbose mode
+
+* Fri Jun 13 2014 Nalin Dahyabhai <nalin@redhat.com> 0.75-1
+- add a -w (wait) flag to the getcert's request/resubmit/start-tracking
+  commands, and add a non-waiting status command
+
+* Wed Jun 11 2014 Nalin Dahyabhai <nalin@redhat.com> 0.74.96-1
+- make the trust settings we apply to CA-supplied certificates while
+  saving them to NSS databases run-time configurable
+- fix compiling against EL5-era OpenSSL
+- when saving CA certificates we pull from an IPA server, nickname
+  it using the realm name with " IPA CA" appended rather than just
+  naming it "IPA CA"
+- fix the local signer so that when it issues itself a new certificate,
+  it uses the same subject name
+- add a -w flag to getcert's request, resubmit, and start-tracking
+  commands, telling it to wait until either the certificate is issued,
+  we get to a state where we know that we won't be able to get one, or
+  we are waiting for a CA
+
+* Mon Jun  9 2014 Nalin Dahyabhai <nalin@redhat.com> 0.74.95-1
+- add the "local" signer, a local toy CA that signs anything you'll
+  ask it to sign
+
+* Sat Jun 07 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.74-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
+
+* Fri Jun  6 2014 Nalin Dahyabhai <nalin@redhat.com> 0.74.94-1
+- fix self-test errors that we trigger with new OpenSSL
+- fix a build error that would sometimes happen when we're told to
+  build PIE binaries
+- quiet a compile warning
+
+* Thu Jun  5 2014 Nalin Dahyabhai <nalin@redhat.com> 0.74.93-1
+- add some self-tests
+- simplify the internal submit-to-CA logic
+- fixes for more problems found through static analysis
+
+* Tue Jun  3 2014 Nalin Dahyabhai <nalin@redhat.com> 0.74.92-1
+- retrieve CA information from CAs, if the helpers can do so, and
+  add a command to explicitly refresh that data: "getcert refresh-ca"
+- offer to save CA certificates to files and databases, when specified with
+  new -a and -F flags to getcert request/resubmit/start-tracking (#1098208,
+  trac #31)
+- add IP address subject alternate names when getcert request/resubmit
+  is passed the -A option (trac #35)
+- read and cache the freshestCRL extension in certificates
+- properly interpret KDC-unreachable errors encountered in the IPA
+  submission error as a server-unreachable error that we will retry,
+  rather than a misconfiguration error which we won't
+- don't let tests get tripped up by new formatting used in dos2unix status
+  messages (#1099080)
+- updated translations
+- be explicit that we are going to use bashisms in test scripts by calling
+  the shell interpreter as 'bash' rather than 'sh' (trac #27)
+
+* Thu Apr  3 2014 Nalin Dahyabhai <nalin@redhat.com> 0.74-1
+- also save state when we exit due to SIGHUP
+- don't get tripped up when enrollment helpers hand us certificates which
+  include CRLF line terminators (ticket #25)
+- be tolerant of certificate issuer names, subject names, DNS, email, and
+  Kerberos principal namem subjectAltNames, and crl distribution point URLs
+  that contain newlines
+- read and cache the certificate template extension in certificates
+- enforce different minimum key sizes depending on the type of key we're
+  trying to generate
+- store DER versions of subject, issuer and template subject, if we have
+  them (Jan Cholasta, ticket #26)
+- when generating signing requests with subject names that don't quite parse
+  as subject names, encode what we're given as PrintableString rather than
+  as a UTF8String
+- always chdir() to a known location at startup, even if we're not becoming
+  a daemon
+- fix a couple of memory leaks (static analysis)
+- add missing buildrequires: on which
+
+* Thu Feb 20 2014 Nalin Dahyabhai <nalin@redhat.com> 0.73-1
+- updates to 0.73
+  - getcert no longer claims to be stuck when a CA is unreachable,
+    because the daemon isn't actually stuck
+
+* Mon Feb 17 2014 Nalin Dahyabhai <nalin@redhat.com>
+- updates to 0.73
+  - also pass the key type to enrollment helpers in the environment as
+    a the value of "CERTMONGER_KEY_TYPE"
+
+* Mon Feb 10 2014 Nalin Dahyabhai <nalin@redhat.com>
+- move the tmpfiles.d file from /etc/tmpfiles.d to %%{_tmpfilesdir},
+  where it belongs (#1180978)
+
+* Mon Feb 10 2014 Nalin Dahyabhai <nalin@redhat.com>
+- updates for 0.73
+  - set the flag to encode EC public key parameters using named curves
+    instead of the default of all-the-details when using OpenSSL
+  - don't break when NSS supports secp521r1 but OpenSSL doesn't
+  - also pass the CA nickname to enrollment helpers in the environment as
+    a text value in "CERTMONGER_CA_NICKNAME", so they can use that value
+    when reading configuration settings
+  - also pass the SPKAC value to enrollment helpers in the environment as
+    a base64 value in "CERTMONGER_SPKAC"
+  - also pass the request's SubjectPublicKeyInfo value to enrollment helpers
+    in the environment as a base64 value in "CERTMONGER_SPKI" (part of #16)
+  - when generating signing requests using NSS, be more accommodating of
+    requested subject names that don't parse properly
+
+* Mon Feb  3 2014 Nalin Dahyabhai <nalin@redhat.com> 0.72-1
+- update to 0.72
+  - support generating DSA parameters and keys on sufficiently-new OpenSSL
+    and NSS
+  - support generating EC keys when OpenSSL and NSS support it, using key
+    size to select the curve to use from among secp256r1, secp384r1,
+    secp521r1 (which are the ones that are usually available, though
+    secp521r1 isn't always, even if the other two are)
+  - stop trying to cache public key parameters at all and instead cache public
+    key info properly
+  - encode the friendlyName attribute in signing requests as a BMPString,
+    not as a PrintableString
+  - catch more filesystem permissions problems earlier (more of #996581)
+
+* Mon Jan 27 2014 Nalin Dahyabhai <nalin@redhat.com> 0.71-1
+- check for cases where we fail to allocate memory while reading a request
+  or CA entry from disk (John Haxby)
+- only handle one watch at a time, which should avoid abort() during
+  attempts to reconnect to the message bus after losing our connection
+  to it (#1055521)
+
+* Fri Jan 24 2014 Daniel Mach <dmach@redhat.com> - 0.70-2
+- Mass rebuild 2014-01-24
+
+* Thu Jan  2 2014 Nalin Dahyabhai <nalin@redhat.com> 0.70-1
+- add a --with-homedir option to configure, and use it, since subprocesses
+  which we run and which use NSS may attempt to write to $HOME/.pki, and
+  0.69's strategy of setting that to "/" was rightly hitting SELinux policy
+  denials (#1047798)
+
+* Fri Dec 27 2013 Daniel Mach <dmach@redhat.com> - 0.69-2
+- Mass rebuild 2013-12-27
+
+* Mon Dec  9 2013 Nalin Dahyabhai <nalin@redhat.com> 0.69-1
+- tweak how we decide whether we're on the master or a minion when we're
+  told to use certmaster as a CA
+- clean up one of the tests so that it doesn't have to work around internal
+  logging producing duplicate messages
+- when logging errors while setting up to contact xmlrpc servers, explicitly
+  note that the error is client-side
+- don't abort() due to incorrect locking when an attempt to save an issued
+  certificate to the designated location fails (part of #1032760/#1033333,
+  ticket #22)
+- when reading an issued certificate from an enrollment helper, ignore
+  noise before or after the certificate itself (more of #1032760/1033333,
+  ticket #22)
+- run subprocesses in a cleaned-up environment (more of #1032760/1033333,
+  ticket #22)
+- clear the ca-error that we saved when we had an error talking to the CA if we
+  subsequently succeed in talking to the CA
+- various other static-analysis fixes
+
+* Thu Aug 29 2013 Nalin Dahyabhai <nalin@redhat.com> 0.68-1
+- notice when the OpenSSL RNG isn't seeded
+- notice when saving certificates or keys fails due to filesystem-related
+  permission denial (#996581)
+
+* Tue Aug  6 2013 Nalin Dahyabhai <nalin@redhat.com> 0.67-3
+- pull up a patch from master to adapt self-tests to certutil's diagnostic
+  output having changed (#992050)
+
+* Sat Aug 03 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.67-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild
+
+* Mon Mar 11 2013 Nalin Dahyabhai <nalin@redhat.com> 0.67-1
+- when saving certificates to NSS databases, try to preserve the trust
+  value assigned to a previously-present certificate with the same nickname
+  and subject, if one is found
+- when saving certificates to NSS databases, also prune certificates from
+  the database which have both the same nickname and subject as the one
+  we're adding, to avoid tripping up tools that only fetch one certificate
+  by nickname
+
+* Wed Feb 13 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.65-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild
+
+* Wed Jan 23 2013 Nalin Dahyabhai <nalin@redhat.com> 0.66-1
+- build as position-independent executables with early binding (#883966)
+- also don't tag the unit file as a configuration file (internal tooling)
+
+* Wed Jan 23 2013 Nalin Dahyabhai <nalin@redhat.com> 0.65-2
+- don't tag the D-Bus session .service file as a configuration file (internal
+  tooling)
+
+* Tue Jan  8 2013 Nalin Dahyabhai <nalin@redhat.com> 0.65-1
+- fix a crash in the self-tests
+
+* Tue Jan  8 2013 Nalin Dahyabhai <nalin@redhat.com> 0.64-1
+- at startup, if we resume the state machine for a given certificate to a state
+  which expects to have the newly-added lock already acquired, acquire it
+  before moving on with the certificate's work (still aimed at fixing #883484)
+
+* Tue Dec 18 2012 Nalin Dahyabhai <nalin@redhat.com> 0.63-1
+- serialize access to NSS databases and the running of pre- and post-save
+  commands which might also access them (possibly fixing part of #883484)
+
+* Thu Nov 29 2012 Nalin Dahyabhai <nalin@redhat.com> 0.62-1
+- add a -u flag to getcert to enable requesting a keyUsage extension value
+- request subjectKeyIdentifier extensions from CAs, and include them in
+  self-signed certificates
+- request basicConstraints from CAs, defaulting to requests for end-entity
+  certificates
+- when requesting CA certificates, also request authorityKeyIdentifier
+- add support for requesting CRL distribution point and authorityInfoAccess
+  extensions that specify OCSP responder locations
+- don't crash when OpenSSL can't build a template certificate from a request
+  when we're in FIPS mode
+- put NSS in FIPS mode, when the system booted that way, except when we're
+  trying to write certificates to a database
+- fix CSR generation and self-signing in FIPS mode with NSS
+- fix self-signing in FIPS mode with OpenSSL
+- new languages from the translation team: mai, ml, nn, ga
+
+* Tue Nov 27 2012 Nalin Dahyabhai <nalin@redhat.com> 0.61-3
+- backport change from git to not choke if X509_REQ_to_X509() fails when we're
+  self-signing using OpenSSL
+- backport another change from git to represent this as a CA-rejected error
+
+* Mon Sep 24 2012 Nalin Dahyabhai <nalin@redhat.com> 0.61-1
+- fix a regression in reading old request tracking files where the
+  request was in state NEED_TO_NOTIFY or NOTIFYING
+
+* Wed Sep  5 2012 Nalin Dahyabhai <nalin@redhat.com> 0.60-1
+- adjust internals of logic for talking to dogtag to at least have a
+  concept of non-agent cases
+- when talking to an IPA server's internal Dogtag instance, infer which
+  ports the CA is listening on from the "dogtag_version" setting in the
+  IPA configuration (Ade Lee)
+- send a notification (or log a message, whatever) when we save a new
+  certificate (#766167)
+
+* Mon Jul 30 2012 Nalin Dahyabhai <nalin@redhat.com>
+- fix a bad %%preun scriptlet
+
+* Wed Jul 18 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.59-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
+
+* Fri Jun 29 2012 Nalin Dahyabhai <nalin@redhat.com> 0.59-1
+- mostly documentation updates
+
+* Fri Jun 29 2012 Nalin Dahyabhai <nalin@redhat.com> 0.58-1
+- add a "dogtag-ipa-renew-agent" CA so that we can renew certificates using
+  an IPA server's internal Dogtag instance
+- export the requested profile and old certificate to enrollment helpers
+- make libxml and libcurl into hard build-time requirements
+- serialize all pre/save/post sequences to make sure that stop/save/start
+  doesn't become stop1/save1/stop2/start1/save2/start2 when we're stopping
+  a service while we muck with more than one of its certificates
+
+* Fri Jun 15 2012 Nalin Dahyabhai <nalin@redhat.com>
+- add a command option (-T) to getcert for specifying which enrollment
+  profile to tell a CA that we're using, in case it cares (#10)
+
+* Thu Jun 14 2012 Nalin Dahyabhai <nalin@redhat.com> 0.57-1
+- clarify that the command passed to getcert -C is a "post"-save command
+- add a "pre"-save command option to getcert, specified with the -B flag (#9)
+- after we notify of an impending not-valid-after approaching, don't do it
+  again immediately
+
+* Sat Mar  3 2012 Nalin Dahyabhai <nalin@redhat.com> 0.56-1
+- when a caller sets the is-default flag on a CA, and another CA is no longer
+  the default, emit the PropertiesChanged signal on the CA which is not the
+  default, instead on the new default a second time
+- drop some dead code from the D-Bus message handlers (static analysis,
+  #796813)
+- cache public keys when we read private keys
+- go back to printing an error indicating that we're missing a required
+  argument when we're missing a required argument, not that the option is
+  invalid (broken since 0.51, #796542)
+
+* Wed Feb 15 2012 Nalin Dahyabhai <nalin@redhat.com> 0.55-1
+- allow root to use our implementation of org.freedesktop.DBus.Properties
+- take more care to not emit useless PropertiesChanged signals
+
+* Wed Feb 15 2012 Nalin Dahyabhai <nalin@redhat.com> 0.54-1
+- fix setting the group ID when spawning the post-save command
+
+* Tue Feb 14 2012 Nalin Dahyabhai <nalin@redhat.com> 0.53-1
+- large changes to the D-Bus glue, exposing a lot of data which we were
+  providing via D-Bus getter methods as properties, and providing more
+  accurate introspection data
+- emit a signal when the daemon saves a certificate to the destination
+  location, and provide an option to have the daemon spawn an arbitrary
+  command at that point, too (#766167)
+- enable starting the service by default on RHEL (#765600)
+
+* Thu Jan 12 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.52-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild
+
+* Fri Dec 16 2011 Nalin Dahyabhai <nalin@redhat.com> 0.52-1
+- note that SELinux usually confines us to writing only to cert_t in
+  doc/getting-started.txt (#765599)
+- fix crashes when we add a request during our first run when we're
+  populating the hard-coded CA list
+- properly deal with cases where a path is passed to us is "./XXX"
+- in session mode, create our data directories as we go
+
+* Tue Dec  6 2011 Nalin Dahyabhai <nalin@redhat.com> 0.51-1
+- api: lift restrictions on characters used in request and CA nicknames by
+  making their object names not incorporate their nicknames
+- api: add find_request_by_nickname and find_ca_by_nickname
+- certmonger-ipa-submit.8: list -k, -K, -t in the summary, document -K
+- getcert: print "invalid option" error messages ourselves (#756291)
+- ipa-submit: supply a Referer: header when submitting requests to IPA
+  (#750617, needed for #747710)
+
+* Fri Oct 14 2011 Nalin Dahyabhai <nalin@redhat.com> 0.50-1
+- really fix these this time:
+ - getcert: error out when "list -c" finds no matching CA (#743488)
+ - getcert: error out when "list -i" finds no matching request (#743485)
+
+* Wed Oct 12 2011 Nalin Dahyabhai <nalin@redhat.com> 0.49-1
+- when using an NSS database, skip loading the module database (#743042)
+- when using an NSS database, skip loading root certs
+- generate SPKAC values when generating CSRs, though we don't do anything
+  with SPKAC values yet
+- internally maintain and use challenge passwords, if we have them
+- behave better when certificates have shorter lifetimes
+- add/recognize/handle notification type "none"
+- getcert: error out when "list -c" finds no matching CA (#743488)
+- getcert: error out when "list -i" finds no matching request (#743485)
+
+* Thu Sep 29 2011 Nalin Dahyabhai <nalin@redhat.com> 0.48-1
+- don't incorrectly assume that CERT_ImportCerts() returns a NULL-terminated
+  array (#742348)
+
+* Tue Sep 27 2011 Nalin Dahyabhai <nalin@redhat.com> 0.47-1
+- getcert: distinguish between {stat() succeeds but isn't a directory} and
+  {stat() failed} when printing an error message (#739903)
+- getcert resubmit/start-tracking: when we're looking for an existing request
+  by ID, and we don't find one, note that specifically (#741262)
+
+* Mon Aug 29 2011 Stephen Gallagher <sgallagh@redhat.com> - 0.46-1.1
+- Rebuild against fixed libtevent version
+
+* Mon Aug 15 2011 Nalin Dahyabhai <nalin@redhat.com> 0.46-1
+- treat the ability to access keys in an NSS database without using a PIN,
+  when we've been told we need one, as an error (#692766, really this time)
+
+* Thu Aug 11 2011 Nalin Dahyabhai <nalin@redhat.com> 0.45-1
+- modify the systemd .service file to be a proper 'dbus' service (more
+  of #718172)
+
+* Thu Aug 11 2011 Nalin Dahyabhai <nalin@redhat.com> 0.44-1
+- check specifically for cases where a specified token that we need to
+  use just isn't present for whatever reason (#697058)
+
+* Wed Aug 10 2011 Nalin Dahyabhai <nalin@redhat.com> 0.43-1
+- add a -K option to ipa-submit, to use the current ccache, which makes
+  it easier to test
+
+* Fri Aug  5 2011 Nalin Dahyabhai <nalin@redhat.com>
+- if xmlrpc-c's struct xmlrpc_curl_xportparms has a gss_delegate field, set
+  it to TRUE when we're doing Negotiate auth (#727864, #727863, #727866)
+
+* Wed Jul 13 2011 Nalin Dahyabhai <nalin@redhat.com>
+- treat the ability to access keys in an NSS database without using a PIN,
+  when we've been told we need one, as an error (#692766)
+- when handling "getcert resubmit" requests, if we don't have a key yet,
+  make sure we go all the way back to generating one (#694184)
+- getcert: try to clean up tests for NSS and PEM file locations (#699059)
+- don't try to set reconnect-on-exit policy unless we managed to connect
+  to the bus (#712500)
+- handle cases where we specify a token but the storage token isn't
+  known (#699552)
+- getcert: recognize -i and storage options to narrow down which requests
+  the user wants to know about (#698772)
+- output hints when the daemon has startup problems, too (#712075)
+- add flags to specify whether we're bus-activated or not, so that we can
+  exit if we have nothing to do after handling a request received over
+  the bus if some specified amount of time has passed
+- explicitly disallow non-root access in the D-Bus configuration (#712072)
+- migrate to systemd on releases newer than Fedora 15 or RHEL 6 (#718172)
+- fix a couple of incorrect calls to talloc_asprintf() (#721392)
+
+* Wed Apr 13 2011 Nalin Dahyabhai <nalin@redhat.com> 0.42-1
+- getcert: fix a buffer overrun preparing a request for the daemon when
+  there are more parameters to encode than space in the array (#696185)
+- updated translations: de, es, id, pl, ru, uk
+
+* Mon Apr 11 2011 Nalin Dahyabhai <nalin@redhat.com> 0.41-1
+- read information about the keys we've just generated before proceeding
+  to generating a CSR (part of #694184, part of #695675)
+- when processing a "resubmit" request from getcert, go back to key
+  generation if we don't have keys yet, else go back to CSR generation as
+  before (#694184, #695675)
+- configure with --with-tmpdir=/var/run/certmonger and own /var/run/certmonger
+  (#687899), and add a systemd tmpfiles.d control file for creating
+  /var/run/certmonger on Fedora 15 and later
+- let session instances exit when they get disconnected from the bus
+- use a lock file to make sure there's only one session instance messing
+  around with the user's files at a time
+- fix errors saving certificates to NSS databases when there's already a
+  certificate there with the same nickname (#695672)
+- make key and certificate location output from 'getcert list' more properly
+  translatable (#7)
+
+* Mon Mar 28 2011 Nalin Dahyabhai <nalin@redhat.com> 0.40-1
+- update to 0.40
+  - fix validation check on EKU OIDs in getcert (#691351)
+  - get session bus mode sorted
+  - add a list of recognized EKU values to the getcert-request man page
+
+* Fri Mar 25 2011 Nalin Dahyabhai <nalin@redhat.com> 0.39-1
+- update to 0.39
+  - fix use of an uninitialized variable in the xmlrpc-based submission
+    helpers (#690886)
+
+* Thu Mar 24 2011 Nalin Dahyabhai <nalin@redhat.com> 0.38-1
+- update to 0.38
+  - catch cases where we can't read a PIN file, but we never have to log
+    in to the token to access the private key (more of #688229)
+
+* Tue Mar 22 2011 Nalin Dahyabhai <nalin@redhat.com> 0.37-1
+- update to 0.37
+  - be more careful about checking if we can read a PIN file successfully
+    before we even call an API that might need us to try (#688229)
+  - fix strict aliasing warnings
+
+* Tue Mar 22 2011 Nalin Dahyabhai <nalin@redhat.com> 0.36-1
+- update to 0.36
+  - fix some use-after-free bugs in the daemon (#689776)
+  - fix a copy/paste error in certmonger-ipa-submit(8)
+  - getcert now suppresses error details when not given its new -v option
+    (#683926, more of #681641/#652047)
+  - updated translations
+    - de, es, pl, ru, uk
+    - indonesian translation is now for "id" rather than "in"
+
+* Wed Mar  2 2011 Nalin Dahyabhai <nalin@redhat.com> 0.35.1-1
+- fix a self-test that broke because one-year-from-now is now a day's worth
+  of seconds further out than it was a few days ago
+
+* Mon Feb 14 2011 Nalin Dahyabhai <nalin@redhat.com> 0.35-1
+- update to 0.35
+  - self-test fixes to rebuild properly in mock (#670322)
+
+* Tue Feb 08 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.34-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
+
+* Fri Jan 14 2011 Nalin Dahyabhai <nalin@redhat.com> 0.34-1
+- update to 0.34
+  - explicitly note the number of requests we're tracking in the output of
+    "getcert list" (#652049)
+  - try to offer some suggestions when we get certain specific errors back
+    in "getcert" (#652047)
+  - updated translations
+    - es
+
+* Thu Dec 23 2010 Nalin Dahyabhai <nalin@redhat.com> 0.33-1
+- update to 0.33
+  - new translations
+    - id by Okta Purnama Rahadian!
+  - updated translations
+    - pl, uk
+  - roll up assorted fixes for defects
+
+* Fri Nov 12 2010 Nalin Dahyabhai <nalin@redhat.com> 0.32-2
+- depend on the e2fsprogs libuuid on Fedora and RHEL releases where it's
+  not part of util-linux-ng
+
+* Wed Oct 13 2010 Nalin Dahyabhai <nalin@redhat.com> 0.32-1
+- oops, rfc5280 says we shouldn't be populating unique identifiers, so
+  make it a configuration option and default the behavior to off
+
+* Tue Oct 12 2010 Nalin Dahyabhai <nalin@redhat.com> 0.31-1
+- start populating the optional unique identifier fields in self-signed
+  certificates
+
+* Thu Sep 30 2010 Nalin Dahyabhai <nalin@redhat.com> 0.30-4
+- explicitly require "dbus" to try to ensure we have a running system bus
+  when we get started (#639126)
+
+* Wed Sep 29 2010 jkeating - 0.30-3
+- Rebuilt for gcc bug 634757
+
+* Thu Sep 23 2010 Nalin Dahyabhai <nalin@redhat.com> 0.30-2
+- try to SIGHUP the messagebus daemon at first install so that it'll
+  let us claim our service name if it isn't restarted before we are
+  first started (#636876)
+
+* Wed Aug 25 2010 Nalin Dahyabhai <nalin@redhat.com> 0.30-1
+- update to 0.30
+  - fix errors computing the time at the end of an interval that were
+    caught by self-tests
+
+* Mon Aug 23 2010 Nalin Dahyabhai <nalin@redhat.com> 0.29-1
+- update to 0.29
+  - fix 64-bit cleanliness issue using libdbus
+  - actually include the full set of tests in tarballs
+
+* Tue Aug 17 2010 Nalin Dahyabhai <nalin@redhat.com> 0.28-1
+- update to 0.28
+  - fix self-signing certificate notBefore and notAfter values on 32-bit
+    machines
+
+* Tue Aug 17 2010 Nalin Dahyabhai <nalin@redhat.com> 0.27-1
+- update to 0.27
+  - portability and test fixes
+
+* Fri Aug 13 2010 Nalin Dahyabhai <nalin@redhat.com> 0.26-1
+- update to 0.26
+  - when canceling a submission request that's being handled by a helper,
+    reap the child process's status after killing it (#624120)
+
+* Fri Aug 13 2010 Nalin Dahyabhai <nalin@redhat.com> 0.25-1
+- update to 0.25
+  - new translations
+    - in by Okta Purnama Rahadian!
+  - fix detection of cases where we can't access a private key in an NSS
+    database because we don't have the PIN
+  - teach '*getcert start-tracking' about the -p and -P options which the
+    '*getcert request' commands already understand (#621670), and also
+    the -U, -K, -E, and -D flags
+  - double-check that the nicknames of keys we get back from
+    PK11_ListPrivKeysInSlot() match the desired nickname before accepting
+    them as matches, so that our tests won't all blow up on EL5
+  - fix dynamic addition and removal of CAs implemented through helpers
+
+* Mon Jun 28 2010 Nalin Dahyabhai <nalin@redhat.com> 0.24-4
+- init script: ensure that the subsys lock is created whenever we're called to
+  "start" when we're already running (even more of #596719)
+
+* Tue Jun 15 2010 Nalin Dahyabhai <nalin@redhat.com> 0.24-3
+- more gracefully handle manual daemon startups and cleaning up of unexpected
+  crashes (still more of #596719)
+
+* Thu Jun 10 2010 Nalin Dahyabhai <nalin@redhat.com> 0.24-2
+- don't create the daemon pidfile until after we've connected to the D-Bus
+  (still more of #596719)
+
+* Tue Jun  8 2010 Nalin Dahyabhai <nalin@redhat.com> 0.24-1
+- update to 0.24
+  - keep the lock on the pid file, if we have one, when we fork, and cancel
+    daemon startup if we can't gain ownership of the lock (the rest of #596719)
+  - make the man pages note which external configuration files we consult when
+    submitting requests to certmaster and ipa CAs
+
+* Thu May 27 2010 Nalin Dahyabhai <nalin@redhat.com> 0.23-1
+- update to 0.23
+  - new translations
+    - pl by Piotr Drąg!
+  - cancel daemon startup if we can't gain ownership of our well-known
+    service name on the DBus (#596719)
+
+* Fri May 14 2010 Nalin Dahyabhai <nalin@redhat.com> 0.22-1
+- update to 0.22
+  - new translations
+    - de by Fabian Affolter!
+  - certmaster-submit: don't fall over when we can't find a certmaster.conf
+    or a minion.conf (i.e., certmaster isn't installed) (#588932)
+  - when reading extension values from certificates, prune out duplicate
+    principal names, email addresses, and hostnames
+
+* Tue May  4 2010 Nalin Dahyabhai <nalin@redhat.com> 0.21-1
+- update to 0.21
+  - getcert/*-getcert: relay the desired CA to the local service, whether
+    specified on the command line (in getcert) or as a built-in hard-wired
+    default (in *-getcert) (#584983)
+  - flesh out the default certmonger.conf so that people can get a feel for
+    the expected formatting (Jenny Galipeau)
+
+* Wed Apr 21 2010 Nalin Dahyabhai <nalin@redhat.com> 0.20-1
+- update to 0.20
+  - correctly parse certificate validity periods given in years (spotted by
+    Stephen Gallagher)
+  - setup for translation
+    - es by Héctor Daniel Cabrera!
+    - ru by Yulia Poyarkova!
+    - uk by Yuri Chornoivan!
+  - fix unpreprocessed defaults in certmonger.conf's man page
+  - tweak the IPA-specific message that indicates a principal name also needs
+    to be specified if we're not using the default subject name (#579542)
+  - make the validity period of self-signed certificates into a configuration
+    setting and not a piece of the state information we track about the signer
+  - init script: exit with status 2 instead of 1 when invoked with an
+    unrecognized argument (#584517)
+
+* Tue Mar 23 2010 Nalin Dahyabhai <nalin@redhat.com> 0.19-1
+- update to 0.19
+  - correctly initialize NSS databases that need to be using a PIN
+  - add certmonger.conf, for customizing notification timings and settings,
+    and use of digests other than the previously-hard-coded SHA256, and
+    drop those settings from individual requests
+  - up the default self-sign validity interval from 30 days to 365 days
+  - drop the first default notification interval from 30 days to 28 days
+    (these two combined to create a fun always-reissuing loop earlier)
+  - record the token which contains the key or certificate when we're
+    storing them in an NSS database, and report it
+  - improve handling of cases where we're supposed to use a PIN but we
+    either don't have one or we have the wrong one
+  - teach getcert to accept a PIN file's name or a PIN value when adding
+    a new entry
+  - update the IPA submission helper to use the new 'request_cert' signature
+    that's landing soon
+  - more tests
+
+* Fri Feb 12 2010 Nalin Dahyabhai <nalin@redhat.com> 0.18-1
+- update to 0.18
+  - add support for using encrypted storage for keys, using PIN values
+    supplied directly or read from files whose names are supplied
+  - don't choke on NSS database locations that use the "sql:" or "dbm:"
+    prefix
+
+* Mon Jan 25 2010 Nalin Dahyabhai <nalin@redhat.com> 0.17-2
+- make the D-Bus configuration file (noreplace) (#541072)
+- make the %%check section and the deps we have just for it conditional on
+  the same macro (#541072)
+
+* Wed Jan  6 2010 Nalin Dahyabhai <nalin@redhat.com> 0.17-1
+- update to 0.17
+  - fix a hang in the daemon (Rob Crittenden)
+  - documentation updates
+  - fix parsing of submission results from IPA (Rob Crittenden)
+
+* Fri Dec 11 2009 Nalin Dahyabhai <nalin@redhat.com> 0.16-1
+- update to 0.16
+  - set a umask at startup (Dan Walsh)
+
+* Tue Dec  8 2009 Nalin Dahyabhai <nalin@redhat.com> 0.15-1
+- update to 0.15
+  - notice that a directory with a trailing '/' is the same location as the
+    directory without it
+  - fix handling of the pid file when we write one (by actually giving it
+    contents)
+
+* Wed Nov 25 2009 Nalin Dahyabhai <nalin@redhat.com> 0.14-1
+- update to 0.14
+  - check key and certificate location at add-time to make sure they're
+    absolute paths to files or directories, as appropriate
+  - IPA: dig into the 'result' item if the named result value we're looking
+    for isn't in the result struct
+
+* Tue Nov 24 2009 Nalin Dahyabhai <nalin@redhat.com> 0.13-1
+- update to 0.13
+  - change the default so that we default to trying to auto-refresh
+    certificates unless told otherwise
+  - preemptively enforce limitations on request nicknames so that they
+    make valid D-Bus object path components
+
+* Tue Nov 24 2009 Nalin Dahyabhai <nalin@redhat.com> 0.12-1
+- update to 0.12
+  - add a crucial bit of error reporting when CAs reject our requests
+  - count the number of configured CAs correctly
+
+* Mon Nov 23 2009 Nalin Dahyabhai <nalin@redhat.com> 0.11-1
+- update to 0.11
+  - add XML-RPC submission for certmaster and IPA
+  - prune entries with duplicate names from the data store
+
+* Fri Nov 13 2009 Nalin Dahyabhai <nalin@redhat.com> 0.10-1
+- update to 0.10
+  - add some compiler warnings and then fix them
+
+* Fri Nov 13 2009 Nalin Dahyabhai <nalin@redhat.com> 0.9-1
+- update to 0.9
+  - run external submission helpers correctly
+  - fix signing of signing requests generated for keys stored in files
+  - only care about new interface and route notifications from netlink,
+    and ignore notifications that don't come from pid 0
+  - fix logic for determining expiration status
+  - correct the version number in self-signed certificates
+
+* Tue Nov 10 2009 Nalin Dahyabhai <nalin@redhat.com> 0.8-1
+- update to 0.8
+  - encode windows UPN values in requests correctly
+  - watch for netlink routing changes and restart stalled submission requests
+  - 'getcert resubmit' can force a regeneration of the CSR and submission
+
+* Fri Nov  6 2009 Nalin Dahyabhai <nalin@redhat.com> 0.7-1
+- update to 0.7
+  - first cut at a getting-started document
+  - refactor some internal key handling with NSS
+  - check for duplicate request nicknames at add-time
+
+* Tue Nov  3 2009 Nalin Dahyabhai <nalin@redhat.com> 0.6-1
+- update to 0.6
+  - man pages
+  - 'getcert stop-tracking' actually makes the server forget now
+  - 'getcert request -e' was redundant, dropped the -e option
+  - 'getcert request -i' now sets the request nickname
+  - 'getcert start-tracking -i' now sets the request nickname
+
+* Mon Nov  2 2009 Nalin Dahyabhai <nalin@redhat.com> 0.5-1
+- update to 0.5
+  - packaging fixes
+  - add a selfsign-getcert client
+  - self-signed certs now get basic constraints and their own serial numbers
+  - accept id-ms-kp-sc-logon as a named EKU value in a request
+
+* Thu Oct 29 2009 Nalin Dahyabhai <nalin@redhat.com> 0.4-1
+- update to 0.4
+
+* Thu Oct 22 2009 Nalin Dahyabhai <nalin@redhat.com> 0.1-1
+- update to 0.1
+
+* Sun Oct 18 2009 Nalin Dahyabhai <nalin@redhat.com> 0.0-1
+- initial package