Branch data Line data Source code
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 *
18 : 7 : 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 : 7 : self = (PySSLCertificate *) type->tp_alloc(type, 0);
26 [ - + ]: 7 : if (self == NULL) {
27 : 0 : return NULL;
28 : : }
29 [ + + ]: 7 : if (upref == 1) {
30 : 6 : X509_up_ref(cert);
31 : : }
32 : 7 : self->cert = cert;
33 : 7 : self->hash = -1;
34 : :
35 : 7 : return (PyObject *) self;
36 : : }
37 : :
38 : : static PyObject *
39 : 7 : _PySSL_CertificateFromX509(_sslmodulestate *state, X509 *cert, int upref)
40 : : {
41 : 7 : return newCertificate(state->PySSLCertificate_Type, cert, upref);
42 : : }
43 : :
44 : : static PyObject*
45 : 4 : _PySSL_CertificateFromX509Stack(_sslmodulestate *state, STACK_OF(X509) *stack, int upref)
46 : : {
47 : : int len, i;
48 : 4 : PyObject *result = NULL;
49 : :
50 : 4 : len = sk_X509_num(stack);
51 : 4 : result = PyList_New(len);
52 [ - + ]: 4 : if (result == NULL) {
53 : 0 : return NULL;
54 : : }
55 [ + + ]: 10 : for (i = 0; i < len; i++) {
56 : 6 : X509 *cert = sk_X509_value(stack, i);
57 : 6 : PyObject *ocert = _PySSL_CertificateFromX509(state, cert, upref);
58 [ - + ]: 6 : if (ocert == NULL) {
59 : 0 : Py_DECREF(result);
60 : 0 : return NULL;
61 : : }
62 : 6 : PyList_SetItem(result, i, ocert);
63 : : }
64 : 4 : 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 *
74 : 2 : _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 : 2 : _sslmodulestate *state = get_state_cert(self);
81 : :
82 : 2 : bio = BIO_new(BIO_s_mem());
83 [ - + ]: 2 : if (bio == NULL) {
84 : 0 : PyErr_SetString(state->PySSLErrorObject,
85 : : "failed to allocate BIO");
86 : 0 : return NULL;
87 : : }
88 [ + - + - ]: 2 : switch(format) {
89 : 1 : case PY_SSL_ENCODING_PEM:
90 : 1 : retcode = PEM_write_bio_X509(bio, self->cert);
91 : 1 : break;
92 : 0 : case PY_SSL_ENCODING_PEM_AUX:
93 : 0 : retcode = PEM_write_bio_X509_AUX(bio, self->cert);
94 : 0 : break;
95 : 1 : case PY_SSL_ENCODING_DER:
96 : 1 : retcode = i2d_X509_bio(bio, self->cert);
97 : 1 : break;
98 : 0 : default:
99 : 0 : PyErr_SetString(PyExc_ValueError, "Unsupported format");
100 : 0 : BIO_free(bio);
101 : 0 : return NULL;
102 : : }
103 [ - + ]: 2 : if (retcode != 1) {
104 : 0 : BIO_free(bio);
105 : 0 : _setSSLError(state, NULL, 0, __FILE__, __LINE__);
106 : 0 : return NULL;
107 : : }
108 [ + + ]: 2 : if (format == PY_SSL_ENCODING_DER) {
109 : 1 : result = _PySSL_BytesFromBIO(state, bio);
110 : : } else {
111 : 1 : result = _PySSL_UnicodeFromBIO(state, bio, "error");
112 : : }
113 : 2 : BIO_free(bio);
114 : 2 : return result;
115 : : }
116 : :
117 : :
118 : : /*[clinic input]
119 : : _ssl.Certificate.get_info
120 : :
121 : : [clinic start generated code]*/
122 : :
123 : : static PyObject *
124 : 2 : _ssl_Certificate_get_info_impl(PySSLCertificate *self)
125 : : /*[clinic end generated code: output=0f0deaac54f4408b input=ba2c1694b39d0778]*/
126 : : {
127 : 2 : return _decode_certificate(get_state_cert(self), self->cert);
128 : : }
129 : :
130 : : static PyObject*
131 : 6 : _x509name_print(_sslmodulestate *state, X509_NAME *name, int indent, unsigned long flags)
132 : : {
133 : : PyObject *res;
134 : : BIO *biobuf;
135 : :
136 : 6 : biobuf = BIO_new(BIO_s_mem());
137 [ - + ]: 6 : if (biobuf == NULL) {
138 : 0 : PyErr_SetString(PyExc_MemoryError, "failed to allocate BIO");
139 : 0 : return NULL;
140 : : }
141 : :
142 [ - + ]: 6 : if (X509_NAME_print_ex(biobuf, name, indent, flags) <= 0) {
143 : 0 : _setSSLError(state, NULL, 0, __FILE__, __LINE__);
144 : 0 : BIO_free(biobuf);
145 : 0 : return NULL;
146 : : }
147 : 6 : res = _PySSL_UnicodeFromBIO(state, biobuf, "strict");
148 : 6 : BIO_free(biobuf);
149 : 6 : return res;
150 : : }
151 : :
152 : : /* ************************************************************************
153 : : * PySSLCertificate_Type
154 : : */
155 : :
156 : : static PyObject *
157 : 6 : certificate_repr(PySSLCertificate *self)
158 : : {
159 : : PyObject *osubject, *result;
160 : :
161 : : /* subject string is ASCII encoded, UTF-8 chars are quoted */
162 : 6 : osubject = _x509name_print(
163 : 6 : get_state_cert(self),
164 : 6 : X509_get_subject_name(self->cert),
165 : : 0,
166 : : XN_FLAG_RFC2253
167 : : );
168 [ - + ]: 6 : if (osubject == NULL)
169 : 0 : return NULL;
170 : 6 : result = PyUnicode_FromFormat(
171 : : "<%s '%U'>",
172 : 6 : Py_TYPE(self)->tp_name, osubject
173 : : );
174 : 6 : Py_DECREF(osubject);
175 : 6 : return result;
176 : : }
177 : :
178 : : static Py_hash_t
179 : 4 : certificate_hash(PySSLCertificate *self)
180 : : {
181 [ + + ]: 4 : if (self->hash == (Py_hash_t)-1) {
182 : : unsigned long hash;
183 : 3 : hash = X509_subject_name_hash(self->cert);
184 [ - + ]: 3 : if ((Py_hash_t)hash == (Py_hash_t)-1) {
185 : 0 : self->hash = -2;
186 : : } else {
187 : 3 : self->hash = (Py_hash_t)hash;
188 : : }
189 : : }
190 : 4 : return self->hash;
191 : : }
192 : :
193 : : static PyObject *
194 : 2 : certificate_richcompare(PySSLCertificate *self, PyObject *other, int op)
195 : : {
196 : : int cmp;
197 : 2 : _sslmodulestate *state = get_state_cert(self);
198 : :
199 [ - + ]: 2 : if (Py_TYPE(other) != state->PySSLCertificate_Type) {
200 : 0 : Py_RETURN_NOTIMPLEMENTED;
201 : : }
202 : : /* only support == and != */
203 [ + + - + ]: 2 : if ((op != Py_EQ) && (op != Py_NE)) {
204 : 0 : Py_RETURN_NOTIMPLEMENTED;
205 : : }
206 : 2 : cmp = X509_cmp(self->cert, ((PySSLCertificate*)other)->cert);
207 [ + + - + : 2 : if (((op == Py_EQ) && (cmp == 0)) || ((op == Py_NE) && (cmp != 0))) {
+ - + - ]
208 : 2 : Py_RETURN_TRUE;
209 : : } else {
210 : 0 : Py_RETURN_FALSE;
211 : : }
212 : : }
213 : :
214 : : static void
215 : 7 : certificate_dealloc(PySSLCertificate *self)
216 : : {
217 : 7 : PyTypeObject *tp = Py_TYPE(self);
218 : 7 : X509_free(self->cert);
219 : 7 : Py_TYPE(self)->tp_free(self);
220 : 7 : Py_DECREF(tp);
221 : 7 : }
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 : : };
|