Merge "Don't accept unknown extensions"

This commit is contained in:
Jenkins 2015-09-28 10:49:34 +00:00 committed by Gerrit Code Review
commit 5b2fa7a5f1
4 changed files with 114 additions and 4 deletions

View File

@ -204,9 +204,10 @@ class X509Certificate(signature.SignatureMixin):
self._cert['tbsCertificate']['extensions'] = None
return self._cert['tbsCertificate']['extensions']
def get_extensions(self):
def get_extensions(self, ext_type=None):
extensions = self._get_extensions()
return [extension.construct_extension(e) for e in extensions]
return [extension.construct_extension(e) for e in extensions
if ext_type is None or e['extnID'] == ext_type._oid]
def add_extension(self, ext, index):
"""Add an X509 V3 Certificate extension.

View File

@ -24,6 +24,7 @@ from webob import exc as http_status
from anchor import jsonloader
from anchor import validators
from anchor.X509 import certificate
from anchor.X509 import extension
from anchor.X509 import signing_request
from anchor.X509 import utils
@ -267,8 +268,20 @@ def sign(csr, ca_conf):
exts = csr.get_extensions()
for i, ext in enumerate(exts):
logger.info("Adding certificate extension: %i %s", i, str(ext))
new_cert.add_extension(ext, i)
# this check is separate from standards validator - the signing backend
# may know about more/fewer extensions than we do
if ext.get_oid() not in extension.EXTENSION_CLASSES.keys():
if ext.get_critical():
logger.warning("CSR submitted with unknown extension oid %s, "
"refusing to sign", ext.get_oid())
raise SigningError("Unknown critical extension %s" % (
ext.get_oid(),))
else:
logger.info("CSR submitted with non-critical unknown oid %s, "
"not including extension", (ext.get_oid(),))
else:
logger.info("Adding certificate extension: %i %s", i, str(ext))
new_cert.add_extension(ext, i)
logger.info("Signing certificate for <%s> with serial <%s>",
csr.get_subject(), serial)

View File

@ -19,6 +19,9 @@ anchor
The default signing backend. It doesn't have any external service dependencies
and all signing happens inside of the Anchor process.
This backend will ignore all non-critical extensions which are not understood
by Anchor and will reject CSRs with unknown critical extensions.
A sample configuration for the ``signing_ca`` block looks like this:
.. code:: json

View File

@ -0,0 +1,93 @@
# -*- coding:utf-8 -*-
#
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import textwrap
import unittest
from pyasn1.type import univ as asn1_univ
from anchor import certificate_ops
from anchor.X509 import certificate
from anchor.X509 import extension
from anchor.X509 import signing_request
import tests
class UnknownExtension(extension.X509Extension):
_oid = asn1_univ.ObjectIdentifier("1.2.3.4")
spec = asn1_univ.Null
class SigningBackendExtensions(tests.DefaultConfigMixin, unittest.TestCase):
csr_data = textwrap.dedent(u"""
-----BEGIN CERTIFICATE REQUEST-----
MIIEsDCCApgCAQAwazELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWEx
FjAUBgNVBAcTDU1vdW50YWluIFZpZXcxDTALBgNVBAoTBEFjbWUxIDAeBgNVBAMT
F2FuY2hvci10ZXN0LmV4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
MIICCgKCAgEAvRri1XL/BIR882HdRisntITkEwDmBUmNcVKioOOc6wfLDzhrDFZc
fo34CvSPm4q4qlnGd4mmJt6rmDwZFhp4PPWHvZ4XWNygI0hZK3P+R6YZWOe2EwCU
M2+yCLLDAVucQZmqFtKLv3fedjM3udgEHrf6rf8eyE9X0eyXGJ7jNLEQvJktpr6v
JrKnMVssyzUXek4ZiWUoMY864MYeG+ZbdeHzSCMC9iCdfQIdTGUJ0SclOPoRPSUu
zyTE4FfDFLCZof6gcYudpdSK4Iy84G89kIb1Yfdvg5ak71uMtPRxSncsbfg4TK8r
WuyXs4alIA5bunhf89b6zt3BKufTzs6jBi9oLertafPW9Xgl2PbIeyN9JH1207/L
EnXpTS5XK/SDRnzkKCe9aSHy+mS77bRQjV+U67V+TVc9OrbZYQ5krHb3mlWf31wU
owS0d7DQLhGrPtBs/C85u4DUTHJcZys7RX4Q7fArDkN1sszhtoxNb2WTgYLKYQYF
IHdYRF8Bqq7ZrNJ+2MOQS1kowXTluJKuCQbgL+UwJl+wtrRdxt64CKSCmtH7h4H+
yhDD2J6CP3jz4SUQY/CxCmHzI1SVDmHwtr7J02V468Bz+zwT9YbLyvwPKAKJAW5h
MUpYN+Yg6Ch7TEa/qw+tbkJbSQeXiAIpzRVAzffo8+djG+UnMdLSMBcCAwEAAaAA
MA0GCSqGSIb3DQEBBQUAA4ICAQAr3YwkjT9Lft7DQP328BfudnAQR+tdodAtZGRU
y3ZUVupQwgtYdCCRnneCdVcAQUnj6tZHkzBhHBflVz24vXZZHiQilaajzeCoJpj5
jXy1ZjPK/efTKw8H325N8hHqGgiXEp86K06LZ4a6m3K+lBZbhb2hSt2MJx8DDn1Y
YE1Ssvo0rxDrhnPbAeAdmVNT4zCazYTAaYk2IwAAY9BsoRQouYsSHbVxG+KFGp2A
Rw9ryCqBXUAbj0b7whOFEj7pqg3F8nNbPuFdaUoCGaN8TWQFy4diwFsujGONDl4w
Df82BlAj/ty9z5WUCs01+z9X4SDm+vchSMqBKgAYZSKEAEmlQf++3tlJpEG7jM1l
SqYkeSVWrkHSBXkNQQ2iNmzMBvCA40Qont8OXP/gqS0+rS37f2LtuUueCgV8Gtay
RWgH7/JcdLEMm/XohRyD2yVz/JhKNWkYyEjtpr4wFTgFX48v6H4fE7o0HcUHy4nK
vN4vwXoa71x65lL1HcZdqYr/ff9KHcwxaOnflTgXzBMvm++F7EwEOK61TDuNkZ8h
gaf8Ejt1XNtA1jPNnRES7gqafOJAwYyshr5XoLzHUgbXBTVlEp5t2buxf76n+nzz
Zz6BD8nuXQMGPy60ql12MQvLmdX7mFFHthucExhA/9R7wSPtdS8OBPljumgUuhRR
BcW7kw==
-----END CERTIFICATE REQUEST-----
""")
def test_copy_good_extensions(self):
csr = signing_request.X509Csr.from_buffer(self.csr_data)
ext = extension.X509ExtensionSubjectAltName()
ext.add_dns_id("example.com")
csr.add_extension(ext)
pem = certificate_ops.sign(csr, self.sample_conf_ca['default_ca'])
cert = certificate.X509Certificate.from_buffer(pem)
self.assertEqual(1, len(cert.get_extensions(
extension.X509ExtensionSubjectAltName)))
def test_ignore_unknown_extensions(self):
csr = signing_request.X509Csr.from_buffer(self.csr_data)
ext = UnknownExtension()
csr.add_extension(ext)
pem = certificate_ops.sign(csr, self.sample_conf_ca['default_ca'])
cert = certificate.X509Certificate.from_buffer(pem)
self.assertEqual(0, len(cert.get_extensions()))
def test_fail_critical_unknown_extensions(self):
csr = signing_request.X509Csr.from_buffer(self.csr_data)
ext = UnknownExtension()
ext.set_critical(True)
csr.add_extension(ext)
with self.assertRaises(certificate_ops.SigningError):
certificate_ops.sign(csr, self.sample_conf_ca['default_ca'])