LCOV - code coverage report
Current view: top level - Modules/_ssl - cert.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit acb105a7c1f] Lines: 75 101 74.3 %
Date: 2022-07-20 13:12:14 Functions: 10 10 100.0 %
Branches: 28 44 63.6 %

           Branch data     Line data    Source code
       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                 :          7 : 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                 :          7 :     self = (PySSLCertificate *) type->tp_alloc(type, 0);
      26         [ -  + ]:          7 :     if (self == NULL) {
      27                 :          0 :         return NULL;
      28                 :            :     }
      29         [ +  + ]:          7 :     if (upref == 1) {
      30                 :          6 :         X509_up_ref(cert);
      31                 :            :     }
      32                 :          7 :     self->cert = cert;
      33                 :          7 :     self->hash = -1;
      34                 :            : 
      35                 :          7 :     return (PyObject *) self;
      36                 :            : }
      37                 :            : 
      38                 :            : static PyObject *
      39                 :          7 : _PySSL_CertificateFromX509(_sslmodulestate *state, X509 *cert, int upref)
      40                 :            : {
      41                 :          7 :     return newCertificate(state->PySSLCertificate_Type, cert, upref);
      42                 :            : }
      43                 :            : 
      44                 :            : static PyObject*
      45                 :          4 : _PySSL_CertificateFromX509Stack(_sslmodulestate *state, STACK_OF(X509) *stack, int upref)
      46                 :            : {
      47                 :            :     int len, i;
      48                 :          4 :     PyObject *result = NULL;
      49                 :            : 
      50                 :          4 :     len = sk_X509_num(stack);
      51                 :          4 :     result = PyList_New(len);
      52         [ -  + ]:          4 :     if (result == NULL) {
      53                 :          0 :         return NULL;
      54                 :            :     }
      55         [ +  + ]:         10 :     for (i = 0; i < len; i++) {
      56                 :          6 :         X509 *cert = sk_X509_value(stack, i);
      57                 :          6 :         PyObject *ocert = _PySSL_CertificateFromX509(state, cert, upref);
      58         [ -  + ]:          6 :         if (ocert == NULL) {
      59                 :          0 :             Py_DECREF(result);
      60                 :          0 :             return NULL;
      61                 :            :         }
      62                 :          6 :         PyList_SetItem(result, i, ocert);
      63                 :            :     }
      64                 :          4 :     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                 :          2 : _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                 :          2 :     _sslmodulestate *state = get_state_cert(self);
      81                 :            : 
      82                 :          2 :     bio = BIO_new(BIO_s_mem());
      83         [ -  + ]:          2 :     if (bio == NULL) {
      84                 :          0 :         PyErr_SetString(state->PySSLErrorObject,
      85                 :            :                         "failed to allocate BIO");
      86                 :          0 :         return NULL;
      87                 :            :     }
      88   [ +  -  +  - ]:          2 :     switch(format) {
      89                 :          1 :     case PY_SSL_ENCODING_PEM:
      90                 :          1 :         retcode = PEM_write_bio_X509(bio, self->cert);
      91                 :          1 :         break;
      92                 :          0 :     case PY_SSL_ENCODING_PEM_AUX:
      93                 :          0 :         retcode = PEM_write_bio_X509_AUX(bio, self->cert);
      94                 :          0 :         break;
      95                 :          1 :     case PY_SSL_ENCODING_DER:
      96                 :          1 :         retcode = i2d_X509_bio(bio, self->cert);
      97                 :          1 :         break;
      98                 :          0 :     default:
      99                 :          0 :         PyErr_SetString(PyExc_ValueError, "Unsupported format");
     100                 :          0 :         BIO_free(bio);
     101                 :          0 :         return NULL;
     102                 :            :     }
     103         [ -  + ]:          2 :     if (retcode != 1) {
     104                 :          0 :         BIO_free(bio);
     105                 :          0 :         _setSSLError(state, NULL, 0, __FILE__, __LINE__);
     106                 :          0 :         return NULL;
     107                 :            :     }
     108         [ +  + ]:          2 :     if (format == PY_SSL_ENCODING_DER) {
     109                 :          1 :         result = _PySSL_BytesFromBIO(state, bio);
     110                 :            :     } else {
     111                 :          1 :         result = _PySSL_UnicodeFromBIO(state, bio, "error");
     112                 :            :     }
     113                 :          2 :     BIO_free(bio);
     114                 :          2 :     return result;
     115                 :            : }
     116                 :            : 
     117                 :            : 
     118                 :            : /*[clinic input]
     119                 :            : _ssl.Certificate.get_info
     120                 :            : 
     121                 :            : [clinic start generated code]*/
     122                 :            : 
     123                 :            : static PyObject *
     124                 :          2 : _ssl_Certificate_get_info_impl(PySSLCertificate *self)
     125                 :            : /*[clinic end generated code: output=0f0deaac54f4408b input=ba2c1694b39d0778]*/
     126                 :            : {
     127                 :          2 :     return _decode_certificate(get_state_cert(self), self->cert);
     128                 :            : }
     129                 :            : 
     130                 :            : static PyObject*
     131                 :          6 : _x509name_print(_sslmodulestate *state, X509_NAME *name, int indent, unsigned long flags)
     132                 :            : {
     133                 :            :     PyObject *res;
     134                 :            :     BIO *biobuf;
     135                 :            : 
     136                 :          6 :     biobuf = BIO_new(BIO_s_mem());
     137         [ -  + ]:          6 :     if (biobuf == NULL) {
     138                 :          0 :         PyErr_SetString(PyExc_MemoryError, "failed to allocate BIO");
     139                 :          0 :         return NULL;
     140                 :            :     }
     141                 :            : 
     142         [ -  + ]:          6 :     if (X509_NAME_print_ex(biobuf, name, indent, flags) <= 0) {
     143                 :          0 :         _setSSLError(state, NULL, 0, __FILE__, __LINE__);
     144                 :          0 :         BIO_free(biobuf);
     145                 :          0 :         return NULL;
     146                 :            :     }
     147                 :          6 :     res = _PySSL_UnicodeFromBIO(state, biobuf, "strict");
     148                 :          6 :     BIO_free(biobuf);
     149                 :          6 :     return res;
     150                 :            : }
     151                 :            : 
     152                 :            : /* ************************************************************************
     153                 :            :  * PySSLCertificate_Type
     154                 :            :  */
     155                 :            : 
     156                 :            : static PyObject *
     157                 :          6 : certificate_repr(PySSLCertificate *self)
     158                 :            : {
     159                 :            :     PyObject *osubject, *result;
     160                 :            : 
     161                 :            :     /* subject string is ASCII encoded, UTF-8 chars are quoted */
     162                 :          6 :     osubject = _x509name_print(
     163                 :          6 :         get_state_cert(self),
     164                 :          6 :         X509_get_subject_name(self->cert),
     165                 :            :         0,
     166                 :            :         XN_FLAG_RFC2253
     167                 :            :     );
     168         [ -  + ]:          6 :     if (osubject == NULL)
     169                 :          0 :         return NULL;
     170                 :          6 :     result = PyUnicode_FromFormat(
     171                 :            :         "<%s '%U'>",
     172                 :          6 :         Py_TYPE(self)->tp_name, osubject
     173                 :            :     );
     174                 :          6 :     Py_DECREF(osubject);
     175                 :          6 :     return result;
     176                 :            : }
     177                 :            : 
     178                 :            : static Py_hash_t
     179                 :          4 : certificate_hash(PySSLCertificate *self)
     180                 :            : {
     181         [ +  + ]:          4 :     if (self->hash == (Py_hash_t)-1) {
     182                 :            :         unsigned long hash;
     183                 :          3 :         hash = X509_subject_name_hash(self->cert);
     184         [ -  + ]:          3 :         if ((Py_hash_t)hash == (Py_hash_t)-1) {
     185                 :          0 :             self->hash = -2;
     186                 :            :         } else {
     187                 :          3 :             self->hash = (Py_hash_t)hash;
     188                 :            :         }
     189                 :            :     }
     190                 :          4 :     return self->hash;
     191                 :            : }
     192                 :            : 
     193                 :            : static PyObject *
     194                 :          2 : certificate_richcompare(PySSLCertificate *self, PyObject *other, int op)
     195                 :            : {
     196                 :            :     int cmp;
     197                 :          2 :     _sslmodulestate *state = get_state_cert(self);
     198                 :            : 
     199         [ -  + ]:          2 :     if (Py_TYPE(other) != state->PySSLCertificate_Type) {
     200                 :          0 :         Py_RETURN_NOTIMPLEMENTED;
     201                 :            :     }
     202                 :            :     /* only support == and != */
     203   [ +  +  -  + ]:          2 :     if ((op != Py_EQ) && (op != Py_NE)) {
     204                 :          0 :         Py_RETURN_NOTIMPLEMENTED;
     205                 :            :     }
     206                 :          2 :     cmp = X509_cmp(self->cert, ((PySSLCertificate*)other)->cert);
     207   [ +  +  -  +  :          2 :     if (((op == Py_EQ) && (cmp == 0)) || ((op == Py_NE) && (cmp != 0))) {
             +  -  +  - ]
     208                 :          2 :         Py_RETURN_TRUE;
     209                 :            :     } else {
     210                 :          0 :         Py_RETURN_FALSE;
     211                 :            :     }
     212                 :            : }
     213                 :            : 
     214                 :            : static void
     215                 :          7 : certificate_dealloc(PySSLCertificate *self)
     216                 :            : {
     217                 :          7 :     PyTypeObject *tp = Py_TYPE(self);
     218                 :          7 :     X509_free(self->cert);
     219                 :          7 :     Py_TYPE(self)->tp_free(self);
     220                 :          7 :     Py_DECREF(tp);
     221                 :          7 : }
     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                 :            : };

Generated by: LCOV version 1.14