mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
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:
parent
006ab23c6d
commit
e736e75ce9
@ -112,7 +112,7 @@ def main():
|
|||||||
api.bootstrap(in_server=True)
|
api.bootstrap(in_server=True)
|
||||||
api.finalize()
|
api.finalize()
|
||||||
|
|
||||||
if certs.ipa_self_signed():
|
if api.env.ra_plugin == 'selfsign':
|
||||||
sys.exit('A selfsign CA can not be added')
|
sys.exit('A selfsign CA can not be added')
|
||||||
|
|
||||||
# get the directory manager password
|
# get the directory manager password
|
||||||
|
@ -1004,16 +1004,10 @@ def main():
|
|||||||
ds = dsinstance.DsInstance(fstore=fstore)
|
ds = dsinstance.DsInstance(fstore=fstore)
|
||||||
ds.init_info(
|
ds.init_info(
|
||||||
realm_name, host_name, domain_name, dm_password,
|
realm_name, host_name, domain_name, dm_password,
|
||||||
False, options.subject, 1101, 1100, None)
|
options.subject, 1101, 1100, None)
|
||||||
|
|
||||||
|
|
||||||
if setup_ca:
|
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:
|
if not dogtag.install_constants.SHARED_DB:
|
||||||
cs = cainstance.CADSInstance(
|
cs = cainstance.CADSInstance(
|
||||||
host_name, realm_name, domain_name, dm_password)
|
host_name, realm_name, domain_name, dm_password)
|
||||||
|
@ -61,10 +61,9 @@ def subject_base():
|
|||||||
return _subject_base
|
return _subject_base
|
||||||
|
|
||||||
def valid_issuer(issuer):
|
def valid_issuer(issuer):
|
||||||
|
# Handle all supported forms of issuer -- currently dogtag only.
|
||||||
if api.env.ra_plugin == 'dogtag':
|
if api.env.ra_plugin == 'dogtag':
|
||||||
return DN(issuer) == DN(('CN', 'Certificate Authority'), subject_base())
|
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):
|
def strip_header(pem):
|
||||||
"""
|
"""
|
||||||
@ -238,7 +237,6 @@ def verify_cert_subject(ldap, hostname, dercert):
|
|||||||
issuer = str(nsscert.issuer)
|
issuer = str(nsscert.issuer)
|
||||||
del(nsscert)
|
del(nsscert)
|
||||||
|
|
||||||
# Handle both supported forms of issuer, from selfsign and dogtag.
|
|
||||||
if (not valid_issuer(issuer)):
|
if (not valid_issuer(issuer)):
|
||||||
raise errors.CertificateOperationError(error=_('Issuer "%(issuer)s" does not match the expected issuer') % \
|
raise errors.CertificateOperationError(error=_('Issuer "%(issuer)s" does not match the expected issuer') % \
|
||||||
{'issuer' : issuer})
|
{'issuer' : issuer})
|
||||||
|
@ -17,20 +17,20 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# 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 sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import shutil
|
import shutil
|
||||||
from ipapython.ipa_log_manager import *
|
|
||||||
import xml.dom.minidom
|
import xml.dom.minidom
|
||||||
import pwd
|
import pwd
|
||||||
import fcntl
|
|
||||||
import base64
|
import base64
|
||||||
from hashlib import sha1
|
from hashlib import sha1
|
||||||
from ConfigParser import RawConfigParser, MissingSectionHeaderError
|
|
||||||
|
|
||||||
from nss import nss
|
from nss import nss
|
||||||
|
|
||||||
|
from ipapython.ipa_log_manager import root_logger
|
||||||
from ipapython import dogtag
|
from ipapython import dogtag
|
||||||
from ipapython import sysrestore
|
from ipapython import sysrestore
|
||||||
from ipapython import ipautil
|
from ipapython import ipautil
|
||||||
@ -46,32 +46,6 @@ from ipalib.text import _
|
|||||||
# where apache can reach
|
# where apache can reach
|
||||||
NSS_DIR = "/etc/httpd/alias"
|
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):
|
def find_cert_from_txt(cert, start=0):
|
||||||
"""
|
"""
|
||||||
Given a cert blob (str) which may or may not contian leading and
|
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)
|
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):
|
class NSSDatabase(object):
|
||||||
"""A general-purpose wrapper around a NSS cert database
|
"""A general-purpose wrapper around a NSS cert database
|
||||||
@ -440,15 +330,10 @@ class CertDB(object):
|
|||||||
except OSError, e:
|
except OSError, e:
|
||||||
raise RuntimeError("Unable to determine the current directory: %s" % str(e))
|
raise RuntimeError("Unable to determine the current directory: %s" % str(e))
|
||||||
|
|
||||||
self.self_signed_ca = ipa_self_signed()
|
|
||||||
|
|
||||||
if not subject_base:
|
if not subject_base:
|
||||||
self.subject_base = DN(('O', 'IPA'))
|
self.subject_base = DN(('O', 'IPA'))
|
||||||
|
|
||||||
if self.self_signed_ca:
|
self.cacert_name = get_ca_nickname(self.realm)
|
||||||
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.valid_months = "120"
|
||||||
self.keysize = "1024"
|
self.keysize = "1024"
|
||||||
|
|
||||||
@ -495,22 +380,6 @@ class CertDB(object):
|
|||||||
# sure we are in a unique place when this happens
|
# sure we are in a unique place when this happens
|
||||||
os.chdir(self.reqdir)
|
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):
|
def set_perms(self, fname, write=False, uid=None):
|
||||||
if uid:
|
if uid:
|
||||||
pent = pwd.getpwnam(uid)
|
pent = pwd.getpwnam(uid)
|
||||||
@ -529,13 +398,10 @@ class CertDB(object):
|
|||||||
return self.nssdb.run_certutil(args, stdin)
|
return self.nssdb.run_certutil(args, stdin)
|
||||||
|
|
||||||
def run_signtool(self, args, stdin=None):
|
def run_signtool(self, args, stdin=None):
|
||||||
if not self.self_signed_ca:
|
with open(self.passwd_fname, "r") as f:
|
||||||
f = open(self.passwd_fname, "r")
|
|
||||||
password = f.readline()
|
password = f.readline()
|
||||||
f.close()
|
new_args = ["/usr/bin/signtool", "-d", self.secdir, "-p", password]
|
||||||
new_args = ["/usr/bin/signtool", "-d", self.secdir, "-p", password]
|
|
||||||
else:
|
|
||||||
new_args = ["/usr/bin/signtool", "-d", self.secdir]
|
|
||||||
new_args = new_args + args
|
new_args = new_args + args
|
||||||
ipautil.run(new_args, stdin)
|
ipautil.run(new_args, stdin)
|
||||||
|
|
||||||
@ -585,41 +451,6 @@ class CertDB(object):
|
|||||||
|
|
||||||
return False
|
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):
|
def export_ca_cert(self, nickname, create_pkcs12=False):
|
||||||
"""create_pkcs12 tells us whether we should create a PKCS#12 file
|
"""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
|
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:
|
except ipautil.CalledProcessError:
|
||||||
return ''
|
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):
|
def track_server_cert(self, nickname, principal, password_file=None, command=None):
|
||||||
"""
|
"""
|
||||||
Tell certmonger to track the given certificate nickname.
|
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):
|
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 dogtag CA then other_certdb contains the RA agent key
|
||||||
|
|
||||||
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
|
|
||||||
that will issue our cert.
|
that will issue our cert.
|
||||||
|
|
||||||
You can override the certificate Subject by specifying a subject.
|
You can override the certificate Subject by specifying a subject.
|
||||||
@ -802,179 +618,117 @@ class CertDB(object):
|
|||||||
"-k", certtype,
|
"-k", certtype,
|
||||||
"-g", keysize,
|
"-g", keysize,
|
||||||
"-z", self.noise_fname,
|
"-z", self.noise_fname,
|
||||||
"-f", self.passwd_fname]
|
"-f", self.passwd_fname,
|
||||||
if not self.self_signed_ca:
|
"-a"]
|
||||||
args.append("-a")
|
|
||||||
(stdout, stderr, returncode) = self.run_certutil(args)
|
(stdout, stderr, returncode) = self.run_certutil(args)
|
||||||
os.remove(self.noise_fname)
|
os.remove(self.noise_fname)
|
||||||
return (stdout, stderr)
|
return (stdout, stderr)
|
||||||
|
|
||||||
def issue_server_cert(self, certreq_fname, cert_fname):
|
def issue_server_cert(self, certreq_fname, cert_fname):
|
||||||
self.setup_cert_request()
|
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
|
if self.host_name is None:
|
||||||
# control this with command line arguments.
|
raise RuntimeError("CA Host is not set.")
|
||||||
#
|
|
||||||
# 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.")
|
|
||||||
|
|
||||||
f = open(certreq_fname, "r")
|
f = open(certreq_fname, "r")
|
||||||
csr = f.readlines()
|
csr = f.readlines()
|
||||||
f.close()
|
f.close()
|
||||||
csr = "".join(csr)
|
csr = "".join(csr)
|
||||||
|
|
||||||
# We just want the CSR bits, make sure there is nothing else
|
# We just want the CSR bits, make sure there is nothing else
|
||||||
csr = pkcs10.strip_header(csr)
|
csr = pkcs10.strip_header(csr)
|
||||||
|
|
||||||
params = {'profileId': 'caIPAserviceCert',
|
params = {'profileId': 'caIPAserviceCert',
|
||||||
'cert_request_type': 'pkcs10',
|
'cert_request_type': 'pkcs10',
|
||||||
'requestor_name': 'IPA Installer',
|
'requestor_name': 'IPA Installer',
|
||||||
'cert_request': csr,
|
'cert_request': csr,
|
||||||
'xmlOutput': 'true'}
|
'xmlOutput': 'true'}
|
||||||
|
|
||||||
# Send the request to the CA
|
# Send the request to the CA
|
||||||
f = open(self.passwd_fname, "r")
|
f = open(self.passwd_fname, "r")
|
||||||
password = f.readline()
|
password = f.readline()
|
||||||
f.close()
|
f.close()
|
||||||
result = dogtag.https_request(
|
result = dogtag.https_request(
|
||||||
self.host_name,
|
self.host_name,
|
||||||
api.env.ca_ee_install_port or
|
api.env.ca_ee_install_port or
|
||||||
dogtag.configured_constants().EE_SECURE_PORT,
|
dogtag.configured_constants().EE_SECURE_PORT,
|
||||||
"/ca/ee/ca/profileSubmitSSLClient",
|
"/ca/ee/ca/profileSubmitSSLClient",
|
||||||
self.secdir, password, "ipaCert", **params)
|
self.secdir, password, "ipaCert", **params)
|
||||||
http_status, http_reason_phrase, http_headers, http_body = result
|
http_status, http_reason_phrase, http_headers, http_body = result
|
||||||
|
|
||||||
if http_status != 200:
|
if http_status != 200:
|
||||||
raise CertificateOperationError(
|
raise CertificateOperationError(
|
||||||
error=_('Unable to communicate with CMS (%s)') %
|
error=_('Unable to communicate with CMS (%s)') %
|
||||||
http_reason_phrase)
|
http_reason_phrase)
|
||||||
|
|
||||||
# The result is an XML blob. Pull the certificate out of that
|
# The result is an XML blob. Pull the certificate out of that
|
||||||
doc = xml.dom.minidom.parseString(http_body)
|
doc = xml.dom.minidom.parseString(http_body)
|
||||||
item_node = doc.getElementsByTagName("b64")
|
item_node = doc.getElementsByTagName("b64")
|
||||||
|
try:
|
||||||
try:
|
try:
|
||||||
try:
|
cert = item_node[0].childNodes[0].data
|
||||||
cert = item_node[0].childNodes[0].data
|
except IndexError:
|
||||||
except IndexError:
|
raise RuntimeError("Certificate issuance failed")
|
||||||
raise RuntimeError("Certificate issuance failed")
|
finally:
|
||||||
finally:
|
doc.unlink()
|
||||||
doc.unlink()
|
|
||||||
|
|
||||||
# base64-decode the result for uniformity
|
# base64-decode the result for uniformity
|
||||||
cert = base64.b64decode(cert)
|
cert = base64.b64decode(cert)
|
||||||
|
|
||||||
# Write the certificate to a file. It will be imported in a later
|
# Write the certificate to a file. It will be imported in a later
|
||||||
# step. This file will be read later to be imported.
|
# step. This file will be read later to be imported.
|
||||||
f = open(cert_fname, "w")
|
f = open(cert_fname, "w")
|
||||||
f.write(cert)
|
f.write(cert)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def issue_signing_cert(self, certreq_fname, cert_fname):
|
def issue_signing_cert(self, certreq_fname, cert_fname):
|
||||||
self.setup_cert_request()
|
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
|
if self.host_name is None:
|
||||||
# control this with command line arguments.
|
raise RuntimeError("CA Host is not set.")
|
||||||
#
|
|
||||||
# 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.")
|
|
||||||
|
|
||||||
f = open(certreq_fname, "r")
|
f = open(certreq_fname, "r")
|
||||||
csr = f.readlines()
|
csr = f.readlines()
|
||||||
f.close()
|
f.close()
|
||||||
csr = "".join(csr)
|
csr = "".join(csr)
|
||||||
|
|
||||||
# We just want the CSR bits, make sure there is no thing else
|
# We just want the CSR bits, make sure there is no thing else
|
||||||
csr = pkcs10.strip_header(csr)
|
csr = pkcs10.strip_header(csr)
|
||||||
|
|
||||||
params = {'profileId': 'caJarSigningCert',
|
params = {'profileId': 'caJarSigningCert',
|
||||||
'cert_request_type': 'pkcs10',
|
'cert_request_type': 'pkcs10',
|
||||||
'requestor_name': 'IPA Installer',
|
'requestor_name': 'IPA Installer',
|
||||||
'cert_request': csr,
|
'cert_request': csr,
|
||||||
'xmlOutput': 'true'}
|
'xmlOutput': 'true'}
|
||||||
|
|
||||||
# Send the request to the CA
|
# Send the request to the CA
|
||||||
f = open(self.passwd_fname, "r")
|
f = open(self.passwd_fname, "r")
|
||||||
password = f.readline()
|
password = f.readline()
|
||||||
f.close()
|
f.close()
|
||||||
result = dogtag.https_request(
|
result = dogtag.https_request(
|
||||||
self.host_name,
|
self.host_name,
|
||||||
api.env.ca_ee_install_port or
|
api.env.ca_ee_install_port or
|
||||||
dogtag.configured_constants().EE_SECURE_PORT,
|
dogtag.configured_constants().EE_SECURE_PORT,
|
||||||
"/ca/ee/ca/profileSubmitSSLClient",
|
"/ca/ee/ca/profileSubmitSSLClient",
|
||||||
self.secdir, password, "ipaCert", **params)
|
self.secdir, password, "ipaCert", **params)
|
||||||
http_status, http_reason_phrase, http_headers, http_body = result
|
http_status, http_reason_phrase, http_headers, http_body = result
|
||||||
if http_status != 200:
|
if http_status != 200:
|
||||||
raise RuntimeError("Unable to submit cert request")
|
raise RuntimeError("Unable to submit cert request")
|
||||||
|
|
||||||
# The result is an XML blob. Pull the certificate out of that
|
# The result is an XML blob. Pull the certificate out of that
|
||||||
doc = xml.dom.minidom.parseString(http_body)
|
doc = xml.dom.minidom.parseString(http_body)
|
||||||
item_node = doc.getElementsByTagName("b64")
|
item_node = doc.getElementsByTagName("b64")
|
||||||
cert = item_node[0].childNodes[0].data
|
cert = item_node[0].childNodes[0].data
|
||||||
doc.unlink()
|
doc.unlink()
|
||||||
|
|
||||||
# base64-decode the cert for uniformity
|
# base64-decode the cert for uniformity
|
||||||
cert = base64.b64decode(cert)
|
cert = base64.b64decode(cert)
|
||||||
|
|
||||||
# Write the certificate to a file. It will be imported in a later
|
# Write the certificate to a file. It will be imported in a later
|
||||||
# step. This file will be read later to be imported.
|
# step. This file will be read later to be imported.
|
||||||
f = open(cert_fname, "w")
|
f = open(cert_fname, "w")
|
||||||
f.write(cert)
|
f.write(cert)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def add_cert(self, cert_fname, nickname):
|
def add_cert(self, cert_fname, nickname):
|
||||||
"""
|
"""
|
||||||
@ -1020,48 +774,11 @@ class CertDB(object):
|
|||||||
"""
|
"""
|
||||||
root_nicknames = self.nssdb.get_trust_chain(nickname)
|
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
|
return root_nicknames
|
||||||
|
|
||||||
def find_root_cert_from_pkcs12(self, pkcs12_fname, passwd_fname=None):
|
def find_root_cert_from_pkcs12(self, pkcs12_fname, passwd_fname=None):
|
||||||
"""Given a PKCS#12 file, try to find any certificates that do
|
return self.nssdb.find_root_cert_from_pkcs12(pkcs12_fname,
|
||||||
not have a key. The assumption is that these are the root CAs.
|
passwd_fname=passwd_fname)
|
||||||
"""
|
|
||||||
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
|
|
||||||
|
|
||||||
def trust_root_cert(self, root_nickname):
|
def trust_root_cert(self, root_nickname):
|
||||||
if root_nickname is None:
|
if root_nickname is None:
|
||||||
@ -1097,14 +814,6 @@ class CertDB(object):
|
|||||||
"-in", pem_fname, "-out", pkcs12_fname,
|
"-in", pem_fname, "-out", pkcs12_fname,
|
||||||
"-passout", "file:" + pkcs12_pwd_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):
|
def create_from_cacert(self, cacert_fname, passwd=None):
|
||||||
if ipautil.file_exists(self.certdb_fname):
|
if ipautil.file_exists(self.certdb_fname):
|
||||||
# We already have a cert db, see if it is for the same CA.
|
# 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.create_pin_file()
|
||||||
self.export_ca_cert(nickname, False)
|
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):
|
def install_pem_from_p12(self, p12_fname, p12_pwd_fname, pem_fname):
|
||||||
ipautil.run(["/usr/bin/openssl", "pkcs12", "-nodes",
|
ipautil.run(["/usr/bin/openssl", "pkcs12", "-nodes",
|
||||||
|
@ -36,7 +36,7 @@ import certs
|
|||||||
import ldap
|
import ldap
|
||||||
from ipaserver.install import ldapupdate
|
from ipaserver.install import ldapupdate
|
||||||
from ipaserver.install import replication
|
from ipaserver.install import replication
|
||||||
from ipalib import errors, api
|
from ipalib import errors
|
||||||
from ipapython.dn import DN
|
from ipapython.dn import DN
|
||||||
|
|
||||||
SERVER_ROOT_64 = "/usr/lib64/dirsrv"
|
SERVER_ROOT_64 = "/usr/lib64/dirsrv"
|
||||||
@ -228,8 +228,7 @@ class DsInstance(service.Service):
|
|||||||
self.step("configuring directory to start on boot", self.__enable)
|
self.step("configuring directory to start on boot", self.__enable)
|
||||||
|
|
||||||
def init_info(self, realm_name, fqdn, domain_name, dm_password,
|
def init_info(self, realm_name, fqdn, domain_name, dm_password,
|
||||||
self_signed_ca, subject_base, idstart, idmax, pkcs12_info,
|
subject_base, idstart, idmax, pkcs12_info, ca_file=None):
|
||||||
ca_file=None):
|
|
||||||
self.realm_name = realm_name.upper()
|
self.realm_name = realm_name.upper()
|
||||||
self.serverid = realm_to_serverid(self.realm_name)
|
self.serverid = realm_to_serverid(self.realm_name)
|
||||||
self.suffix = ipautil.realm_to_suffix(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.dm_password = dm_password
|
||||||
self.domain = domain_name
|
self.domain = domain_name
|
||||||
self.principal = "ldap/%s@%s" % (self.fqdn, self.realm_name)
|
self.principal = "ldap/%s@%s" % (self.fqdn, self.realm_name)
|
||||||
self.self_signed_ca = False
|
|
||||||
self.subject_base = subject_base
|
self.subject_base = subject_base
|
||||||
self.idstart = idstart
|
self.idstart = idstart
|
||||||
self.idmax = idmax
|
self.idmax = idmax
|
||||||
@ -247,11 +245,11 @@ class DsInstance(service.Service):
|
|||||||
self.__setup_sub_dict()
|
self.__setup_sub_dict()
|
||||||
|
|
||||||
def create_instance(self, realm_name, fqdn, domain_name,
|
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,
|
idstart=1100, idmax=999999, subject_base=None,
|
||||||
hbac_allow=True, ca_file=None):
|
hbac_allow=True, ca_file=None):
|
||||||
self.init_info(
|
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)
|
subject_base, idstart, idmax, pkcs12_info, ca_file=ca_file)
|
||||||
|
|
||||||
self.__common_setup()
|
self.__common_setup()
|
||||||
@ -282,7 +280,7 @@ class DsInstance(service.Service):
|
|||||||
idmax = 1100
|
idmax = 1100
|
||||||
|
|
||||||
self.init_info(
|
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)
|
idstart, idmax, pkcs12_info, ca_file=ca_file)
|
||||||
self.master_fqdn = master_fqdn
|
self.master_fqdn = master_fqdn
|
||||||
|
|
||||||
@ -545,30 +543,21 @@ class DsInstance(service.Service):
|
|||||||
# We only handle one server cert
|
# We only handle one server cert
|
||||||
nickname = server_certs[0][0]
|
nickname = server_certs[0][0]
|
||||||
self.dercert = dsdb.get_cert_from_db(nickname, pem=False)
|
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(
|
'restart_dirsrv %s' % self.serverid)
|
||||||
nickname, self.principal, dsdb.passwd_fname,
|
|
||||||
'restart_dirsrv %s' % self.serverid)
|
|
||||||
else:
|
else:
|
||||||
nickname = self.nickname
|
nickname = self.nickname
|
||||||
cadb = certs.CertDB(self.realm_name, host_name=self.fqdn, subject_base=self.subject_base)
|
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)
|
# FIXME, need to set this nickname in the RA plugin
|
||||||
self.dercert = dsdb.create_server_cert(nickname, self.fqdn, cadb)
|
cadb.export_ca_cert('ipaCert', False)
|
||||||
dsdb.track_server_cert(
|
dsdb.create_from_cacert(cadb.cacert_fname, passwd=None)
|
||||||
nickname, self.principal, dsdb.passwd_fname,
|
self.dercert = dsdb.create_server_cert(
|
||||||
'restart_dirsrv %s' % self.serverid)
|
nickname, self.fqdn, cadb)
|
||||||
dsdb.create_pin_file()
|
dsdb.track_server_cert(
|
||||||
else:
|
nickname, self.principal, dsdb.passwd_fname,
|
||||||
# FIXME, need to set this nickname in the RA plugin
|
'restart_dirsrv %s' % self.serverid)
|
||||||
cadb.export_ca_cert('ipaCert', False)
|
dsdb.create_pin_file()
|
||||||
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()
|
|
||||||
|
|
||||||
conn = ipaldap.IPAdmin(self.fqdn)
|
conn = ipaldap.IPAdmin(self.fqdn)
|
||||||
conn.do_simple_bind(DN(('cn', 'directory manager')), self.dm_password)
|
conn.do_simple_bind(DN(('cn', 'directory manager')), self.dm_password)
|
||||||
|
@ -63,15 +63,13 @@ class HTTPInstance(service.Service):
|
|||||||
|
|
||||||
def create_instance(self, realm, fqdn, domain_name, dm_password=None,
|
def create_instance(self, realm, fqdn, domain_name, dm_password=None,
|
||||||
autoconfig=True, pkcs12_info=None,
|
autoconfig=True, pkcs12_info=None,
|
||||||
self_signed_ca=False, subject_base=None,
|
subject_base=None, auto_redirect=True, ca_file=None):
|
||||||
auto_redirect=True, ca_file=None):
|
|
||||||
self.fqdn = fqdn
|
self.fqdn = fqdn
|
||||||
self.realm = realm
|
self.realm = realm
|
||||||
self.domain = domain_name
|
self.domain = domain_name
|
||||||
self.dm_password = dm_password
|
self.dm_password = dm_password
|
||||||
self.suffix = ipautil.realm_to_suffix(self.realm)
|
self.suffix = ipautil.realm_to_suffix(self.realm)
|
||||||
self.pkcs12_info = pkcs12_info
|
self.pkcs12_info = pkcs12_info
|
||||||
self.self_signed_ca = self_signed_ca
|
|
||||||
self.principal = "HTTP/%s@%s" % (self.fqdn, self.realm)
|
self.principal = "HTTP/%s@%s" % (self.fqdn, self.realm)
|
||||||
self.dercert = None
|
self.dercert = None
|
||||||
self.subject_base = subject_base
|
self.subject_base = subject_base
|
||||||
@ -237,9 +235,7 @@ class HTTPInstance(service.Service):
|
|||||||
print "Adding Include conf.d/ipa-rewrite to %s failed." % NSS_CONF
|
print "Adding Include conf.d/ipa-rewrite to %s failed." % NSS_CONF
|
||||||
|
|
||||||
def __setup_ssl(self):
|
def __setup_ssl(self):
|
||||||
fqdn = None
|
fqdn = self.fqdn
|
||||||
if not self.self_signed_ca:
|
|
||||||
fqdn = self.fqdn
|
|
||||||
|
|
||||||
ca_db = certs.CertDB(self.realm, host_name=fqdn, subject_base=self.subject_base)
|
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)
|
self.__set_mod_nss_nickname(nickname)
|
||||||
else:
|
else:
|
||||||
if self.self_signed_ca:
|
|
||||||
db.create_from_cacert(ca_db.cacert_fname)
|
|
||||||
|
|
||||||
db.create_password_conf()
|
db.create_password_conf()
|
||||||
self.dercert = db.create_server_cert(self.cert_nickname, self.fqdn,
|
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 + "/cert8.db")
|
||||||
ipaservices.restore_context(certs.NSS_DIR + "/key3.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):
|
def __setup_autoconfig(self):
|
||||||
target_fname = '/usr/share/ipa/html/preferences.html'
|
target_fname = '/usr/share/ipa/html/preferences.html'
|
||||||
ipautil.copy_template_file(
|
ipautil.copy_template_file(
|
||||||
|
@ -130,13 +130,6 @@ class ReplicaPrepare(admintool.AdminTool):
|
|||||||
if api.env.host == self.replica_fqdn:
|
if api.env.host == self.replica_fqdn:
|
||||||
raise admintool.ScriptError("You can't create a replica on itself")
|
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:
|
if not api.env.enable_ra and not options.http_pkcs12:
|
||||||
raise admintool.ScriptError(
|
raise admintool.ScriptError(
|
||||||
"Cannot issue certificates: a CA is not installed. Use the "
|
"Cannot issue certificates: a CA is not installed. Use the "
|
||||||
@ -227,8 +220,7 @@ class ReplicaPrepare(admintool.AdminTool):
|
|||||||
options.reverse_zone, options.ip_address):
|
options.reverse_zone, options.ip_address):
|
||||||
raise admintool.ScriptError("Invalid reverse zone")
|
raise admintool.ScriptError("Invalid reverse zone")
|
||||||
|
|
||||||
if (not certs.ipa_self_signed() and
|
if (not ipautil.file_exists(
|
||||||
not ipautil.file_exists(
|
|
||||||
dogtag.configured_constants().CS_CFG_PATH) and
|
dogtag.configured_constants().CS_CFG_PATH) and
|
||||||
not options.dirsrv_pin):
|
not options.dirsrv_pin):
|
||||||
self.log.info("If you installed IPA with your own certificates "
|
self.log.info("If you installed IPA with your own certificates "
|
||||||
@ -281,17 +273,17 @@ class ReplicaPrepare(admintool.AdminTool):
|
|||||||
options.dirsrv_pkcs12)
|
options.dirsrv_pkcs12)
|
||||||
self.copy_info_file(options.dirsrv_pkcs12, "dscert.p12")
|
self.copy_info_file(options.dirsrv_pkcs12, "dscert.p12")
|
||||||
else:
|
else:
|
||||||
if not certs.ipa_self_signed():
|
if ipautil.file_exists(options.ca_file):
|
||||||
if ipautil.file_exists(options.ca_file):
|
self.copy_info_file(options.ca_file, "cacert.p12")
|
||||||
self.copy_info_file(options.ca_file, "cacert.p12")
|
else:
|
||||||
else:
|
raise admintool.ScriptError("Root CA PKCS#12 not "
|
||||||
raise admintool.ScriptError("Root CA PKCS#12 not "
|
"found in %s" % options.ca_file)
|
||||||
"found in %s" % options.ca_file)
|
|
||||||
self.log.info(
|
self.log.info(
|
||||||
"Creating SSL certificate for the Directory Server")
|
"Creating SSL certificate for the Directory Server")
|
||||||
self.export_certdb("dscert", passwd_fname)
|
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(
|
self.log.info(
|
||||||
"Creating SSL certificate for the dogtag Directory Server")
|
"Creating SSL certificate for the dogtag Directory Server")
|
||||||
self.export_certdb("dogtagcert", passwd_fname)
|
self.export_certdb("dogtagcert", passwd_fname)
|
||||||
@ -318,8 +310,7 @@ class ReplicaPrepare(admintool.AdminTool):
|
|||||||
self.export_certdb("httpcert", passwd_fname)
|
self.export_certdb("httpcert", passwd_fname)
|
||||||
|
|
||||||
self.log.info("Exporting RA certificate")
|
self.log.info("Exporting RA certificate")
|
||||||
if not certs.ipa_self_signed():
|
self.export_ra_pkcs12()
|
||||||
self.export_ra_pkcs12()
|
|
||||||
|
|
||||||
def copy_pkinit_certificate(self):
|
def copy_pkinit_certificate(self):
|
||||||
options = self.options
|
options = self.options
|
||||||
@ -464,19 +455,14 @@ class ReplicaPrepare(admintool.AdminTool):
|
|||||||
nickname = "Server-Cert"
|
nickname = "Server-Cert"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self_signed = certs.ipa_self_signed()
|
|
||||||
|
|
||||||
db = certs.CertDB(
|
db = certs.CertDB(
|
||||||
api.env.realm, nssdir=self.dir, subject_base=subject_base)
|
api.env.realm, nssdir=self.dir, subject_base=subject_base)
|
||||||
db.create_passwd_file()
|
db.create_passwd_file()
|
||||||
ca_db = certs.CertDB(
|
ca_db = certs.CertDB(
|
||||||
api.env.realm, host_name=api.env.host,
|
api.env.realm, host_name=api.env.host,
|
||||||
subject_base=subject_base)
|
subject_base=subject_base)
|
||||||
if is_kdc:
|
db.create_from_cacert(ca_db.cacert_fname)
|
||||||
ca_db.create_kdc_cert("KDC-Cert", hostname, self.dir)
|
db.create_server_cert(nickname, hostname, ca_db)
|
||||||
else:
|
|
||||||
db.create_from_cacert(ca_db.cacert_fname)
|
|
||||||
db.create_server_cert(nickname, hostname, ca_db)
|
|
||||||
|
|
||||||
pkcs12_fname = os.path.join(self.dir, fname + ".p12")
|
pkcs12_fname = os.path.join(self.dir, fname + ".p12")
|
||||||
|
|
||||||
|
@ -81,7 +81,6 @@ class KrbInstance(service.Service):
|
|||||||
self.kdc_password = None
|
self.kdc_password = None
|
||||||
self.sub_dict = None
|
self.sub_dict = None
|
||||||
self.pkcs12_info = None
|
self.pkcs12_info = None
|
||||||
self.self_signed_ca = None
|
|
||||||
|
|
||||||
if fstore:
|
if fstore:
|
||||||
self.fstore = fstore
|
self.fstore = fstore
|
||||||
@ -158,10 +157,9 @@ class KrbInstance(service.Service):
|
|||||||
self.step("starting the KDC", self.__start_instance)
|
self.step("starting the KDC", self.__start_instance)
|
||||||
self.step("configuring KDC to start on boot", self.__enable)
|
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.master_password = master_password
|
||||||
self.pkcs12_info = pkcs12_info
|
self.pkcs12_info = pkcs12_info
|
||||||
self.self_signed_ca = self_signed_ca
|
|
||||||
self.subject_base = subject_base
|
self.subject_base = subject_base
|
||||||
|
|
||||||
self.__common_setup(realm_name, host_name, domain_name, admin_password)
|
self.__common_setup(realm_name, host_name, domain_name, admin_password)
|
||||||
@ -189,9 +187,8 @@ class KrbInstance(service.Service):
|
|||||||
master_fqdn, host_name,
|
master_fqdn, host_name,
|
||||||
domain_name, admin_password,
|
domain_name, admin_password,
|
||||||
setup_pkinit=False, pkcs12_info=None,
|
setup_pkinit=False, pkcs12_info=None,
|
||||||
self_signed_ca=False, subject_base=None):
|
subject_base=None):
|
||||||
self.pkcs12_info = pkcs12_info
|
self.pkcs12_info = pkcs12_info
|
||||||
self.self_signed_ca = self_signed_ca
|
|
||||||
self.subject_base = subject_base
|
self.subject_base = subject_base
|
||||||
self.master_fqdn = master_fqdn
|
self.master_fqdn = master_fqdn
|
||||||
|
|
||||||
@ -412,23 +409,15 @@ class KrbInstance(service.Service):
|
|||||||
self.move_service_to_host(host_principal)
|
self.move_service_to_host(host_principal)
|
||||||
|
|
||||||
def __setup_pkinit(self):
|
def __setup_pkinit(self):
|
||||||
if self.self_signed_ca:
|
ca_db = certs.CertDB(self.realm, host_name=self.fqdn,
|
||||||
ca_db = certs.CertDB(self.realm,
|
subject_base=self.subject_base)
|
||||||
subject_base=self.subject_base)
|
|
||||||
else:
|
|
||||||
ca_db = certs.CertDB(self.realm, host_name=self.fqdn,
|
|
||||||
subject_base=self.subject_base)
|
|
||||||
|
|
||||||
if self.pkcs12_info:
|
if self.pkcs12_info:
|
||||||
ca_db.install_pem_from_p12(self.pkcs12_info[0],
|
ca_db.install_pem_from_p12(self.pkcs12_info[0],
|
||||||
self.pkcs12_info[1],
|
self.pkcs12_info[1],
|
||||||
"/var/kerberos/krb5kdc/kdc.pem")
|
"/var/kerberos/krb5kdc/kdc.pem")
|
||||||
else:
|
else:
|
||||||
if self.self_signed_ca:
|
raise RuntimeError("PKI not supported yet\n")
|
||||||
ca_db.create_kdc_cert("KDC-Cert", self.fqdn,
|
|
||||||
"/var/kerberos/krb5kdc")
|
|
||||||
else:
|
|
||||||
raise RuntimeError("PKI not supported yet\n")
|
|
||||||
|
|
||||||
# Finally copy the cacert in the krb directory so we don't
|
# Finally copy the cacert in the krb directory so we don't
|
||||||
# have any selinux issues with the file context
|
# have any selinux issues with the file context
|
||||||
|
@ -44,11 +44,9 @@ class rabase(Backend):
|
|||||||
if api.env.in_tree:
|
if api.env.in_tree:
|
||||||
self.sec_dir = api.env.dot_ipa + os.sep + 'alias'
|
self.sec_dir = api.env.dot_ipa + os.sep + 'alias'
|
||||||
self.pwd_file = self.sec_dir + os.sep + '.pwd'
|
self.pwd_file = self.sec_dir + os.sep + '.pwd'
|
||||||
self.serial_file = self.sec_dir + os.sep + 'ca_serialno'
|
|
||||||
else:
|
else:
|
||||||
self.sec_dir = "/etc/httpd/alias"
|
self.sec_dir = "/etc/httpd/alias"
|
||||||
self.pwd_file = "/etc/httpd/alias/pwdfile.txt"
|
self.pwd_file = "/etc/httpd/alias/pwdfile.txt"
|
||||||
self.serial_file = certs.CA_SERIALNO
|
|
||||||
super(rabase, self).__init__()
|
super(rabase, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
|
@ -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)
|
|
Loading…
Reference in New Issue
Block a user