Christian Heimes | 666991f | 2021-04-26 15:01:40 +0200 | [diff] [blame] | 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, |
Christian Heimes | 91554e4 | 2021-05-02 09:47:45 +0200 | [diff] [blame] | 243 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_IMMUTABLETYPE, |
Christian Heimes | 666991f | 2021-04-26 15:01:40 +0200 | [diff] [blame] | 244 | PySSLCertificate_slots, |
| 245 | }; |