xref: /third_party/python/Modules/_ssl/cert.c (revision 7db96d56)
1#include "Python.h"
2#include "../_ssl.h"
3
4#include "openssl/err.h"
5#include "openssl/bio.h"
6#include "openssl/pem.h"
7#include "openssl/x509.h"
8
9/*[clinic input]
10module _ssl
11class _ssl.Certificate "PySSLCertificate *" "PySSLCertificate_Type"
12[clinic start generated code]*/
13/*[clinic end generated code: output=da39a3ee5e6b4b0d input=780fc647948cfffc]*/
14
15#include "clinic/cert.c.h"
16
17static PyObject *
18newCertificate(PyTypeObject *type, X509 *cert, int upref)
19{
20    PySSLCertificate *self;
21
22    assert(type != NULL && type->tp_alloc != NULL);
23    assert(cert != NULL);
24
25    self = (PySSLCertificate *) type->tp_alloc(type, 0);
26    if (self == NULL) {
27        return NULL;
28    }
29    if (upref == 1) {
30        X509_up_ref(cert);
31    }
32    self->cert = cert;
33    self->hash = -1;
34
35    return (PyObject *) self;
36}
37
38static PyObject *
39_PySSL_CertificateFromX509(_sslmodulestate *state, X509 *cert, int upref)
40{
41    return newCertificate(state->PySSLCertificate_Type, cert, upref);
42}
43
44static PyObject*
45_PySSL_CertificateFromX509Stack(_sslmodulestate *state, STACK_OF(X509) *stack, int upref)
46{
47    int len, i;
48    PyObject *result = NULL;
49
50    len = sk_X509_num(stack);
51    result = PyList_New(len);
52    if (result == NULL) {
53        return NULL;
54    }
55    for (i = 0; i < len; i++) {
56        X509 *cert = sk_X509_value(stack, i);
57        PyObject *ocert = _PySSL_CertificateFromX509(state, cert, upref);
58        if (ocert == NULL) {
59            Py_DECREF(result);
60            return NULL;
61        }
62        PyList_SetItem(result, i, ocert);
63    }
64    return result;
65}
66
67/*[clinic input]
68_ssl.Certificate.public_bytes
69    format: int(c_default="PY_SSL_ENCODING_PEM") = Encoding.PEM
70
71[clinic start generated code]*/
72
73static PyObject *
74_ssl_Certificate_public_bytes_impl(PySSLCertificate *self, int format)
75/*[clinic end generated code: output=c01ddbb697429e12 input=4d38c45e874b0e64]*/
76{
77    BIO *bio;
78    int retcode;
79    PyObject *result;
80    _sslmodulestate *state = get_state_cert(self);
81
82    bio = BIO_new(BIO_s_mem());
83    if (bio == NULL) {
84        PyErr_SetString(state->PySSLErrorObject,
85                        "failed to allocate BIO");
86        return NULL;
87    }
88    switch(format) {
89    case PY_SSL_ENCODING_PEM:
90        retcode = PEM_write_bio_X509(bio, self->cert);
91        break;
92    case PY_SSL_ENCODING_PEM_AUX:
93        retcode = PEM_write_bio_X509_AUX(bio, self->cert);
94        break;
95    case PY_SSL_ENCODING_DER:
96        retcode = i2d_X509_bio(bio, self->cert);
97        break;
98    default:
99        PyErr_SetString(PyExc_ValueError, "Unsupported format");
100        BIO_free(bio);
101        return NULL;
102    }
103    if (retcode != 1) {
104        BIO_free(bio);
105        _setSSLError(state, NULL, 0, __FILE__, __LINE__);
106        return NULL;
107    }
108    if (format == PY_SSL_ENCODING_DER) {
109        result = _PySSL_BytesFromBIO(state, bio);
110    } else {
111        result = _PySSL_UnicodeFromBIO(state, bio, "error");
112    }
113    BIO_free(bio);
114    return result;
115}
116
117
118/*[clinic input]
119_ssl.Certificate.get_info
120
121[clinic start generated code]*/
122
123static PyObject *
124_ssl_Certificate_get_info_impl(PySSLCertificate *self)
125/*[clinic end generated code: output=0f0deaac54f4408b input=ba2c1694b39d0778]*/
126{
127    return _decode_certificate(get_state_cert(self), self->cert);
128}
129
130static PyObject*
131_x509name_print(_sslmodulestate *state, X509_NAME *name, int indent, unsigned long flags)
132{
133    PyObject *res;
134    BIO *biobuf;
135
136    biobuf = BIO_new(BIO_s_mem());
137    if (biobuf == NULL) {
138        PyErr_SetString(PyExc_MemoryError, "failed to allocate BIO");
139        return NULL;
140    }
141
142    if (X509_NAME_print_ex(biobuf, name, indent, flags) <= 0) {
143        _setSSLError(state, NULL, 0, __FILE__, __LINE__);
144        BIO_free(biobuf);
145        return NULL;
146    }
147    res = _PySSL_UnicodeFromBIO(state, biobuf, "strict");
148    BIO_free(biobuf);
149    return res;
150}
151
152/* ************************************************************************
153 * PySSLCertificate_Type
154 */
155
156static PyObject *
157certificate_repr(PySSLCertificate *self)
158{
159    PyObject *osubject, *result;
160
161    /* subject string is ASCII encoded, UTF-8 chars are quoted */
162    osubject = _x509name_print(
163        get_state_cert(self),
164        X509_get_subject_name(self->cert),
165        0,
166        XN_FLAG_RFC2253
167    );
168    if (osubject == NULL)
169        return NULL;
170    result = PyUnicode_FromFormat(
171        "<%s '%U'>",
172        Py_TYPE(self)->tp_name, osubject
173    );
174    Py_DECREF(osubject);
175    return result;
176}
177
178static Py_hash_t
179certificate_hash(PySSLCertificate *self)
180{
181    if (self->hash == (Py_hash_t)-1) {
182        unsigned long hash;
183        hash = X509_subject_name_hash(self->cert);
184        if ((Py_hash_t)hash == (Py_hash_t)-1) {
185            self->hash = -2;
186        } else {
187            self->hash = (Py_hash_t)hash;
188        }
189    }
190    return self->hash;
191}
192
193static PyObject *
194certificate_richcompare(PySSLCertificate *self, PyObject *other, int op)
195{
196    int cmp;
197    _sslmodulestate *state = get_state_cert(self);
198
199    if (Py_TYPE(other) != state->PySSLCertificate_Type) {
200        Py_RETURN_NOTIMPLEMENTED;
201    }
202    /* only support == and != */
203    if ((op != Py_EQ) && (op != Py_NE)) {
204        Py_RETURN_NOTIMPLEMENTED;
205    }
206    cmp = X509_cmp(self->cert, ((PySSLCertificate*)other)->cert);
207    if (((op == Py_EQ) && (cmp == 0)) || ((op == Py_NE) && (cmp != 0))) {
208        Py_RETURN_TRUE;
209    } else {
210        Py_RETURN_FALSE;
211    }
212}
213
214static void
215certificate_dealloc(PySSLCertificate *self)
216{
217    PyTypeObject *tp = Py_TYPE(self);
218    X509_free(self->cert);
219    Py_TYPE(self)->tp_free(self);
220    Py_DECREF(tp);
221}
222
223static PyMethodDef certificate_methods[] = {
224    /* methods */
225    _SSL_CERTIFICATE_PUBLIC_BYTES_METHODDEF
226    _SSL_CERTIFICATE_GET_INFO_METHODDEF
227    {NULL, NULL}
228};
229
230static PyType_Slot PySSLCertificate_slots[] = {
231    {Py_tp_dealloc, certificate_dealloc},
232    {Py_tp_repr, certificate_repr},
233    {Py_tp_hash, certificate_hash},
234    {Py_tp_richcompare, certificate_richcompare},
235    {Py_tp_methods, certificate_methods},
236    {0, 0},
237};
238
239static PyType_Spec PySSLCertificate_spec = {
240    "_ssl.Certificate",
241    sizeof(PySSLCertificate),
242    0,
243    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_IMMUTABLETYPE,
244    PySSLCertificate_slots,
245};
246