Branch: master

6df22c8c 2015-08-31 16:29:22 Timothy Pearson
Fix up Kerberos PKI certificate generation
M src/libtdeldap.cpp
M src/libtdeldap.h
diff --git a/src/libtdeldap.cpp b/src/libtdeldap.cpp
index f009297..e113114 100644
--- a/src/libtdeldap.cpp
+++ b/src/libtdeldap.cpp
@@ -24,6 +24,7 @@
 #include <netdb.h>
 #include <pwd.h>
 
+#include <tqdir.h>
 #include <tqfile.h>
 #include <tqcheckbox.h>
 #include <tdeapplication.h>
@@ -121,6 +122,13 @@
 TQString LDAPManager::ldapdnForRealm(TQString realm) {
 	TQStringList domainChunks = TQStringList::split(".", realm.lower());
 	TQString basedc = "dc=" + domainChunks.join(",dc=");
+	return basedc;
+}
+
+TQString LDAPManager::openssldcForRealm(TQString realm) {
+	TQStringList domainChunks = TQStringList::split(".", realm.lower());
+	TQString basedc = "DC=" + domainChunks.join("/DC=");
+	basedc = "/" + basedc;
 	return basedc;
 }
 
@@ -3803,12 +3811,17 @@
 	return ret;
 }
 
-int LDAPManager::generatePublicKerberosCACertificate(LDAPCertConfig certinfo) {
+int LDAPManager::generatePublicKerberosCACertificate(LDAPCertConfig certinfo, LDAPRealmConfig realmcfg) {
+	TQString errstr;
 	TQString command;
 	TQString subject;
 
+	if (writeOpenSSLConfigurationFile(realmcfg, &errstr) != 0) {
+		printf("ERROR: Unable to generate OpenSSL configuration file!  Details: '%s'\n", errstr.ascii());
+		return -1;
+	}
 	subject = TQString("\"/C=%1/ST=%2/L=%3/O=%4/OU=%5/CN=%6/emailAddress=%7\"").arg(certinfo.countryName).arg(certinfo.stateOrProvinceName).arg(certinfo.localityName).arg(certinfo.organizationName).arg(certinfo.orgUnitName).arg(certinfo.commonName).arg(certinfo.emailAddress);
-	command = TQString("openssl req -days %1 -key %2 -new -x509 -out %3 -subj %4").arg(certinfo.caExpiryDays).arg(KERBEROS_PKI_PEMKEY_FILE).arg(KERBEROS_PKI_PEM_FILE).arg(subject);
+	command = TQString("openssl req -days %1 -key %2 -new -x509 -out %3 -config %4 -subj %5").arg(certinfo.caExpiryDays).arg(KERBEROS_PKI_PEMKEY_FILE).arg(KERBEROS_PKI_PEM_FILE).arg(OPENSSL_EXTENSIONS_FILE).arg(subject);
 	if (system(command) < 0) {
 		printf("ERROR: Execution of \"%s\" failed!\n", command.ascii());
 		return -1;
@@ -3826,8 +3839,14 @@
 }
 
 int LDAPManager::generatePublicKerberosCertificate(LDAPCertConfig certinfo, LDAPRealmConfig realmcfg) {
+	TQString errstr;
 	TQString command;
 	TQString subject;
+
+	if (writeOpenSSLConfigurationFile(realmcfg, &errstr) != 0) {
+		printf("ERROR: Unable to generate OpenSSL configuration file!  Details: '%s'\n", errstr.ascii());
+		return -1;
+	}
 
 	TQString kdc_certfile = KERBEROS_PKI_KDC_FILE;
 	TQString kdc_keyfile = KERBEROS_PKI_KDCKEY_FILE;
@@ -3836,13 +3855,18 @@
 	kdc_keyfile.replace("@@@KDCSERVER@@@", realmcfg.name.lower());
 	kdc_reqfile.replace("@@@KDCSERVER@@@", realmcfg.name.lower());
 
-	subject = TQString("\"/C=%1/ST=%2/L=%3/O=%4/OU=%5/CN=%6/emailAddress=%7\"").arg(certinfo.countryName).arg(certinfo.stateOrProvinceName).arg(certinfo.localityName).arg(certinfo.organizationName).arg(certinfo.orgUnitName).arg(certinfo.commonName).arg(certinfo.emailAddress);
-	command = TQString("openssl req -days %1 -new -out %2 -key %3 -subj %4").arg(certinfo.kerberosExpiryDays).arg(kdc_reqfile).arg(kdc_keyfile).arg(subject);
+	TQString common_name = TQString::null;
+	if (realmcfg.kdc != "") {
+		common_name = TQString("/CN=%1").arg(common_name);
+	}
+
+	subject = TQString("\"/C=%1/ST=%2/L=%3/O=%4/OU=%5/%6%7\"").arg(certinfo.countryName).arg(certinfo.stateOrProvinceName).arg(certinfo.localityName).arg(certinfo.organizationName).arg(certinfo.orgUnitName).arg(common_name).arg(openssldcForRealm(realmcfg.name));
+	command = TQString("openssl req -days %1 -new -out %2 -key %3 -config %4 -subj %5").arg(certinfo.kerberosExpiryDays).arg(kdc_reqfile).arg(kdc_keyfile).arg(OPENSSL_EXTENSIONS_FILE).arg(subject);
 	if (system(command) < 0) {
 		printf("ERROR: Execution of \"%s\" failed!\n", command.ascii());
 		return -1;
 	}
-	command = TQString("openssl x509 -req -in %1 -CAkey %2 -CA %3 -out %4 -extfile %5 -extensions kdc_cert -CAcreateserial").arg(kdc_reqfile).arg(KERBEROS_PKI_PEMKEY_FILE).arg(KERBEROS_PKI_PEM_FILE).arg(kdc_certfile).arg(OPENSSL_EXTENSIONS_FILE);
+	command = TQString("openssl x509 -req -days %1 -in %2 -CAkey %3 -CA %4 -out %5 -extfile %6 -extensions pkinit_kdc_cert -CAcreateserial").arg(certinfo.kerberosExpiryDays).arg(kdc_reqfile).arg(KERBEROS_PKI_PEMKEY_FILE).arg(KERBEROS_PKI_PEM_FILE).arg(kdc_certfile).arg(OPENSSL_EXTENSIONS_FILE);
 	if (system(command) < 0) {
 		printf("ERROR: Execution of \"%s\" failed!\n", command.ascii());
 		return -1;
@@ -3866,8 +3890,14 @@
 }
 
 int LDAPManager::generatePublicLDAPCertificate(LDAPCertConfig certinfo, LDAPRealmConfig realmcfg, uid_t ldap_uid, gid_t ldap_gid) {
+	TQString errstr;
 	TQString command;
 	TQString subject;
+
+	if (writeOpenSSLConfigurationFile(realmcfg, &errstr) != 0) {
+		printf("ERROR: Unable to generate OpenSSL configuration file!  Details: '%s'\n", errstr.ascii());
+		return -1;
+	}
 
 	TQString ldap_certfile = LDAP_CERT_FILE;
 	TQString ldap_keyfile = LDAP_CERTKEY_FILE;
@@ -3876,13 +3906,18 @@
 	ldap_keyfile.replace("@@@ADMINSERVER@@@", realmcfg.name.lower());
 	ldap_reqfile.replace("@@@ADMINSERVER@@@", realmcfg.name.lower());
 
-	subject = TQString("\"/C=%1/ST=%2/L=%3/O=%4/OU=%5/CN=%6/emailAddress=%7\"").arg(certinfo.countryName).arg(certinfo.stateOrProvinceName).arg(certinfo.localityName).arg(certinfo.organizationName).arg(certinfo.orgUnitName).arg(certinfo.commonName).arg(certinfo.emailAddress);
-	command = TQString("openssl req -days %1 -new -out %2 -key %3 -subj %4").arg(certinfo.ldapExpiryDays).arg(ldap_reqfile).arg(ldap_keyfile).arg(subject);
+	TQString common_name = TQString::null;
+	if (realmcfg.kdc != "") {
+		common_name = TQString("/CN=%1").arg(common_name);
+	}
+
+	subject = TQString("\"/C=%1/ST=%2/L=%3/O=%4/OU=%5/%6%7\"").arg(certinfo.countryName).arg(certinfo.stateOrProvinceName).arg(certinfo.localityName).arg(certinfo.organizationName).arg(certinfo.orgUnitName).arg(common_name).arg(openssldcForRealm(realmcfg.name));
+	command = TQString("openssl req -days %1 -new -out %2 -key %3 -config %4 -subj %5").arg(certinfo.ldapExpiryDays).arg(ldap_reqfile).arg(ldap_keyfile).arg(OPENSSL_EXTENSIONS_FILE).arg(subject);
 	if (system(command) < 0) {
 		printf("ERROR: Execution of \"%s\" failed!\n", command.ascii());
 		return -1;
 	}
-	command = TQString("openssl x509 -req -in %1 -CAkey %2 -CA %3 -out %4 -CAcreateserial").arg(ldap_reqfile).arg(KERBEROS_PKI_PEMKEY_FILE).arg(KERBEROS_PKI_PEM_FILE).arg(ldap_certfile);
+	command = TQString("openssl x509 -req -days %1 -in %2 -CAkey %3 -CA %4 -out %5 -CAcreateserial").arg(certinfo.ldapExpiryDays).arg(ldap_reqfile).arg(KERBEROS_PKI_PEMKEY_FILE).arg(KERBEROS_PKI_PEM_FILE).arg(ldap_certfile);
 	if (system(command) < 0) {
 		printf("ERROR: Execution of \"%s\" failed!\n", command.ascii());
 		return -1;
@@ -4163,6 +4198,228 @@
 	return 0;
 }
 
+int LDAPManager::writeOpenSSLConfigurationFile(LDAPRealmConfig realmcfg, TQString *errstr) {
+	TQDir tde_cert_dir(TDE_CERTIFICATE_DIR);
+	if (!tde_cert_dir.exists()) {
+		TQString command = TQString("mkdir -p %1").arg(TDE_CERTIFICATE_DIR);
+		if (system(command) < 0) {
+			if (errstr) {
+				*errstr = i18n("Could not create directory '%1'").arg(TDE_CERTIFICATE_DIR);
+			}
+			return 1;
+		}
+	}
+	TQFile file(TQString::fromLatin1(OPENSSL_EXTENSIONS_FILE));
+	if (file.open(IO_WriteOnly)) {
+		TQTextStream stream( &file );
+
+		stream << "# This file was automatically generated by TDE\n";
+		stream << "# All changes will be lost!\n";
+		stream << "\n";
+		stream << "[ca]" << "\n";
+		stream << "default_ca = user" << "\n";
+		stream << "\n";
+		stream << "[usr]" << "\n";
+		// stream << "database = index.txt" << "\n";
+		// stream << "serial = serial" << "\n";
+		stream << "x509_extensions = usr_cert" << "\n";
+		stream << "default_md = sha1" << "\n";
+		stream << "policy = policy_match" << "\n";
+		stream << "email_in_dn = no" << "\n";
+		stream << "certs = ." << "\n";
+		stream << "\n";
+		stream << "[ocsp]" << "\n";
+		// stream << "database = index.txt" << "\n";
+		// stream << "serial = serial" << "\n";
+		stream << "x509_extensions = ocsp_cert" << "\n";
+		stream << "default_md = sha1" << "\n";
+		stream << "policy = policy_match" << "\n";
+		stream << "email_in_dn = no" << "\n";
+		stream << "certs = ." << "\n";
+		stream << "\n";
+		stream << "[usr_ke]" << "\n";
+		// stream << "database = index.txt" << "\n";
+		// stream << "serial = serial" << "\n";
+		stream << "x509_extensions = usr_cert_ke" << "\n";
+		stream << "default_md = sha1" << "\n";
+		stream << "policy = policy_match" << "\n";
+		stream << "email_in_dn = no" << "\n";
+		stream << "certs = ." << "\n";
+		stream << "\n";
+		stream << "[usr_ds]" << "\n";
+		// stream << "database = index.txt" << "\n";
+		// stream << "serial = serial" << "\n";
+		stream << "x509_extensions = usr_cert_ds" << "\n";
+		stream << "default_md = sha1" << "\n";
+		stream << "policy = policy_match" << "\n";
+		stream << "email_in_dn = no" << "\n";
+		stream << "certs = ." << "\n";
+		stream << "\n";
+		stream << "[pkinit_client]" << "\n";
+		// stream << "database = index.txt" << "\n";
+		// stream << "serial = serial" << "\n";
+		stream << "x509_extensions = pkinit_client_cert" << "\n";
+		stream << "default_md = sha1" << "\n";
+		stream << "policy = policy_match" << "\n";
+		stream << "email_in_dn = no" << "\n";
+		stream << "certs = ." << "\n";
+		stream << "\n";
+		stream << "[pkinit_kdc]" << "\n";
+		// stream << "database = index.txt" << "\n";
+		// stream << "serial = serial" << "\n";
+		stream << "x509_extensions = pkinit_kdc_cert" << "\n";
+		stream << "default_md = sha1" << "\n";
+		stream << "policy = policy_match" << "\n";
+		stream << "email_in_dn = no" << "\n";
+		stream << "certs = ." << "\n";
+		stream << "\n";
+		stream << "[https]" << "\n";
+		// stream << "database = index.txt" << "\n";
+		// stream << "serial = serial" << "\n";
+		stream << "x509_extensions = https_cert" << "\n";
+		stream << "default_md = sha1" << "\n";
+		stream << "policy = policy_match" << "\n";
+		stream << "email_in_dn = no" << "\n";
+		stream << "certs = ." << "\n";
+		stream << "\n";
+		stream << "[subca]" << "\n";
+		// stream << "database = index.txt" << "\n";
+		// stream << "serial = serial" << "\n";
+		stream << "x509_extensions = v3_ca" << "\n";
+		stream << "default_md = sha1" << "\n";
+		stream << "policy = policy_match" << "\n";
+		stream << "email_in_dn = no" << "\n";
+		stream << "certs = ." << "\n";
+		stream << "\n";
+		stream << "[req]" << "\n";
+		stream << "distinguished_name = req_distinguished_name" << "\n";
+		stream << "x509_extensions = v3_ca" << "\n";
+		stream << "string_mask = utf8only" << "\n";
+		stream << "\n";
+		stream << "[v3_ca]" << "\n";
+		stream << "subjectKeyIdentifier=hash" << "\n";
+		stream << "authorityKeyIdentifier=keyid:always,issuer:always" << "\n";
+		stream << "basicConstraints = CA:true" << "\n";
+		stream << "keyUsage = critical, cRLSign, keyCertSign, keyEncipherment, nonRepudiation, digitalSignature" << "\n";
+		stream << "\n";
+		stream << "[usr_cert]" << "\n";
+		stream << "basicConstraints=CA:FALSE" << "\n";
+		stream << "keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment" << "\n";
+		stream << TQString("crlDistributionPoints=URI:http://%1/crl.pem").arg(realmcfg.certificate_revocation_list_url);
+		stream << "subjectKeyIdentifier = hash" << "\n";
+		stream << "\n";
+		stream << "[usr_cert_ke]" << "\n";
+		stream << "basicConstraints=CA:FALSE" << "\n";
+		stream << "keyUsage = critical, nonRepudiation, keyEncipherment" << "\n";
+		stream << TQString("crlDistributionPoints=URI:http://%1/crl.pem").arg(realmcfg.certificate_revocation_list_url);
+		stream << "subjectKeyIdentifier = hash" << "\n";
+		stream << "\n";
+		stream << "[proxy_cert]" << "\n";
+		stream << "basicConstraints=CA:FALSE" << "\n";
+		stream << "keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment" << "\n";
+		stream << TQString("crlDistributionPoints=URI:http://%1/crl.pem").arg(realmcfg.certificate_revocation_list_url);
+		stream << "subjectKeyIdentifier = hash" << "\n";
+		// stream << "proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:0,policy:text:foo" << "\n";
+		stream << "\n";
+		stream << "[pkinitc_principals]" << "\n"; 
+		// stream << "princ1 = GeneralString:bar" << "\n";
+		stream << "\n";
 ** Diff limit reached (max: 250 lines) **