diff --git a/src/calibre/utils/certgen.c b/src/calibre/utils/certgen.c index 2e46478f58..11a8105fcc 100644 --- a/src/calibre/utils/certgen.c +++ b/src/calibre/utils/certgen.c @@ -110,14 +110,14 @@ add_ext(STACK_OF(X509_EXTENSION) *sk, int nid, const char *value, char *item_typ static PyObject* create_rsa_cert_req(PyObject *self, PyObject *args) { 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, *basic_constraints = NULL; + char *common_name = NULL, *country = NULL, *state = NULL, *locality = NULL, *org = NULL, *org_unit = NULL, *email = NULL, *basic_constraints = NULL, *digital_key_usage = NULL; X509_REQ *Cert = NULL; PyObject *alt_names = NULL; int ok = 0, signature_length = 0; Py_ssize_t i = 0; STACK_OF(X509_EXTENSION) *exts = NULL; - if(!PyArg_ParseTuple(args, "OO!szzzzzzz", &capsule, &PyTuple_Type, &alt_names, &common_name, &country, &state, &locality, &org, &org_unit, &email, &basic_constraints)) return NULL; + if(!PyArg_ParseTuple(args, "OO!szzzzzzzz", &capsule, &PyTuple_Type, &alt_names, &common_name, &country, &state, &locality, &org, &org_unit, &email, &basic_constraints, &digital_key_usage)) return NULL; if(!PyCapsule_CheckExact(capsule)) return PyErr_Format(PyExc_TypeError, "The key is not a capsule object"); EVP_PKEY *KeyPair = PyCapsule_GetPointer(capsule, NULL); if (!KeyPair) return PyErr_Format(PyExc_TypeError, "The key capsule is NULL"); @@ -134,7 +134,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 (PyTuple_GET_SIZE(alt_names) > 0 || basic_constraints) { + if (PyTuple_GET_SIZE(alt_names) > 0 || basic_constraints || digital_key_usage) { exts = sk_X509_EXTENSION_new_null(); if (!exts) { set_error("sk_X509_EXTENSION_new_null"); goto error; } for (i = 0; i < PyTuple_GET_SIZE(alt_names); i++) { @@ -147,6 +147,9 @@ static PyObject* create_rsa_cert_req(PyObject *self, PyObject *args) { if (basic_constraints) { if(!add_ext(exts, NID_basic_constraints, basic_constraints, "basic_constraints")) goto error; } + if (digital_key_usage) { + if(!add_ext(exts, NID_key_usage, digital_key_usage, "key_usage")) goto error; + } X509_REQ_add_extensions(Cert, exts); sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); } diff --git a/src/calibre/utils/certgen.py b/src/calibre/utils/certgen.py index 68524a292c..d9905a4479 100644 --- a/src/calibre/utils/certgen.py +++ b/src/calibre/utils/certgen.py @@ -16,11 +16,11 @@ 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=(), basic_constraints=None + organizational_unit=None, email_address=None, alt_names=(), basic_constraints=None, digital_key_usage=None ): return certgen.create_rsa_cert_req( key_pair, tuple(alt_names), common_name, - country, state, locality, organization, organizational_unit, email_address, basic_constraints + country, state, locality, organization, organizational_unit, email_address, basic_constraints, digital_key_usage ) @@ -66,7 +66,7 @@ def create_server_cert( # Create the Certificate Authority cakey = create_key_pair(key_size) - careq = create_cert_request(cakey, ca_name, basic_constraints='CA:TRUE') + careq = create_cert_request(cakey, ca_name, basic_constraints='critical,CA:TRUE', digital_key_usage='critical,keyCertSign,cRLSign') cacert = create_ca_cert(careq, cakey) # Create the server certificate issued by the newly created CA @@ -91,10 +91,26 @@ def create_server_cert( return cacert, cakey, cert, pkey -if __name__ == '__main__': +def develop(): + import subprocess + import tempfile cacert, cakey, cert, pkey = create_server_cert('test.me', alt_names=['DNS:moose.cat', 'DNS:huge.bat']) print("CA Certificate") print(cert_info(cacert)) print(), print(), print() print('Server Certificate') print(cert_info(cert)) + with tempfile.NamedTemporaryFile(prefix='CA-', suffix='.pem') as cafile, tempfile.NamedTemporaryFile(prefix='Server-', suffix='.crt') as certfile: + cafile.write(serialize_cert(cacert).encode()) + certfile.write(serialize_cert(cert).encode()) + cafile.flush() + certfile.flush() + # Verify the self signed certificate + subprocess.check_call(['openssl', 'verify', '-verbose', '-x509_strict', '-CAfile', cafile.name, cafile.name]) + # Verify the server certificate signed with the self signed certificate + raise SystemExit(subprocess.run([ + 'openssl', 'verify', '-show_chain', '-no_check_time', '-verbose', '-x509_strict', '-CAfile', cafile.name, certfile.name]).returncode) + + +if __name__ == '__main__': + develop()