cpython/Modules/_ssl/cert.c
Christian Heimes 91554e4c5c
bpo-43908: Mark ssl, hash, and hmac types as immutable (GH-25792)
Signed-off-by: Christian Heimes <christian@python.org>
2021-05-02 09:47:45 +02:00

246 lines
6.1 KiB
C

#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, 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
*/
static PyObject *
certificate_repr(PySSLCertificate *self)
{
PyObject *osubject, *result;
/* 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(PySSLCertificate *self)
{
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(PySSLCertificate *self, PyObject *other, int op)
{
int cmp;
_sslmodulestate *state = get_state_cert(self);
if (Py_TYPE(other) != 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*)other)->cert);
if (((op == Py_EQ) && (cmp == 0)) || ((op == Py_NE) && (cmp != 0))) {
Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
}
static void
certificate_dealloc(PySSLCertificate *self)
{
PyTypeObject *tp = Py_TYPE(self);
X509_free(self->cert);
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,
};