From 3511b4e5e40124d223197e9f5a5794969f8f3b1b Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 16 May 2017 16:17:47 +0530 Subject: [PATCH] Add the CA:TRUE basic constraint when generating a CA certificate --- src/calibre/utils/certgen.c | 21 +++++++++++---------- src/calibre/utils/certgen.py | 15 +++++++++------ 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/calibre/utils/certgen.c b/src/calibre/utils/certgen.c index bdf8a39fcc..730e8da709 100644 --- a/src/calibre/utils/certgen.c +++ b/src/calibre/utils/certgen.c @@ -97,7 +97,7 @@ static PyObject* create_rsa_cert_req(PyObject *self, PyObject *args) { RSA *KeyPair = NULL; PyObject *capsule = NULL, *ans = NULL, *t = NULL; X509_NAME *Name = NULL; - char *common_name = NULL, *country = NULL, *state = NULL, *locality = NULL, *org = NULL, *org_unit = NULL, *email = NULL, buf[1024]; + char *common_name = NULL, *country = NULL, *state = NULL, *locality = NULL, *org = NULL, *org_unit = NULL, *email = NULL, *basic_constraints = NULL, buf[1024]; X509_REQ *Cert = NULL; EVP_PKEY *PrivateKey = NULL; PyObject *alt_names = NULL; @@ -105,7 +105,7 @@ static PyObject* create_rsa_cert_req(PyObject *self, PyObject *args) { Py_ssize_t i = 0; STACK_OF(X509_EXTENSION) *exts = NULL; - if(!PyArg_ParseTuple(args, "OOszzzzzz", &capsule, &alt_names, &common_name, &country, &state, &locality, &org, &org_unit, &email)) return NULL; + if(!PyArg_ParseTuple(args, "OOszzzzzzz", &capsule, &alt_names, &common_name, &country, &state, &locality, &org, &org_unit, &email, &basic_constraints)) return NULL; if(!PyCapsule_CheckExact(capsule)) return PyErr_Format(PyExc_TypeError, "The key is not a capsule object"); if(!PySequence_Check(alt_names)) return PyErr_Format(PyExc_TypeError, "alt_names must be a sequence"); KeyPair = PyCapsule_GetPointer(capsule, NULL); @@ -123,7 +123,7 @@ static PyObject* create_rsa_cert_req(PyObject *self, PyObject *args) { if (!add_entry(Name, "emailAddress", email)) goto error; if (!add_entry(Name, "CN", common_name)) goto error; - if (PySequence_Length(alt_names) > 0) { + if (PySequence_Length(alt_names) > 0 || basic_constraints) { exts = sk_X509_EXTENSION_new_null(); if (!exts) { set_error("sk_X509_EXTENSION_new_null"); goto error; } for (i = 0; i < PySequence_Length(alt_names); i++) { @@ -133,6 +133,9 @@ static PyObject* create_rsa_cert_req(PyObject *self, PyObject *args) { Py_XDECREF(t); if(!add_ext(exts, NID_subject_alt_name, buf)) goto error; } + if (basic_constraints) { + if(!add_ext(exts, NID_basic_constraints, basic_constraints)) goto error; + } X509_REQ_add_extensions(Cert, exts); sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); } @@ -243,13 +246,11 @@ static PyObject* create_rsa_cert(PyObject *self, PyObject *args) { if (!Name) { set_error("X509_REQ_get_subject_name(CA_cert)"); goto error; } if (!X509_set_issuer_name(Cert, Name)) { set_error("X509_set_issuer_name"); goto error; } - if (!req_is_for_CA_cert) { - exts = X509_REQ_get_extensions(req); - if (exts) { - X509V3_set_ctx(&ctx, CA_cert, Cert, NULL, NULL, 0); - for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { - if(!X509_add_ext(Cert, sk_X509_EXTENSION_value(exts, i), -1)) { set_error("X509_add_ext"); goto error; } - } + exts = X509_REQ_get_extensions(req); + if (exts) { + X509V3_set_ctx(&ctx, CA_cert, Cert, NULL, NULL, 0); + for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { + if(!X509_add_ext(Cert, sk_X509_EXTENSION_value(exts, i), -1)) { set_error("X509_add_ext"); goto error; } } } diff --git a/src/calibre/utils/certgen.py b/src/calibre/utils/certgen.py index 1defebc8ff..bbc0a17d51 100644 --- a/src/calibre/utils/certgen.py +++ b/src/calibre/utils/certgen.py @@ -9,7 +9,7 @@ __copyright__ = '2015, Kovid Goyal ' from calibre.constants import plugins certgen, err = plugins['certgen'] if err: - raise ImportError('Failed to load teh certgen module with error: %s' % err) + raise ImportError('Failed to load the certgen module with error: %s' % err) def create_key_pair(size=2048): @@ -19,7 +19,7 @@ def create_key_pair(size=2048): def create_cert_request( key_pair, common_name, country='IN', state='Maharashtra', locality='Mumbai', organization=None, - organizational_unit=None, email_address=None, alt_names=() + organizational_unit=None, email_address=None, alt_names=(), basic_constraints=None ): def enc(x): if isinstance(x, type('')): @@ -27,7 +27,7 @@ def create_cert_request( return x or None return certgen.create_rsa_cert_req( key_pair, tuple(bytes(enc(x)) for x in alt_names if x), - *map(enc, (common_name, country, state, locality, organization, organizational_unit, email_address)) + *map(enc, (common_name, country, state, locality, organization, organizational_unit, email_address, basic_constraints)) ) @@ -59,7 +59,7 @@ def create_server_cert( ): # Create the Certificate Authority cakey = create_key_pair(key_size) - careq = create_cert_request(cakey, ca_name) + careq = create_cert_request(cakey, ca_name, basic_constraints='CA:TRUE') cacert = create_ca_cert(careq, cakey) # Create the server certificate issued by the newly created CA @@ -81,8 +81,11 @@ def create_server_cert( export(ca_key_file, cakey, serialize_key, encrypt_key_with_password) return cacert, cakey, cert, pkey + if __name__ == '__main__': cacert, cakey, cert, pkey = create_server_cert('test.me', alt_names=['1.test.me', '*.all.test.me']) + print("CA Certificate") + print (cert_info(cacert).encode('utf-8')) + print(), print(), print() + print('Server Certificate') print (cert_info(cert).encode('utf-8')) - -