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] 10module _ssl 11class _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 17static PyObject * 18newCertificate(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 38static PyObject * 39_PySSL_CertificateFromX509(_sslmodulestate *state, X509 *cert, int upref) 40{ 41 return newCertificate(state->PySSLCertificate_Type, cert, upref); 42} 43 44static 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 73static 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 123static 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 130static 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 156static PyObject * 157certificate_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 178static Py_hash_t 179certificate_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 193static PyObject * 194certificate_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 214static void 215certificate_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 223static PyMethodDef certificate_methods[] = { 224 /* methods */ 225 _SSL_CERTIFICATE_PUBLIC_BYTES_METHODDEF 226 _SSL_CERTIFICATE_GET_INFO_METHODDEF 227 {NULL, NULL} 228}; 229 230static 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 239static 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