| #include "Python.h" | |
| #include "../_ssl.h" | |
| #include "openssl/err.h" | |
| #include "openssl/bio.h" | |
| #include "openssl/pem.h" | |
| #include "openssl/x509.h" | |
| /*[clinic input] | |
| module _ssl | |
| class _ssl.Certificate "PySSLCertificate *" "PySSLCertificate_Type" | |
| [clinic start generated code]*/ | |
| /*[clinic end generated code: output=da39a3ee5e6b4b0d input=780fc647948cfffc]*/ | |
| #include "clinic/cert.c.h" | |
| static PyObject * | |
| newCertificate(PyTypeObject *type, X509 *cert, int upref) | |
| { | |
| PySSLCertificate *self; | |
| assert(type != NULL && type->tp_alloc != NULL); | |
| assert(cert != NULL); | |
| self = (PySSLCertificate *) type->tp_alloc(type, 0); | |
| if (self == NULL) { | |
| return NULL; | |
| } | |
| if (upref == 1) { | |
| X509_up_ref(cert); | |
| } | |
| self->cert = cert; | |
| self->hash = -1; | |
| return (PyObject *) self; | |
| } | |
| static PyObject * | |
| _PySSL_CertificateFromX509(_sslmodulestate *state, X509 *cert, int upref) | |
| { | |
| return newCertificate(state->PySSLCertificate_Type, cert, upref); | |
| } | |
| static PyObject* | |
| _PySSL_CertificateFromX509Stack(_sslmodulestate *state, STACK_OF(X509) *stack, int upref) | |
| { | |
| int len, i; | |
| PyObject *result = NULL; | |
| len = sk_X509_num(stack); | |
| result = PyList_New(len); | |
| if (result == NULL) { | |
| return NULL; | |
| } | |
| for (i = 0; i < len; i++) { | |
| X509 *cert = sk_X509_value(stack, i); | |
| PyObject *ocert = _PySSL_CertificateFromX509(state, cert, upref); | |
| if (ocert == NULL) { | |
| Py_DECREF(result); | |
| return NULL; | |
| } | |
| PyList_SetItem(result, i, ocert); | |
| } | |
| return result; | |
| } | |
| /*[clinic input] | |
| _ssl.Certificate.public_bytes | |
| format: int(c_default="PY_SSL_ENCODING_PEM") = Encoding.PEM | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| _ssl_Certificate_public_bytes_impl(PySSLCertificate *self, int format) | |
| /*[clinic end generated code: output=c01ddbb697429e12 input=4d38c45e874b0e64]*/ | |
| { | |
| BIO *bio; | |
| int retcode; | |
| PyObject *result; | |
| _sslmodulestate *state = get_state_cert(self); | |
| bio = BIO_new(BIO_s_mem()); | |
| if (bio == NULL) { | |
| PyErr_SetString(state->PySSLErrorObject, | |
| "failed to allocate BIO"); | |
| return NULL; | |
| } | |
| switch(format) { | |
| case PY_SSL_ENCODING_PEM: | |
| retcode = PEM_write_bio_X509(bio, self->cert); | |
| break; | |
| case PY_SSL_ENCODING_PEM_AUX: | |
| retcode = PEM_write_bio_X509_AUX(bio, self->cert); | |
| break; | |
| case PY_SSL_ENCODING_DER: | |
| retcode = i2d_X509_bio(bio, self->cert); | |
| break; | |
| default: | |
| PyErr_SetString(PyExc_ValueError, "Unsupported format"); | |
| BIO_free(bio); | |
| return NULL; | |
| } | |
| if (retcode != 1) { | |
| BIO_free(bio); | |
| _setSSLError(state, NULL, 0, __FILE__, __LINE__); | |
| return NULL; | |
| } | |
| if (format == PY_SSL_ENCODING_DER) { | |
| result = _PySSL_BytesFromBIO(state, bio); | |
| } else { | |
| result = _PySSL_UnicodeFromBIO(state, bio, "error"); | |
| } | |
| BIO_free(bio); | |
| return result; | |
| } | |
| /*[clinic input] | |
| _ssl.Certificate.get_info | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| _ssl_Certificate_get_info_impl(PySSLCertificate *self) | |
| /*[clinic end generated code: output=0f0deaac54f4408b input=ba2c1694b39d0778]*/ | |
| { | |
| return _decode_certificate(get_state_cert(self), self->cert); | |
| } | |
| static PyObject* | |
| _x509name_print(_sslmodulestate *state, const X509_NAME *name, | |
| int indent, unsigned long flags) | |
| { | |
| PyObject *res; | |
| BIO *biobuf; | |
| biobuf = BIO_new(BIO_s_mem()); | |
| if (biobuf == NULL) { | |
| PyErr_SetString(PyExc_MemoryError, "failed to allocate BIO"); | |
| return NULL; | |
| } | |
| if (X509_NAME_print_ex(biobuf, name, indent, flags) <= 0) { | |
| _setSSLError(state, NULL, 0, __FILE__, __LINE__); | |
| BIO_free(biobuf); | |
| return NULL; | |
| } | |
| res = _PySSL_UnicodeFromBIO(state, biobuf, "strict"); | |
| BIO_free(biobuf); | |
| return res; | |
| } | |
| /* ************************************************************************ | |
| * PySSLCertificate_Type | |
| */ | |
| #define PySSLCertificate_CAST(op) ((PySSLCertificate *)(op)) | |
| static PyObject * | |
| certificate_repr(PyObject *op) | |
| { | |
| PyObject *osubject, *result; | |
| PySSLCertificate *self = PySSLCertificate_CAST(op); | |
| /* subject string is ASCII encoded, UTF-8 chars are quoted */ | |
| osubject = _x509name_print( | |
| get_state_cert(self), | |
| X509_get_subject_name(self->cert), | |
| 0, | |
| XN_FLAG_RFC2253 | |
| ); | |
| if (osubject == NULL) | |
| return NULL; | |
| result = PyUnicode_FromFormat( | |
| "<%s '%U'>", | |
| Py_TYPE(self)->tp_name, osubject | |
| ); | |
| Py_DECREF(osubject); | |
| return result; | |
| } | |
| static Py_hash_t | |
| certificate_hash(PyObject *op) | |
| { | |
| PySSLCertificate *self = PySSLCertificate_CAST(op); | |
| if (self->hash == (Py_hash_t)-1) { | |
| unsigned long hash; | |
| hash = X509_subject_name_hash(self->cert); | |
| if ((Py_hash_t)hash == (Py_hash_t)-1) { | |
| self->hash = -2; | |
| } else { | |
| self->hash = (Py_hash_t)hash; | |
| } | |
| } | |
| return self->hash; | |
| } | |
| static PyObject * | |
| certificate_richcompare(PyObject *lhs, PyObject *rhs, int op) | |
| { | |
| int cmp; | |
| PySSLCertificate *self = PySSLCertificate_CAST(lhs); | |
| _sslmodulestate *state = get_state_cert(self); | |
| if (Py_TYPE(rhs) != state->PySSLCertificate_Type) { | |
| Py_RETURN_NOTIMPLEMENTED; | |
| } | |
| /* only support == and != */ | |
| if ((op != Py_EQ) && (op != Py_NE)) { | |
| Py_RETURN_NOTIMPLEMENTED; | |
| } | |
| cmp = X509_cmp(self->cert, ((PySSLCertificate*)rhs)->cert); | |
| if (((op == Py_EQ) && (cmp == 0)) || ((op == Py_NE) && (cmp != 0))) { | |
| Py_RETURN_TRUE; | |
| } else { | |
| Py_RETURN_FALSE; | |
| } | |
| } | |
| static void | |
| certificate_dealloc(PyObject *op) | |
| { | |
| PySSLCertificate *self = PySSLCertificate_CAST(op); | |
| PyTypeObject *tp = Py_TYPE(self); | |
| X509_free(self->cert); | |
| (void)Py_TYPE(self)->tp_free(self); | |
| Py_DECREF(tp); | |
| } | |
| static PyMethodDef certificate_methods[] = { | |
| /* methods */ | |
| _SSL_CERTIFICATE_PUBLIC_BYTES_METHODDEF | |
| _SSL_CERTIFICATE_GET_INFO_METHODDEF | |
| {NULL, NULL} | |
| }; | |
| static PyType_Slot PySSLCertificate_slots[] = { | |
| {Py_tp_dealloc, certificate_dealloc}, | |
| {Py_tp_repr, certificate_repr}, | |
| {Py_tp_hash, certificate_hash}, | |
| {Py_tp_richcompare, certificate_richcompare}, | |
| {Py_tp_methods, certificate_methods}, | |
| {0, 0}, | |
| }; | |
| static PyType_Spec PySSLCertificate_spec = { | |
| "_ssl.Certificate", | |
| sizeof(PySSLCertificate), | |
| 0, | |
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_IMMUTABLETYPE, | |
| PySSLCertificate_slots, | |
| }; |