Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
allendowney
GitHub Repository: allendowney/cpython
Path: blob/main/Modules/_ssl/cert.c
12 views
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
247