diff options
Diffstat (limited to 'ipaserver/plugins')
-rw-r--r-- | ipaserver/plugins/dogtag.py (renamed from ipaserver/plugins/ra.py) | 50 | ||||
-rw-r--r-- | ipaserver/plugins/rabase.py | 113 | ||||
-rw-r--r-- | ipaserver/plugins/selfsign.py | 126 |
3 files changed, 253 insertions, 36 deletions
diff --git a/ipaserver/plugins/ra.py b/ipaserver/plugins/dogtag.py index 1238f5036..2b1e84e7a 100644 --- a/ipaserver/plugins/ra.py +++ b/ipaserver/plugins/dogtag.py @@ -20,39 +20,22 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -Backend plugin for IPA-RA. - -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. +Backend plugin for RA using Dogtag. """ from ipalib import api, SkipPluginModule -if api.env.enable_ra is not True: +if api.env.ra_plugin != 'dogtag': # In this case, abort loading this plugin module... - raise SkipPluginModule(reason='env.enable_ra is not True') -import os, stat, subprocess -import array -import errno -import binascii + raise SkipPluginModule(reason='dogtag not selected as RA plugin') +import os from httplib import HTTPConnection -from urllib import urlencode, quote -from socket import gethostname +from urllib import urlencode +from ipaserver.plugins import rabase import socket -from ipalib import Backend from ipalib.errors import NetworkError -from ipaserver import servercore -from ipaserver import ipaldap from ipalib.constants import TYPE_ERROR from ipapython import nsslib import nss.nss as nss -import nss.ssl as ssl -from nss.error import NSPRError import xml.dom.minidom def get_xml_value(doc, tagname): @@ -62,7 +45,7 @@ def get_xml_value(doc, tagname): except IndexError: return None -class ra(Backend): +class ra(rabase.rabase): """ Request Authority backend plugin. """ @@ -110,29 +93,20 @@ class ra(Backend): self.debug('request data %s', data) return (status, reason, data) - def _sslget(self, url, **kw): + def _sslget(self, url, port, **kw): """ Perform an HTTPS request :param url: The URL to post to. :param kw: Keyword arguments to encode into POST body. """ - uri = 'https://%s:%d%s' % (self.env.ca_host, self.env.ca_ssl_port, url) + uri = 'https://%s:%d%s' % (self.env.ca_host, port, url) post = urlencode(kw) self.info('sslget %r', uri) self.debug('sslget post %r', post) - argv = [ - '/usr/bin/sslget', - '-n', self.ipa_certificate_nickname, # nickname - '-w', self.pwd_file, # pwfile - '-d', self.sec_dir, # dbdir - '-e', post, # post - '-r', url, # url - '%s:%d' % (self.env.ca_host, self.env.ca_ssl_port), - ] headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"} - conn = nsslib.NSSConnection(self.env.ca_host, self.env.ca_ssl_port, dbdir=self.sec_dir) + conn = nsslib.NSSConnection(self.env.ca_host, port, dbdir=self.sec_dir) conn.sslsock.set_client_auth_data_callback(nsslib.client_auth_data_callback, self.ipa_certificate_nickname, self.password, nss.get_default_certdb()) conn.set_debuglevel(10) conn.request("POST", url, post, headers) @@ -194,6 +168,7 @@ class ra(Backend): issued_certificate = None (status, reason, stdout) = self._sslget( '/ca/agent/ca/displayBySerial', + self.env.ca_agent_port, serialNumber=serial_number, xmlOutput='true', ) @@ -229,6 +204,7 @@ class ra(Backend): self.debug('%s.request_certificate()', self.fullname) certificate = None (status, reason, stdout) = self._sslget('/ca/ee/ca/profileSubmit', + self.env.ca_ee_port, profileId='caRAserverCert', cert_request_type=request_type, cert_request=csr, @@ -292,6 +268,7 @@ class ra(Backend): ) response = {} (status, reason, stdout) = self._sslget('/ca/agent/ca/doRevoke', + self.env.ca_agent_port, op='revoke', revocationReason=revocation_reason, revokeAll='(certRecordId=%s)' % serial_number, @@ -316,6 +293,7 @@ class ra(Backend): response = {} self.debug('%s.take_certificate_off_hold()', self.fullname) (status, reason, stdout) = self._sslget('/ca/agent/ca/doUnrevoke', + self.env.ca_agent_port, serialNumber=serial_number, ) if (status == 0): diff --git a/ipaserver/plugins/rabase.py b/ipaserver/plugins/rabase.py new file mode 100644 index 000000000..3fc0ec5cd --- /dev/null +++ b/ipaserver/plugins/rabase.py @@ -0,0 +1,113 @@ +# Authors: +# Rob Crittenden <rcritten@@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; version 2 only +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" +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 +from ipalib import Backend +from ipalib import errors +from ipaserver.install import certs +import os + +class rabase(Backend): + """ + Request Authority backend plugin. + """ + def __init__(self): + if api.env.home: + 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__() + + + def check_request_status(self, request_id): + """ + Check status of a certificate signing request. + + :param request_id: request ID + """ + raise errors.NotImplementedError(name='%s.check_request_status' % self.name) + + def get_certificate(self, serial_number=None): + """ + Retrieve an existing certificate. + + :param serial_number: certificate serial number + """ + raise errors.NotImplementedError(name='%s.check_request_status' % self.name) + + def request_certificate(self, csr, request_type='pkcs10'): + """ + Submit certificate signing request. + + :param csr: The certificate signing request. + :param request_type: The request type (defaults to ``'pkcs10'``). + """ + raise errors.NotImplementedError(name='%s.check_request_status' % self.name) + + def revoke_certificate(self, serial_number, revocation_reason=0): + """ + Revoke a certificate. + + The integer ``revocation_reason`` code must have one of these values: + + * ``0`` - unspecified + * ``1`` - keyCompromise + * ``2`` - cACompromise + * ``3`` - affiliationChanged + * ``4`` - superseded + * ``5`` - cessationOfOperation + * ``6`` - certificateHold + * ``8`` - removeFromCRL + * ``9`` - privilegeWithdrawn + * ``10`` - aACompromise + + Note that reason code ``7`` is not used. See RFC 5280 for more details: + + http://www.ietf.org/rfc/rfc5280.txt + + :param serial_number: Certificate serial number. + :param revocation_reason: Integer code of revocation reason. + """ + raise errors.NotImplementedError(name='%s.check_request_status' % self.name) + + def take_certificate_off_hold(self, serial_number): + """ + Take revoked certificate off hold. + + :param serial_number: Certificate serial number. + """ + raise errors.NotImplementedError('%s.check_request_status' % self.name) + diff --git a/ipaserver/plugins/selfsign.py b/ipaserver/plugins/selfsign.py new file mode 100644 index 000000000..4bec0665a --- /dev/null +++ b/ipaserver/plugins/selfsign.py @@ -0,0 +1,126 @@ +# Authors: +# Rob Crittenden <rcritten@@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; version 2 only +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" +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 +import subprocess +import os +from ipaserver.plugins import rabase +from ipaserver.install import certs +import tempfile +from OpenSSL import crypto + +class ra(rabase.rabase): + """ + Request Authority backend plugin. + """ + + def request_certificate(self, csr, request_type='pkcs10'): + """ + Submit certificate signing request. + + :param csr: The certificate signing request. + :param request_type: The request type (defaults to ``'pkcs10'``). + """ + (csr_fd, csr_name) = tempfile.mkstemp() + os.write(csr_fd, csr) + os.close(csr_fd) + (cert_fd, cert_name) = tempfile.mkstemp() + os.close(cert_fd) + + serialno = certs.next_serial(self.serial_file) + + try: + args = [ + "/usr/bin/certutil", + "-C", + "-d", self.sec_dir, + "-c", "CA certificate", + "-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() + self.log.debug("stdout = %s" % stdout) + self.log.debug("stderr = %s" % stderr) + finally: + os.remove(csr_name) + + try: + cert_fd = open(cert_name) + cert = cert_fd.read() + cert_fd.close() + finally: + os.remove(cert_name) + + try: + # Grab the subject, reverse it, combine it and return it + x509 = crypto.load_certificate(crypto.FILETYPE_PEM, cert) + sub = x509.get_subject().get_components() + sub.reverse() + subject = "" + for s in sub: + subject = subject + "%s=%s," % (s[0], s[1]) + subject = subject[:-1] + + serial = x509.get_serial_number() + except crypto.Error, e: + raise errors.GenericError(format='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] + + return {'status':0, 'subject': subject, 'certificate':cert, 'serial': "0x%x" % serial} + +api.register(ra) |