pkcs10: remove pyasn1 PKCS #10 spec

In the dogtag-ipa-ca-renew-agent-submit certmonger renewal helper,
we currently use our hand-rolled PKCS #10 pyasn1 specification to
parse the friendlyName out of CSRs generated by certmonger (it
contains the NSSDB nickname of the cert).

Use other information from the renewal helper process environment to
determine the nickname and remove our PKCS #10 pyasn1 spec.

Part of: https://fedorahosted.org/freeipa/ticket/6398

Reviewed-By: Jan Cholasta <jcholast@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
This commit is contained in:
Fraser Tweedale 2016-10-12 11:03:56 +10:00 committed by David Kupka
parent 66637f766d
commit 85487281cd
2 changed files with 36 additions and 66 deletions

View File

@ -39,10 +39,10 @@ import six
from ipapython import ipautil
from ipapython.dn import DN
from ipalib import api, errors, pkcs10, x509
from ipalib import api, errors, x509
from ipaplatform.paths import paths
from ipaserver.plugins.ldap2 import ldap2
from ipaserver.install import cainstance, certs
from ipaserver.install import cainstance, dsinstance, certs
# This is a certmonger CA helper script for IPA CA subsystem cert renewal. See
# https://git.fedorahosted.org/cgit/certmonger.git/tree/doc/submit.txt for more
@ -65,8 +65,36 @@ if six.PY3:
IPA_CA_NICKNAME = 'caSigningCert cert-pki-ca'
def get_nickname():
csr = os.environ.get('CERTMONGER_CSR')
return pkcs10.get_friendlyname(csr) if csr else None
subject = os.environ.get('CERTMONGER_REQ_SUBJECT')
if not subject:
return None
subject_base = dsinstance.DsInstance().find_subject_base()
if not subject_base:
return None
nickname_by_subject_dn = {
DN('CN=Certificate Authority', subject_base):
'caSigningCert cert-pki-ca',
DN('CN=CA Audit', subject_base): 'auditSigningCert cert-pki-ca',
DN('CN=OCSP Subsystem', subject_base): 'ocspSigningCert cert-pki-ca',
DN('CN=CA Subsystem', subject_base): 'subsystemCert cert-pki-ca',
DN('CN=KRA Audit', subject_base): 'auditSigningCert cert-pki-kra',
DN('CN=KRA Transport Certificate', subject_base):
'transportCert cert-pki-kra',
DN('CN=KRA Storage Certificate', subject_base):
'storageCert cert-pki-kra',
DN('CN=IPA RA', subject_base): 'ipaCert',
}
try:
return nickname_by_subject_dn[DN(subject)]
except KeyError:
cas = api.Command.ca_find(ipacasubjectdn=DN(subject))['result']
if len(cas) == 0:
return None
return 'caSigningCert cert-pki-ca {}'.format(cas[0]['ipacaid'][0])
def is_lightweight_ca():
nickname = get_nickname() or ''
@ -216,13 +244,9 @@ def store_cert():
else:
return (OPERATION_NOT_SUPPORTED_BY_HELPER,)
csr = os.environ.get('CERTMONGER_CSR')
if not csr:
return (UNCONFIGURED, "Certificate request not provided")
nickname = pkcs10.get_friendlyname(csr)
nickname = get_nickname()
if not nickname:
return (REJECTED, "No friendly name in the certificate request")
return (REJECTED, "Nickname could not be determined")
cert = os.environ.get('CERTMONGER_CERTIFICATE')
if not cert:
@ -325,13 +349,9 @@ def retrieve_or_reuse_cert():
Retrieve certificate from LDAP. If the certificate is not available, reuse
the old certificate.
"""
csr = os.environ.get('CERTMONGER_CSR')
if not csr:
return (UNCONFIGURED, "Certificate request not provided")
nickname = pkcs10.get_friendlyname(csr)
nickname = get_nickname()
if not nickname:
return (REJECTED, "No friendly name in the certificate request")
return (REJECTED, "Nickname could not be determined")
cert = os.environ.get('CERTMONGER_CERTIFICATE')
if not cert:

View File

@ -23,57 +23,8 @@ import binascii
import sys
from cryptography.hazmat.backends import default_backend
import cryptography.x509
from pyasn1.type import univ, namedtype, tag
from pyasn1.codec.der import decoder
# Unfortunately, NSS can only parse the extension request attribute, so
# we have to parse friendly name ourselves (see RFC 2986)
class _Attribute(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('type', univ.ObjectIdentifier()),
namedtype.NamedType('values', univ.Set()),
)
class _Attributes(univ.SetOf):
componentType = _Attribute()
class _CertificationRequestInfo(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('version', univ.Integer()),
namedtype.NamedType('subject', univ.Sequence()),
namedtype.NamedType('subjectPublicKeyInfo', univ.Sequence()),
namedtype.OptionalNamedType('attributes', _Attributes().subtype(
implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
)
class _CertificationRequest(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('certificationRequestInfo',
_CertificationRequestInfo()),
namedtype.NamedType('signatureAlgorithm', univ.Sequence()),
namedtype.NamedType('signatureValue', univ.BitString()),
)
_FRIENDLYNAME = univ.ObjectIdentifier('1.2.840.113549.1.9.20')
def get_friendlyname(csr, datatype=PEM):
"""
Given a CSR return the value of the friendlyname attribute, if any.
The return value is a string.
"""
if datatype == PEM:
csr = strip_header(csr)
csr = base64.b64decode(csr)
csr = decoder.decode(csr, asn1Spec=_CertificationRequest())[0]
for attribute in csr['certificationRequestInfo']['attributes']:
if attribute['type'] == _FRIENDLYNAME:
return unicode(attribute['values'][0])
return None
def strip_header(csr):
"""
Remove the header and footer from a CSR.
@ -113,4 +64,3 @@ if __name__ == '__main__':
csr = ''.join(csrlines)
print(load_certificate_request(csr))
print(get_friendlyname(csr))