Drop --selfsign server functionality

Design: http://freeipa.org/page/V3/Drop_selfsign_functionality
Ticket: https://fedorahosted.org/freeipa/ticket/3494
This commit is contained in:
Petr Viktorin 2013-03-27 14:25:18 +01:00 committed by Rob Crittenden
parent 006ab23c6d
commit e736e75ce9
10 changed files with 133 additions and 801 deletions

View File

@ -112,7 +112,7 @@ def main():
api.bootstrap(in_server=True)
api.finalize()
if certs.ipa_self_signed():
if api.env.ra_plugin == 'selfsign':
sys.exit('A selfsign CA can not be added')
# get the directory manager password

View File

@ -1004,16 +1004,10 @@ def main():
ds = dsinstance.DsInstance(fstore=fstore)
ds.init_info(
realm_name, host_name, domain_name, dm_password,
False, options.subject, 1101, 1100, None)
options.subject, 1101, 1100, None)
if setup_ca:
# Clean up any previous self-signed CA that may exist
try:
os.remove(certs.CA_SERIALNO)
except:
pass
if not dogtag.install_constants.SHARED_DB:
cs = cainstance.CADSInstance(
host_name, realm_name, domain_name, dm_password)

View File

@ -61,10 +61,9 @@ def subject_base():
return _subject_base
def valid_issuer(issuer):
# Handle all supported forms of issuer -- currently dogtag only.
if api.env.ra_plugin == 'dogtag':
return DN(issuer) == DN(('CN', 'Certificate Authority'), subject_base())
else:
return DN(issuer) == DN(('CN', '%s Certificate Authority' % api.env.realm))
def strip_header(pem):
"""
@ -238,7 +237,6 @@ def verify_cert_subject(ldap, hostname, dercert):
issuer = str(nsscert.issuer)
del(nsscert)
# Handle both supported forms of issuer, from selfsign and dogtag.
if (not valid_issuer(issuer)):
raise errors.CertificateOperationError(error=_('Issuer "%(issuer)s" does not match the expected issuer') % \
{'issuer' : issuer})

View File

@ -17,20 +17,20 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import os, stat, subprocess, re
import os
import stat
import re
import sys
import tempfile
import shutil
from ipapython.ipa_log_manager import *
import xml.dom.minidom
import pwd
import fcntl
import base64
from hashlib import sha1
from ConfigParser import RawConfigParser, MissingSectionHeaderError
from nss import nss
from ipapython.ipa_log_manager import root_logger
from ipapython import dogtag
from ipapython import sysrestore
from ipapython import ipautil
@ -46,32 +46,6 @@ from ipalib.text import _
# where apache can reach
NSS_DIR = "/etc/httpd/alias"
CA_SERIALNO="/var/lib/ipa/ca_serialno"
def ipa_self_signed():
"""
Determine if the current IPA CA is self-signed or using another CA
We do this based on the CA plugin that is currently in use.
"""
if api.env.ra_plugin == 'selfsign':
return True
else:
return False
def ipa_self_signed_master():
"""
The selfsign backend is enabled only one a single master.
Return True/False whether this is that master.
Returns None if not a self-signed server.
"""
if ipa_self_signed():
return api.env.enable_ra
else:
return None
def find_cert_from_txt(cert, start=0):
"""
Given a cert blob (str) which may or may not contian leading and
@ -106,90 +80,6 @@ def get_cert_nickname(cert):
return (str(dn[0]), dn)
def next_serial(serial_file=CA_SERIALNO):
"""
Get the next serial number if we're using an NSS-based self-signed CA.
The file is an ini-like file with following properties:
lastvalue = the last serial number handed out
nextreplica = the serial number the next replica should start with
replicainterval = the number to add to nextreplica the next time a
replica is created
File locking is attempted so we have unique serial numbers.
"""
fp = None
parser = RawConfigParser()
if ipautil.file_exists(serial_file):
try:
fp = open(serial_file, "r+")
fcntl.flock(fp.fileno(), fcntl.LOCK_EX)
parser.readfp(fp)
serial = parser.getint('selfsign', 'lastvalue')
cur_serial = serial + 1
except IOError, e:
raise RuntimeError("Unable to determine serial number: %s" % str(e))
except MissingSectionHeaderError:
fcntl.flock(fp.fileno(), fcntl.LOCK_UN)
fp.close()
f=open(serial_file,"r")
r = f.readline()
f.close()
cur_serial = int(r) + 1
fp = open(serial_file, "w")
fcntl.flock(fp.fileno(), fcntl.LOCK_EX)
parser.add_section('selfsign')
parser.set('selfsign', 'nextreplica', 500000)
parser.set('selfsign', 'replicainterval', 500000)
else:
fp = open(serial_file, "w")
fcntl.flock(fp.fileno(), fcntl.LOCK_EX)
parser.add_section('selfsign')
parser.set('selfsign', 'nextreplica', 500000)
parser.set('selfsign', 'replicainterval', 500000)
cur_serial = 1000
try:
fp.seek(0)
parser.set('selfsign', 'lastvalue', cur_serial)
parser.write(fp)
fp.flush()
fcntl.flock(fp.fileno(), fcntl.LOCK_UN)
fp.close()
except IOError, e:
raise RuntimeError("Unable to increment serial number: %s" % str(e))
return str(cur_serial)
def next_replica(serial_file=CA_SERIALNO):
"""
Return the starting serial number for a new self-signed replica
"""
fp = None
parser = RawConfigParser()
if ipautil.file_exists(serial_file):
try:
fp = open(serial_file, "r+")
fcntl.flock(fp.fileno(), fcntl.LOCK_EX)
parser.readfp(fp)
serial = parser.getint('selfsign', 'nextreplica')
nextreplica = serial + parser.getint('selfsign', 'replicainterval')
except IOError, e:
raise RuntimeError("Unable to determine serial number: %s" % str(e))
else:
raise RuntimeError("%s does not exist, cannot create replica" % serial_file)
try:
fp.seek(0)
parser.set('selfsign', 'nextreplica', nextreplica)
parser.write(fp)
fp.flush()
fcntl.flock(fp.fileno(), fcntl.LOCK_UN)
fp.close()
except IOError, e:
raise RuntimeError("Unable to increment serial number: %s" % str(e))
return str(serial)
class NSSDatabase(object):
"""A general-purpose wrapper around a NSS cert database
@ -440,14 +330,9 @@ class CertDB(object):
except OSError, e:
raise RuntimeError("Unable to determine the current directory: %s" % str(e))
self.self_signed_ca = ipa_self_signed()
if not subject_base:
self.subject_base = DN(('O', 'IPA'))
if self.self_signed_ca:
self.cacert_name = get_ca_nickname(self.realm, 'CN=%s Certificate Authority')
else:
self.cacert_name = get_ca_nickname(self.realm)
self.valid_months = "120"
self.keysize = "1024"
@ -495,22 +380,6 @@ class CertDB(object):
# sure we are in a unique place when this happens
os.chdir(self.reqdir)
def set_serial_from_pkcs12(self):
"""A CA cert was loaded from a PKCS#12 file. Set up our serial file"""
cur_serial = self.find_cacert_serial()
try:
fp = open(CA_SERIALNO, "w")
parser = RawConfigParser()
parser.add_section('selfsign')
parser.set('selfsign', 'lastvalue', cur_serial)
parser.set('selfsign', 'nextreplica', 500000)
parser.set('selfsign', 'replicainterval', 500000)
parser.write(fp)
fp.close()
except IOError, e:
raise RuntimeError("Unable to increment serial number: %s" % str(e))
def set_perms(self, fname, write=False, uid=None):
if uid:
pent = pwd.getpwnam(uid)
@ -529,13 +398,10 @@ class CertDB(object):
return self.nssdb.run_certutil(args, stdin)
def run_signtool(self, args, stdin=None):
if not self.self_signed_ca:
f = open(self.passwd_fname, "r")
with open(self.passwd_fname, "r") as f:
password = f.readline()
f.close()
new_args = ["/usr/bin/signtool", "-d", self.secdir, "-p", password]
else:
new_args = ["/usr/bin/signtool", "-d", self.secdir]
new_args = new_args + args
ipautil.run(new_args, stdin)
@ -585,41 +451,6 @@ class CertDB(object):
return False
def create_ca_cert(self):
os.chdir(self.secdir)
subject = DN(('cn', '%s Certificate Authority' % self.realm))
p = subprocess.Popen(["/usr/bin/certutil",
"-d", self.secdir,
"-S", "-n", self.cacert_name,
"-s", str(subject),
"-x",
"-t", "CT,,C",
"-1",
"-2",
"-5",
"-m", next_serial(),
"-v", self.valid_months,
"-z", self.noise_fname,
"-f", self.passwd_fname],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
# Create key usage extension
# 0 - Digital Signature
# 1 - Non-repudiation
# 5 - Cert signing key
# Is this a critical extension [y/N]? y
p.stdin.write("0\n1\n5\n9\ny\n")
# Create basic constraint extension
# Is this a CA certificate [y/N]? y
# Enter the path length constraint, enter to skip [<0 for unlimited pat
# Is this a critical extension [y/N]? y
# 5 6 7 9 n -> SSL, S/MIME, Object signing CA
p.stdin.write("y\n\ny\n")
p.stdin.write("5\n6\n7\n9\nn\n")
p.wait()
os.chdir(self.cwd)
def export_ca_cert(self, nickname, create_pkcs12=False):
"""create_pkcs12 tells us whether we should create a PKCS#12 file
of the CA or not. If we are running on a replica then we won't
@ -686,16 +517,6 @@ class CertDB(object):
except ipautil.CalledProcessError:
return ''
def find_cacert_serial(self):
(out, err, returncode) = self.run_certutil(["-L", "-n", self.cacert_name])
data = out.split('\n')
for line in data:
x = re.match(r'\s+Serial Number: (\d+) .*', line)
if x is not None:
return x.group(1)
raise RuntimeError("Unable to find serial number")
def track_server_cert(self, nickname, principal, password_file=None, command=None):
"""
Tell certmonger to track the given certificate nickname.
@ -752,12 +573,7 @@ class CertDB(object):
def create_server_cert(self, nickname, hostname, other_certdb=None, subject=None):
"""
other_certdb can mean one of two things, depending on the context.
If we are using a self-signed CA then other_certdb contains the
CA that will be signing our CSR.
If we are using a dogtag CA then it contains the RA agent key
If we are using a dogtag CA then other_certdb contains the RA agent key
that will issue our cert.
You can override the certificate Subject by specifying a subject.
@ -802,44 +618,15 @@ class CertDB(object):
"-k", certtype,
"-g", keysize,
"-z", self.noise_fname,
"-f", self.passwd_fname]
if not self.self_signed_ca:
args.append("-a")
"-f", self.passwd_fname,
"-a"]
(stdout, stderr, returncode) = self.run_certutil(args)
os.remove(self.noise_fname)
return (stdout, stderr)
def issue_server_cert(self, certreq_fname, cert_fname):
self.setup_cert_request()
if self.self_signed_ca:
p = subprocess.Popen(["/usr/bin/certutil",
"-d", self.secdir,
"-C", "-c", self.cacert_name,
"-i", certreq_fname,
"-o", cert_fname,
"-m", next_serial(),
"-v", self.valid_months,
"-f", self.passwd_fname,
"-1", "-5"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
# Bah - this sucks, but I guess it isn't possible to fully
# control this with command line arguments.
#
# What this is requesting is:
# -1 (Create key usage extension)
# 2 - Key encipherment
# 9 - done
# n - not critical
#
# -5 (Create netscape cert type extension)
# 1 - SSL Server
# 9 - done
# n - not critical
p.stdin.write("2\n9\nn\n1\n9\nn\n")
p.wait()
else:
if self.host_name is None:
raise RuntimeError("CA Host is not set.")
@ -894,40 +681,9 @@ class CertDB(object):
f.write(cert)
f.close()
return
def issue_signing_cert(self, certreq_fname, cert_fname):
self.setup_cert_request()
if self.self_signed_ca:
p = subprocess.Popen(["/usr/bin/certutil",
"-d", self.secdir,
"-C", "-c", self.cacert_name,
"-i", certreq_fname,
"-o", cert_fname,
"-m", next_serial(),
"-v", self.valid_months,
"-f", self.passwd_fname,
"-1", "-5"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
# Bah - this sucks, but I guess it isn't possible to fully
# control this with command line arguments.
#
# What this is requesting is:
# -1 (Create key usage extension)
# 0 - Digital Signature
# 5 - Cert signing key
# 9 - done
# n - not critical
#
# -5 (Create netscape cert type extension)
# 3 - Object Signing
# 9 - done
# n - not critical
p.stdin.write("0\n5\n9\nn\n3\n9\nn\n")
p.wait()
else:
if self.host_name is None:
raise RuntimeError("CA Host is not set.")
@ -974,8 +730,6 @@ class CertDB(object):
f.write(cert)
f.close()
return
def add_cert(self, cert_fname, nickname):
"""
Load a certificate from a PEM file and add minimal trust.
@ -1020,48 +774,11 @@ class CertDB(object):
"""
root_nicknames = self.nssdb.get_trust_chain(nickname)
# Try to work around a change in the F-11 certutil where untrusted
# CA's are not shown in the chain. This will make a default IPA
# server installable.
if len(root_nicknames) == 0 and self.self_signed_ca:
return [self.cacert_name]
return root_nicknames
def find_root_cert_from_pkcs12(self, pkcs12_fname, passwd_fname=None):
"""Given a PKCS#12 file, try to find any certificates that do
not have a key. The assumption is that these are the root CAs.
"""
args = ["/usr/bin/pk12util", "-d", self.secdir,
"-l", pkcs12_fname,
"-k", passwd_fname]
if passwd_fname:
args = args + ["-w", passwd_fname]
try:
(stdout, stderr, returncode) = ipautil.run(args)
except ipautil.CalledProcessError, e:
if e.returncode == 17:
raise RuntimeError("incorrect password")
else:
raise RuntimeError("unknown error using pkcs#12 file")
lines = stdout.split('\n')
# A simple state machine.
# 1 = looking for "Certificate:"
# 2 = looking for the Friendly name (nickname)
nicknames = []
state = 1
for line in lines:
if state == 2:
m = re.match("\W+Friendly Name: (.*)", line)
if m:
nicknames.append( m.groups(0)[0])
state = 1
if line == "Certificate:":
state = 2
return nicknames
return self.nssdb.find_root_cert_from_pkcs12(pkcs12_fname,
passwd_fname=passwd_fname)
def trust_root_cert(self, root_nickname):
if root_nickname is None:
@ -1097,14 +814,6 @@ class CertDB(object):
"-in", pem_fname, "-out", pkcs12_fname,
"-passout", "file:" + pkcs12_pwd_fname])
def create_self_signed(self, passwd=None):
self.create_noise_file()
self.create_passwd_file(passwd)
self.create_certdbs()
self.create_ca_cert()
self.export_ca_cert(self.cacert_name, True)
self.create_pin_file()
def create_from_cacert(self, cacert_fname, passwd=None):
if ipautil.file_exists(self.certdb_fname):
# We already have a cert db, see if it is for the same CA.
@ -1167,94 +876,6 @@ class CertDB(object):
self.create_pin_file()
self.export_ca_cert(nickname, False)
self.self_signed_ca=False
# This file implies that we have our own self-signed CA. Ensure
# that it no longer exists (from previous installs, for example).
try:
os.remove(CA_SERIALNO)
except:
pass
def create_kdc_cert(self, nickname, hostname, destdir):
"""Create a new certificate with the spcial othername encoding needed
by a KDC certificate.
nickname: the CN name set in the certificate
destdir: the location where cert and key are to be installed
destdir will contain kdc.pem if the operation is successful
"""
reqcfg = "kdc_req.conf"
extcfg = ipautil.SHARE_DIR + "kdc_extensions.template"
key_fname = destdir + "/kdckey.pem"
cert_fname = destdir + "/kdccert.pem"
key_cert_fname = destdir + "/kdc.pem"
# Setup the temp dir
self.setup_cert_request()
# Copy the CA password file because openssl apparently can't use
# the same file twice within the same command and throws an error
ca_pwd_file = self.reqdir + "pwdfile.txt"
shutil.copyfile(self.passwd_fname, ca_pwd_file)
# Extract the cacert.pem file used by openssl to sign the certs
ipautil.run(["/usr/bin/openssl", "pkcs12",
"-in", self.pk12_fname,
"-passin", "file:" + self.passwd_fname,
"-passout", "file:" + ca_pwd_file,
"-out", "cacert.pem"])
# Create the kdc key
ipautil.run(["/usr/bin/openssl", "genrsa",
"-out", key_fname, "2048"])
# Prepare a simple cert request
req_dict = dict(PASSWORD=self.gen_password(),
SUBJBASE=self.subject_base,
CERTNAME=DN(('CN', nickname)))
req_template = ipautil.SHARE_DIR + reqcfg + ".template"
conf = ipautil.template_file(req_template, req_dict)
fd = open(reqcfg, "w+")
fd.write(conf)
fd.close()
base = str(self.subject_base).replace(",", "/")
esc_subject = DN(('CN', '%s/%s' % (nickname, base)))
ipautil.run(["/usr/bin/openssl", "req", "-new",
"-config", reqcfg,
"-subj", str(esc_subject),
"-key", key_fname,
"-out", "kdc.req"])
# Finally, sign the cert using the extensions file to set the
# special name
ipautil.run(["/usr/bin/openssl", "x509", "-req",
"-CA", "cacert.pem",
"-extfile", extcfg,
"-extensions", "kdc_cert",
"-passin", "file:" + ca_pwd_file,
"-set_serial", next_serial(),
"-in", "kdc.req",
"-out", cert_fname],
env = { 'REALM':self.realm, 'HOST_FQDN':hostname })
# Merge key and cert in a single file
fd = open(key_fname, "r")
key = fd.read()
fd.close()
fd = open(cert_fname, "r")
cert = fd.read()
fd.close()
fd = open(key_cert_fname, "w")
fd.write(key)
fd.write(cert)
fd.close()
os.unlink(key_fname)
os.unlink(cert_fname)
def install_pem_from_p12(self, p12_fname, p12_pwd_fname, pem_fname):
ipautil.run(["/usr/bin/openssl", "pkcs12", "-nodes",

View File

@ -36,7 +36,7 @@ import certs
import ldap
from ipaserver.install import ldapupdate
from ipaserver.install import replication
from ipalib import errors, api
from ipalib import errors
from ipapython.dn import DN
SERVER_ROOT_64 = "/usr/lib64/dirsrv"
@ -228,8 +228,7 @@ class DsInstance(service.Service):
self.step("configuring directory to start on boot", self.__enable)
def init_info(self, realm_name, fqdn, domain_name, dm_password,
self_signed_ca, subject_base, idstart, idmax, pkcs12_info,
ca_file=None):
subject_base, idstart, idmax, pkcs12_info, ca_file=None):
self.realm_name = realm_name.upper()
self.serverid = realm_to_serverid(self.realm_name)
self.suffix = ipautil.realm_to_suffix(self.realm_name)
@ -237,7 +236,6 @@ class DsInstance(service.Service):
self.dm_password = dm_password
self.domain = domain_name
self.principal = "ldap/%s@%s" % (self.fqdn, self.realm_name)
self.self_signed_ca = False
self.subject_base = subject_base
self.idstart = idstart
self.idmax = idmax
@ -247,11 +245,11 @@ class DsInstance(service.Service):
self.__setup_sub_dict()
def create_instance(self, realm_name, fqdn, domain_name,
dm_password, pkcs12_info=None, self_signed_ca=False,
dm_password, pkcs12_info=None,
idstart=1100, idmax=999999, subject_base=None,
hbac_allow=True, ca_file=None):
self.init_info(
realm_name, fqdn, domain_name, dm_password, self_signed_ca,
realm_name, fqdn, domain_name, dm_password,
subject_base, idstart, idmax, pkcs12_info, ca_file=ca_file)
self.__common_setup()
@ -282,7 +280,7 @@ class DsInstance(service.Service):
idmax = 1100
self.init_info(
realm_name, fqdn, domain_name, dm_password, None, None,
realm_name, fqdn, domain_name, dm_password, None,
idstart, idmax, pkcs12_info, ca_file=ca_file)
self.master_fqdn = master_fqdn
@ -545,21 +543,12 @@ class DsInstance(service.Service):
# We only handle one server cert
nickname = server_certs[0][0]
self.dercert = dsdb.get_cert_from_db(nickname, pem=False)
if api.env.enable_ra:
dsdb.track_server_cert(
nickname, self.principal, dsdb.passwd_fname,
dsdb.track_server_cert(nickname, self.principal, dsdb.passwd_fname,
'restart_dirsrv %s' % self.serverid)
else:
nickname = self.nickname
cadb = certs.CertDB(self.realm_name, host_name=self.fqdn, subject_base=self.subject_base)
if self.self_signed_ca:
dsdb.create_from_cacert(cadb.cacert_fname, passwd=None)
self.dercert = dsdb.create_server_cert(nickname, self.fqdn, cadb)
dsdb.track_server_cert(
nickname, self.principal, dsdb.passwd_fname,
'restart_dirsrv %s' % self.serverid)
dsdb.create_pin_file()
else:
# FIXME, need to set this nickname in the RA plugin
cadb.export_ca_cert('ipaCert', False)
dsdb.create_from_cacert(cadb.cacert_fname, passwd=None)

View File

@ -63,15 +63,13 @@ class HTTPInstance(service.Service):
def create_instance(self, realm, fqdn, domain_name, dm_password=None,
autoconfig=True, pkcs12_info=None,
self_signed_ca=False, subject_base=None,
auto_redirect=True, ca_file=None):
subject_base=None, auto_redirect=True, ca_file=None):
self.fqdn = fqdn
self.realm = realm
self.domain = domain_name
self.dm_password = dm_password
self.suffix = ipautil.realm_to_suffix(self.realm)
self.pkcs12_info = pkcs12_info
self.self_signed_ca = self_signed_ca
self.principal = "HTTP/%s@%s" % (self.fqdn, self.realm)
self.dercert = None
self.subject_base = subject_base
@ -237,8 +235,6 @@ class HTTPInstance(service.Service):
print "Adding Include conf.d/ipa-rewrite to %s failed." % NSS_CONF
def __setup_ssl(self):
fqdn = None
if not self.self_signed_ca:
fqdn = self.fqdn
ca_db = certs.CertDB(self.realm, host_name=fqdn, subject_base=self.subject_base)
@ -262,8 +258,6 @@ class HTTPInstance(service.Service):
self.__set_mod_nss_nickname(nickname)
else:
if self.self_signed_ca:
db.create_from_cacert(ca_db.cacert_fname)
db.create_password_conf()
self.dercert = db.create_server_cert(self.cert_nickname, self.fqdn,
@ -288,13 +282,6 @@ class HTTPInstance(service.Service):
ipaservices.restore_context(certs.NSS_DIR + "/cert8.db")
ipaservices.restore_context(certs.NSS_DIR + "/key3.db")
# In case this got generated as part of the install, reset the
# context
if ipautil.file_exists(certs.CA_SERIALNO):
ipaservices.restore_context(certs.CA_SERIALNO)
os.chown(certs.CA_SERIALNO, 0, pent.pw_gid)
os.chmod(certs.CA_SERIALNO, 0664)
def __setup_autoconfig(self):
target_fname = '/usr/share/ipa/html/preferences.html'
ipautil.copy_template_file(

View File

@ -130,13 +130,6 @@ class ReplicaPrepare(admintool.AdminTool):
if api.env.host == self.replica_fqdn:
raise admintool.ScriptError("You can't create a replica on itself")
# FIXME: certs.ipa_self_signed_master return value can be
# True, False, None, with different meanings.
# So, we need to explicitly compare to False
if certs.ipa_self_signed_master() == False:
raise admintool.ScriptError("A selfsign CA backend can only "
"prepare on the original master")
if not api.env.enable_ra and not options.http_pkcs12:
raise admintool.ScriptError(
"Cannot issue certificates: a CA is not installed. Use the "
@ -227,8 +220,7 @@ class ReplicaPrepare(admintool.AdminTool):
options.reverse_zone, options.ip_address):
raise admintool.ScriptError("Invalid reverse zone")
if (not certs.ipa_self_signed() and
not ipautil.file_exists(
if (not ipautil.file_exists(
dogtag.configured_constants().CS_CFG_PATH) and
not options.dirsrv_pin):
self.log.info("If you installed IPA with your own certificates "
@ -281,17 +273,17 @@ class ReplicaPrepare(admintool.AdminTool):
options.dirsrv_pkcs12)
self.copy_info_file(options.dirsrv_pkcs12, "dscert.p12")
else:
if not certs.ipa_self_signed():
if ipautil.file_exists(options.ca_file):
self.copy_info_file(options.ca_file, "cacert.p12")
else:
raise admintool.ScriptError("Root CA PKCS#12 not "
"found in %s" % options.ca_file)
self.log.info(
"Creating SSL certificate for the Directory Server")
self.export_certdb("dscert", passwd_fname)
if not options.dirsrv_pkcs12 and not certs.ipa_self_signed():
if not options.dirsrv_pkcs12:
self.log.info(
"Creating SSL certificate for the dogtag Directory Server")
self.export_certdb("dogtagcert", passwd_fname)
@ -318,7 +310,6 @@ class ReplicaPrepare(admintool.AdminTool):
self.export_certdb("httpcert", passwd_fname)
self.log.info("Exporting RA certificate")
if not certs.ipa_self_signed():
self.export_ra_pkcs12()
def copy_pkinit_certificate(self):
@ -464,17 +455,12 @@ class ReplicaPrepare(admintool.AdminTool):
nickname = "Server-Cert"
try:
self_signed = certs.ipa_self_signed()
db = certs.CertDB(
api.env.realm, nssdir=self.dir, subject_base=subject_base)
db.create_passwd_file()
ca_db = certs.CertDB(
api.env.realm, host_name=api.env.host,
subject_base=subject_base)
if is_kdc:
ca_db.create_kdc_cert("KDC-Cert", hostname, self.dir)
else:
db.create_from_cacert(ca_db.cacert_fname)
db.create_server_cert(nickname, hostname, ca_db)

View File

@ -81,7 +81,6 @@ class KrbInstance(service.Service):
self.kdc_password = None
self.sub_dict = None
self.pkcs12_info = None
self.self_signed_ca = None
if fstore:
self.fstore = fstore
@ -158,10 +157,9 @@ class KrbInstance(service.Service):
self.step("starting the KDC", self.__start_instance)
self.step("configuring KDC to start on boot", self.__enable)
def create_instance(self, realm_name, host_name, domain_name, admin_password, master_password, setup_pkinit=False, pkcs12_info=None, self_signed_ca=False, subject_base=None):
def create_instance(self, realm_name, host_name, domain_name, admin_password, master_password, setup_pkinit=False, pkcs12_info=None, subject_base=None):
self.master_password = master_password
self.pkcs12_info = pkcs12_info
self.self_signed_ca = self_signed_ca
self.subject_base = subject_base
self.__common_setup(realm_name, host_name, domain_name, admin_password)
@ -189,9 +187,8 @@ class KrbInstance(service.Service):
master_fqdn, host_name,
domain_name, admin_password,
setup_pkinit=False, pkcs12_info=None,
self_signed_ca=False, subject_base=None):
subject_base=None):
self.pkcs12_info = pkcs12_info
self.self_signed_ca = self_signed_ca
self.subject_base = subject_base
self.master_fqdn = master_fqdn
@ -412,10 +409,6 @@ class KrbInstance(service.Service):
self.move_service_to_host(host_principal)
def __setup_pkinit(self):
if self.self_signed_ca:
ca_db = certs.CertDB(self.realm,
subject_base=self.subject_base)
else:
ca_db = certs.CertDB(self.realm, host_name=self.fqdn,
subject_base=self.subject_base)
@ -423,10 +416,6 @@ class KrbInstance(service.Service):
ca_db.install_pem_from_p12(self.pkcs12_info[0],
self.pkcs12_info[1],
"/var/kerberos/krb5kdc/kdc.pem")
else:
if self.self_signed_ca:
ca_db.create_kdc_cert("KDC-Cert", self.fqdn,
"/var/kerberos/krb5kdc")
else:
raise RuntimeError("PKI not supported yet\n")

View File

@ -44,11 +44,9 @@ class rabase(Backend):
if api.env.in_tree:
self.sec_dir = api.env.dot_ipa + os.sep + 'alias'
self.pwd_file = self.sec_dir + os.sep + '.pwd'
self.serial_file = self.sec_dir + os.sep + 'ca_serialno'
else:
self.sec_dir = "/etc/httpd/alias"
self.pwd_file = "/etc/httpd/alias/pwdfile.txt"
self.serial_file = certs.CA_SERIALNO
super(rabase, self).__init__()

View File

@ -1,230 +0,0 @@
# Authors:
# Rob Crittenden <rcritten@@redhat.com>
# John Dennis <jdennis@redhat.com>
#
# Copyright (C) 2009 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Backend plugin for RA activities.
The `ra` plugin provides access to the CA to issue, retrieve, and revoke
certificates via the following methods:
* `ra.check_request_status()` - check certificate request status.
* `ra.get_certificate()` - retrieve an existing certificate.
* `ra.request_certificate()` - request a new certificate.
* `ra.revoke_certificate()` - revoke a certificate.
* `ra.take_certificate_off_hold()` - take a certificate off hold.
"""
from ipalib import api, SkipPluginModule
if api.env.ra_plugin != 'selfsign':
# In this case, abort loading this plugin module...
raise SkipPluginModule(reason='selfsign is not selected as RA plugin, it is %s' % api.env.ra_plugin)
from ipalib import Backend
from ipalib import errors
from ipalib import x509
from ipalib import pkcs10
from ipapython.dn import DN, EditableDN, RDN
from ipapython.certdb import get_ca_nickname
import subprocess
import os
import re
from ipaserver.plugins import rabase
from ipaserver.install import certs
import tempfile
from ipalib import _
from ipalib import api
from ipalib.plugins.cert import get_csr_hostname
from nss.error import NSPRError
class ra(rabase.rabase):
"""
Request Authority backend plugin.
"""
def request_certificate(self, csr, request_type='pkcs10'):
"""
:param csr: The certificate signing request.
:param request_type: The request type (defaults to ``'pkcs10'``).
Submit certificate signing request.
The command returns a dict with these possible key/value pairs.
Some key/value pairs may be absent.
+---------------+---------------+---------------+
|result name |result type |comments |
+===============+===============+===============+
|serial_number |unicode [1]_ | |
+---------------+---------------+---------------+
|certificate |unicode [2]_ | |
+---------------+---------------+---------------+
|request_id |unicode | |
+---------------+---------------+---------------+
|subject |unicode | |
+---------------+---------------+---------------+
.. [1] Passed through XMLRPC as decimal string. Can convert to
optimal integer type (int or long) via int(serial_number)
.. [2] Base64 encoded
"""
try:
config = api.Command['config_show']()['result']
subject_base = EditableDN(config.get('ipacertificatesubjectbase')[0])
hostname = get_csr_hostname(csr)
subject_base.insert(0, RDN(('CN', hostname)))
request = pkcs10.load_certificate_request(csr)
# python-nss normalizes the request subject
request_subject = DN(str(pkcs10.get_subject(request)))
if subject_base != request_subject:
raise errors.CertificateOperationError(error=_('Request subject "%(request_subject)s" does not match the form "%(subject_base)s"') % \
{'request_subject' : request_subject, 'subject_base' : subject_base})
except errors.CertificateOperationError, e:
raise e
except NSPRError, e:
raise errors.CertificateOperationError(error=_('unable to decode csr: %s') % e)
# certutil wants the CSR to have have a header and footer. Add one
# if it isn't there.
s = csr.find('-----BEGIN NEW CERTIFICATE REQUEST-----')
if s == -1:
s = csr.find('-----BEGIN CERTIFICATE REQUEST-----')
if s == -1:
csr = '-----BEGIN NEW CERTIFICATE REQUEST-----\n' + csr + \
'\n-----END NEW CERTIFICATE REQUEST-----\n'
try:
(csr_fd, csr_name) = tempfile.mkstemp()
os.write(csr_fd, csr)
os.close(csr_fd)
except Exception, e:
try:
os.remove(csr_name)
except:
pass
self.log.error('unable to create temporary csr file: %s' % e)
raise errors.CertificateOperationError(error=_('file operation'))
try:
(cert_fd, cert_name) = tempfile.mkstemp()
os.close(cert_fd)
except Exception, e:
try:
os.remove(csr_name)
except:
pass
try:
os.remove(cert_name)
except:
pass
self.log.error('unable to create temporary certificate file: %s' % e)
raise errors.CertificateOperationError(error=_('file operation'))
try:
serialno = certs.next_serial(self.serial_file)
except Exception, e:
try:
os.remove(csr_name)
except:
pass
try:
os.remove(cert_name)
except:
pass
self.log.error('next_serial() failed: %s' % e)
raise errors.CertificateOperationError(error=_('cannot obtain next serial number'))
try:
args = [
"/usr/bin/certutil",
"-C",
"-d", self.sec_dir,
"-c", get_ca_nickname(api.env.realm),
"-i", csr_name,
"-o", cert_name,
"-m", str(serialno),
"-v", "60",
"-1",
"-5",
"-6",
"-a",
"-f", self.pwd_file]
self.log.debug("issue cert: %s" % str(args))
p = subprocess.Popen(args,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE, close_fds=True)
p.stdin.write("0\n1\n2\n3\n9\ny\n")
p.stdin.write("0\n9\nn\n")
p.stdin.write("1\n9\nn\n")
(stdout, stderr) = p.communicate()
status = p.returncode
self.log.debug("stdout = %s" % stdout)
self.log.debug("stderr = %s" % stderr)
if status != 0:
try:
os.remove(cert_name)
except:
pass
self.log.error('certutil failed: %s' % stderr)
raise errors.CertificateOperationError(error=_('certutil failure'))
finally:
try:
os.remove(csr_name)
except:
pass
try:
cert_fd = open(cert_name)
cert = cert_fd.read()
cert_fd.close()
finally:
try:
os.remove(cert_name)
except:
pass
try:
subject = x509.get_subject(cert)
serial = x509.get_serial_number(cert)
except NSPRError, e:
self.log.error('Unable to decode certificate in entry: %s' % str(e))
raise errors.CertificateOperationError(
error=_('Unable to decode certificate in entry: %s') % str(e))
# To make it look like dogtag return just the base64 data.
cert = cert.replace('\n','')
cert = cert.replace('\r','')
s = cert.find('-----BEGIN CERTIFICATE-----')
e = cert.find('-----END CERTIFICATE-----')
s = s + 27
cert = cert[s:e]
cmd_result = {}
cmd_result['serial_number'] = unicode(serial) # convert long to decimal unicode string
cmd_result['serial_number_hex'] = u'0x%X' % serial
cmd_result['certificate'] = unicode(cert)
cmd_result['subject'] = unicode(subject)
return cmd_result
api.register(ra)