• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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]
10 module _ssl
11 class _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 
17 static PyObject *
newCertificate(PyTypeObject * type,X509 * cert,int upref)18 newCertificate(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 
38 static PyObject *
_PySSL_CertificateFromX509(_sslmodulestate * state,X509 * cert,int upref)39 _PySSL_CertificateFromX509(_sslmodulestate *state, X509 *cert, int upref)
40 {
41     return newCertificate(state->PySSLCertificate_Type, cert, upref);
42 }
43 
44 static PyObject*
_PySSL_CertificateFromX509Stack(_sslmodulestate * state,STACK_OF (X509)* stack,int upref)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 
73 static PyObject *
_ssl_Certificate_public_bytes_impl(PySSLCertificate * self,int format)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 
123 static PyObject *
_ssl_Certificate_get_info_impl(PySSLCertificate * self)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 
130 static PyObject*
_x509name_print(_sslmodulestate * state,X509_NAME * name,int indent,unsigned long flags)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 
156 static PyObject *
certificate_repr(PySSLCertificate * self)157 certificate_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 
178 static Py_hash_t
certificate_hash(PySSLCertificate * self)179 certificate_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 
193 static PyObject *
certificate_richcompare(PySSLCertificate * self,PyObject * other,int op)194 certificate_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 
214 static void
certificate_dealloc(PySSLCertificate * self)215 certificate_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 
223 static PyMethodDef certificate_methods[] = {
224     /* methods */
225     _SSL_CERTIFICATE_PUBLIC_BYTES_METHODDEF
226     _SSL_CERTIFICATE_GET_INFO_METHODDEF
227     {NULL, NULL}
228 };
229 
230 static 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 
239 static 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