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.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
|
||||
|
@ -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)
|
||||
|
@ -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})
|
||||
|
@ -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",
|
||||
|
@ -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)
|
||||
|
@ -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(
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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")
|
||||
|
||||
|
@ -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__()
|
||||
|
||||
|
||||
|
@ -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