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 | 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 * |
39 | _PySSL_CertificateFromX509(_sslmodulestate *state, X509 *cert, int upref) |
40 | { |
41 | return newCertificate(state->PySSLCertificate_Type, cert, upref); |
42 | } |
43 | |
44 | static 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 | |
73 | static 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 | |
123 | static 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 | |
130 | static 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 | |
156 | static PyObject * |
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 |
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 * |
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 |
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 | |