openssl: add blacklist-by-serial.

This lets us blacklist certs by serial as well as by sha256 fingerprint, and
adds the ability to comment in the blacklist file.

TEST=script (added to package tests)
BUG=chromium-os:20060

Change-Id: I57e98aa856a14d76341f41050d38477238649f37
Signed-off-by: Elly Jones <ellyjones@chromium.org>
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
index a6781b5..e1ee95b 100644
--- a/crypto/x509/x509_vfy.c
+++ b/crypto/x509/x509_vfy.c
@@ -128,23 +128,51 @@
 
 static int is_blacklisted(X509 *x)
 {
+	/* See http://tools.ietf.org/html/rfc5280#section-4.1.2.2:
+	 * "Certificate users MUST be able to handle serialNumber values up to
+	 *  20 octets.  Conforming CAs MUST NOT use serialNumber values longer
+	 *  than 20 octets."
+	 */
+	static const int MAX_SERIAL = 20;
+	static const int MAX_BLACKLIST_LINE = 1024;
+
 	unsigned char md[EVP_MAX_MD_SIZE];
 	char hexmd[EVP_MAX_MD_SIZE * 2 + 1];
+	char hexserial[MAX_SERIAL * 2 + 1];
 	const EVP_MD *hash = EVP_sha256();
 	unsigned int n;
-	char line[SHA256_DIGEST_LENGTH * 2 + 1];
+	char line[MAX_BLACKLIST_LINE];
 	BIO *file = BIO_new_file(OPENSSLDIR "/blacklist", "r");
 	int ret = 0;
+	ASN1_INTEGER *serial = NULL;
+	unsigned int serial_len;
 
 	if (!file)
 		return 0;
 
 	if (!X509_digest(x, hash, md, &n))
 		goto out;
-	hexify(md, hexmd, SHA256_DIGEST_LENGTH);
+	hexify(md, hexmd, n);
+	serial = X509_get_serialNumber(x);
+	serial_len = serial->length;
+	if (serial_len > sizeof(hexserial) / 2)
+		/* We only match the first MAX_SERIAL bytes of the serial. */
+		serial_len = sizeof(hexserial) / 2;
+	hexify(serial->data, hexserial, serial_len);
 
 	while (gets_trunc(file, line, sizeof(line))) {
-		if (!strcmp(line, hexmd)) {
+		char *str = line;
+		char *cmd = strsep(&str, " ");
+		char *arg = strsep(&str, " ");
+		if (!cmd || !arg || cmd[0] == '#')
+			continue;
+		if (strchr(arg, '\n'))
+			*strchr(arg, '\n') = '\0';
+		if (!strcmp(cmd, "sha256") && !strcmp(arg, hexmd)) {
+			ret = 1;
+			goto out;
+		}
+		if (!strcmp(cmd, "serial") && !strcmp(arg, hexserial)) {
 			ret = 1;
 			goto out;
 		}
diff --git a/test/Makefile b/test/Makefile
index 0b3b3e8..8a3cd68 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -161,7 +161,8 @@
 	test_rand test_bn test_ec test_ecdsa test_ecdh \
 	test_enc test_x509 test_rsa test_crl test_sid \
 	test_gen test_req test_pkcs7 test_verify test_dh test_dsa \
-	test_ss test_ca test_engine test_evp test_ssl test_ige test_jpake
+	test_ss test_ca test_engine test_evp test_ssl test_ige test_jpake \
+	test_blacklist
 
 test_evp:
 	../util/shlib_wrap.sh ./$(EVPTEST) evptests.txt
@@ -245,6 +246,9 @@
 	@sh ./treq 2>/dev/null
 	@sh ./treq testreq2.pem 2>/dev/null
 
+test_blacklist:
+	@sh ./tblacklist
+
 test_pkcs7:
 	@sh ./tpkcs7 2>/dev/null
 	@sh ./tpkcs7d 2>/dev/null
diff --git a/test/tblacklist b/test/tblacklist
new file mode 100644
index 0000000..42e4451
--- /dev/null
+++ b/test/tblacklist
@@ -0,0 +1,73 @@
+#!/bin/sh
+# Test /etc/ssl/blacklist
+
+td=$(mktemp -d "openssl-test.XXXXXXXX")
+
+cat >> "$td/thawte.pem" << EOF
+-----BEGIN CERTIFICATE-----
+MIIDIzCCAoygAwIBAgIEMAAAAjANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDMgUHVi
+bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNTEzMDAw
+MDAwWhcNMTQwNTEyMjM1OTU5WjBMMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh
+d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBD
+QTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1NNn0I0Vf67NMf59HZGhPwtx
+PKzMyGT7Y/wySweUvW+Aui/hBJPAM/wJMyPpC3QrccQDxtLN4i/1CWPN/0ilAL/g
+5/OIty0y3pg25gqtAHvEZEo7hHUD8nCSfQ5i9SGraTaEMXWQ+L/HbIgbBpV8yeWo
+3nWhLHpo39XKHIdYYBkCAwEAAaOB/jCB+zASBgNVHRMBAf8ECDAGAQH/AgEAMAsG
+A1UdDwQEAwIBBjARBglghkgBhvhCAQEEBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAX
+BgNVBAMTEFByaXZhdGVMYWJlbDMtMTUwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDov
+L2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwMgYIKwYBBQUHAQEEJjAkMCIGCCsG
+AQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMDQGA1UdJQQtMCsGCCsGAQUF
+BwMBBggrBgEFBQcDAgYJYIZIAYb4QgQBBgpghkgBhvhFAQgBMA0GCSqGSIb3DQEB
+BQUAA4GBAFWsY+reod3SkF+fC852vhNRj5PZBSvIG3dLrWlQoe7e3P3bB+noOZTc
+q3J5Lwa/q4FwxKjt6lM07e8eU9kGx1Yr0Vz00YqOtCuxN5BICEIlxT6Ky3/rbwTR
+bcV0oveifHtgPHfNDs5IAn8BL7abN+AqKjbc1YXWrOU/VG+WHgWv
+-----END CERTIFICATE-----
+EOF
+
+cat >> "$td/google.pem" << EOF
+-----BEGIN CERTIFICATE-----
+MIIDITCCAoqgAwIBAgIQL9+89q6RUm0PmqPfQDQ+mjANBgkqhkiG9w0BAQUFADBM
+MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg
+THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0wOTEyMTgwMDAwMDBaFw0x
+MTEyMTgyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh
+MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw
+FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
+gYEA6PmGD5D6htffvXImttdEAoN4c9kCKO+IRTn7EOh8rqk41XXGOOsKFQebg+jN
+gtXj9xVoRaELGYW84u+E593y17iYwqG7tcFR39SDAqc9BkJb4SLD3muFXxzW2k6L
+05vuuWciKh0R73mkszeK9P4Y/bz5RiNQl/Os/CRGK1w7t0UCAwEAAaOB5zCB5DAM
+BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl
+LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF
+BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw
+Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0
+ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUF
+AAOBgQCfQ89bxFApsb/isJr/aiEdLRLDLE5a+RLizrmCUi3nHX4adpaQedEkUjh5
+u2ONgJd8IyAPkU0Wueru9G2Jysa9zCRo1kNbzipYvzwY4OA8Ys+WAi0oR1A04Se6
+z5nRUP8pJcA2NhUzUnC+MY+f6H/nEQyNv4SgQhqAibAxWEEHXw==
+-----END CERTIFICATE-----
+EOF
+
+# These are from 'openssl x509 -in google.pem -text -fingerprint -sha256'
+google_sha256='f641c36cfef49bc071359ecf88eed9317b738b5989416ad401720c0a4e2e6352'
+google_serial='2fdfbcf6ae91526d0f9aa3df40343e9a'
+blacklist=/etc/ssl/blacklist
+
+die () {
+	echo "$@"
+	exit 1
+}
+
+verify () {
+	openssl verify -CAfile "$td/thawte.pem" "$td/google.pem" > "$td/$1.out" 2> "$td/$1.err"
+}
+
+# First, ensure that the cert verifies with no changes.
+cp "$blacklist" "$td/old-blacklist"
+verify good || die "failed to verify good signature"
+echo "serial $google_serial" > "$blacklist"
+verify serial && die "verified with blacklisted serial"
+echo "sha256 $google_sha256" > "$blacklist"
+verify sha256 && die "verified with blacklisted sha256"
+cp "$td/old-blacklist" "$blacklist"
+rm -rf "$td"
+exit 0