mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 02:15:10 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			245 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			245 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "Python.h"
 | |
| #include "../_ssl.h"
 | |
| 
 | |
| #include "openssl/err.h"
 | |
| #include "openssl/bio.h"
 | |
| #include "openssl/pem.h"
 | |
| #include "openssl/x509.h"
 | |
| 
 | |
| /*[clinic input]
 | |
| module _ssl
 | |
| class _ssl.Certificate "PySSLCertificate *" "PySSLCertificate_Type"
 | |
| [clinic start generated code]*/
 | |
| /*[clinic end generated code: output=da39a3ee5e6b4b0d input=780fc647948cfffc]*/
 | |
| 
 | |
| #include "clinic/cert.c.h"
 | |
| 
 | |
| static PyObject *
 | |
| newCertificate(PyTypeObject *type, X509 *cert, int upref)
 | |
| {
 | |
|     PySSLCertificate *self;
 | |
| 
 | |
|     assert(type != NULL && type->tp_alloc != NULL);
 | |
|     assert(cert != NULL);
 | |
| 
 | |
|     self = (PySSLCertificate *) type->tp_alloc(type, 0);
 | |
|     if (self == NULL) {
 | |
|         return NULL;
 | |
|     }
 | |
|     if (upref == 1) {
 | |
|         X509_up_ref(cert);
 | |
|     }
 | |
|     self->cert = cert;
 | |
|     self->hash = -1;
 | |
| 
 | |
|     return (PyObject *) self;
 | |
| }
 | |
| 
 | |
| static PyObject *
 | |
| _PySSL_CertificateFromX509(_sslmodulestate *state, X509 *cert, int upref)
 | |
| {
 | |
|     return newCertificate(state->PySSLCertificate_Type, cert, upref);
 | |
| }
 | |
| 
 | |
| static PyObject*
 | |
| _PySSL_CertificateFromX509Stack(_sslmodulestate *state, STACK_OF(X509) *stack, int upref)
 | |
| {
 | |
|     int len, i;
 | |
|     PyObject *result = NULL;
 | |
| 
 | |
|     len = sk_X509_num(stack);
 | |
|     result = PyList_New(len);
 | |
|     if (result == NULL) {
 | |
|         return NULL;
 | |
|     }
 | |
|     for (i = 0; i < len; i++) {
 | |
|         X509 *cert = sk_X509_value(stack, i);
 | |
|         PyObject *ocert = _PySSL_CertificateFromX509(state, cert, upref);
 | |
|         if (ocert == NULL) {
 | |
|             Py_DECREF(result);
 | |
|             return NULL;
 | |
|         }
 | |
|         PyList_SetItem(result, i, ocert);
 | |
|     }
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| /*[clinic input]
 | |
| _ssl.Certificate.public_bytes
 | |
|     format: int(c_default="PY_SSL_ENCODING_PEM") = Encoding.PEM
 | |
| 
 | |
| [clinic start generated code]*/
 | |
| 
 | |
| static PyObject *
 | |
| _ssl_Certificate_public_bytes_impl(PySSLCertificate *self, int format)
 | |
| /*[clinic end generated code: output=c01ddbb697429e12 input=4d38c45e874b0e64]*/
 | |
| {
 | |
|     BIO *bio;
 | |
|     int retcode;
 | |
|     PyObject *result;
 | |
|     _sslmodulestate *state = get_state_cert(self);
 | |
| 
 | |
|     bio = BIO_new(BIO_s_mem());
 | |
|     if (bio == NULL) {
 | |
|         PyErr_SetString(state->PySSLErrorObject,
 | |
|                         "failed to allocate BIO");
 | |
|         return NULL;
 | |
|     }
 | |
|     switch(format) {
 | |
|     case PY_SSL_ENCODING_PEM:
 | |
|         retcode = PEM_write_bio_X509(bio, self->cert);
 | |
|         break;
 | |
|     case PY_SSL_ENCODING_PEM_AUX:
 | |
|         retcode = PEM_write_bio_X509_AUX(bio, self->cert);
 | |
|         break;
 | |
|     case PY_SSL_ENCODING_DER:
 | |
|         retcode = i2d_X509_bio(bio, self->cert);
 | |
|         break;
 | |
|     default:
 | |
|         PyErr_SetString(PyExc_ValueError, "Unsupported format");
 | |
|         BIO_free(bio);
 | |
|         return NULL;
 | |
|     }
 | |
|     if (retcode != 1) {
 | |
|         BIO_free(bio);
 | |
|         _setSSLError(state, NULL, 0, __FILE__, __LINE__);
 | |
|         return NULL;
 | |
|     }
 | |
|     if (format == PY_SSL_ENCODING_DER) {
 | |
|         result = _PySSL_BytesFromBIO(state, bio);
 | |
|     } else {
 | |
|         result = _PySSL_UnicodeFromBIO(state, bio, "error");
 | |
|     }
 | |
|     BIO_free(bio);
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*[clinic input]
 | |
| _ssl.Certificate.get_info
 | |
| 
 | |
| [clinic start generated code]*/
 | |
| 
 | |
| static PyObject *
 | |
| _ssl_Certificate_get_info_impl(PySSLCertificate *self)
 | |
| /*[clinic end generated code: output=0f0deaac54f4408b input=ba2c1694b39d0778]*/
 | |
| {
 | |
|     return _decode_certificate(get_state_cert(self), self->cert);
 | |
| }
 | |
| 
 | |
| static PyObject*
 | |
| _x509name_print(_sslmodulestate *state, X509_NAME *name, int indent, unsigned long flags)
 | |
| {
 | |
|     PyObject *res;
 | |
|     BIO *biobuf;
 | |
| 
 | |
|     biobuf = BIO_new(BIO_s_mem());
 | |
|     if (biobuf == NULL) {
 | |
|         PyErr_SetString(PyExc_MemoryError, "failed to allocate BIO");
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     if (X509_NAME_print_ex(biobuf, name, indent, flags) <= 0) {
 | |
|         _setSSLError(state, NULL, 0, __FILE__, __LINE__);
 | |
|         BIO_free(biobuf);
 | |
|         return NULL;
 | |
|     }
 | |
|     res = _PySSL_UnicodeFromBIO(state, biobuf, "strict");
 | |
|     BIO_free(biobuf);
 | |
|     return res;
 | |
| }
 | |
| 
 | |
| /* ************************************************************************
 | |
|  * PySSLCertificate_Type
 | |
|  */
 | |
| 
 | |
| static PyObject *
 | |
| certificate_repr(PySSLCertificate *self)
 | |
| {
 | |
|     PyObject *osubject, *result;
 | |
| 
 | |
|     /* subject string is ASCII encoded, UTF-8 chars are quoted */
 | |
|     osubject = _x509name_print(
 | |
|         get_state_cert(self),
 | |
|         X509_get_subject_name(self->cert),
 | |
|         0,
 | |
|         XN_FLAG_RFC2253
 | |
|     );
 | |
|     if (osubject == NULL)
 | |
|         return NULL;
 | |
|     result = PyUnicode_FromFormat(
 | |
|         "<%s '%U'>",
 | |
|         Py_TYPE(self)->tp_name, osubject
 | |
|     );
 | |
|     Py_DECREF(osubject);
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| static Py_hash_t
 | |
| certificate_hash(PySSLCertificate *self)
 | |
| {
 | |
|     if (self->hash == (Py_hash_t)-1) {
 | |
|         unsigned long hash;
 | |
|         hash = X509_subject_name_hash(self->cert);
 | |
|         if ((Py_hash_t)hash == (Py_hash_t)-1) {
 | |
|             self->hash = -2;
 | |
|         } else {
 | |
|             self->hash = (Py_hash_t)hash;
 | |
|         }
 | |
|     }
 | |
|     return self->hash;
 | |
| }
 | |
| 
 | |
| static PyObject *
 | |
| certificate_richcompare(PySSLCertificate *self, PyObject *other, int op)
 | |
| {
 | |
|     int cmp;
 | |
|     _sslmodulestate *state = get_state_cert(self);
 | |
| 
 | |
|     if (Py_TYPE(other) != state->PySSLCertificate_Type) {
 | |
|         Py_RETURN_NOTIMPLEMENTED;
 | |
|     }
 | |
|     /* only support == and != */
 | |
|     if ((op != Py_EQ) && (op != Py_NE)) {
 | |
|         Py_RETURN_NOTIMPLEMENTED;
 | |
|     }
 | |
|     cmp = X509_cmp(self->cert, ((PySSLCertificate*)other)->cert);
 | |
|     if (((op == Py_EQ) && (cmp == 0)) || ((op == Py_NE) && (cmp != 0))) {
 | |
|         Py_RETURN_TRUE;
 | |
|     } else {
 | |
|         Py_RETURN_FALSE;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| certificate_dealloc(PySSLCertificate *self)
 | |
| {
 | |
|     PyTypeObject *tp = Py_TYPE(self);
 | |
|     X509_free(self->cert);
 | |
|     Py_TYPE(self)->tp_free(self);
 | |
|     Py_DECREF(tp);
 | |
| }
 | |
| 
 | |
| static PyMethodDef certificate_methods[] = {
 | |
|     /* methods */
 | |
|     _SSL_CERTIFICATE_PUBLIC_BYTES_METHODDEF
 | |
|     _SSL_CERTIFICATE_GET_INFO_METHODDEF
 | |
|     {NULL, NULL}
 | |
| };
 | |
| 
 | |
| static PyType_Slot PySSLCertificate_slots[] = {
 | |
|     {Py_tp_dealloc, certificate_dealloc},
 | |
|     {Py_tp_repr, certificate_repr},
 | |
|     {Py_tp_hash, certificate_hash},
 | |
|     {Py_tp_richcompare, certificate_richcompare},
 | |
|     {Py_tp_methods, certificate_methods},
 | |
|     {0, 0},
 | |
| };
 | |
| 
 | |
| static PyType_Spec PySSLCertificate_spec = {
 | |
|     "_ssl.Certificate",
 | |
|     sizeof(PySSLCertificate),
 | |
|     0,
 | |
|     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_IMMUTABLETYPE,
 | |
|     PySSLCertificate_slots,
 | |
| };
 | 
