pyOpenSSL-0.13/0000755000214500021450000000000011630175113013235 5ustar bb-slavebb-slavepyOpenSSL-0.13/OpenSSL/0000755000214500021450000000000011630175113014520 5ustar bb-slavebb-slavepyOpenSSL-0.13/OpenSSL/crypto/0000755000214500021450000000000011630175113016040 5ustar bb-slavebb-slavepyOpenSSL-0.13/OpenSSL/crypto/crl.c0000644000214500021450000001713611630175105016775 0ustar bb-slavebb-slave#include #define crypto_MODULE #include "crypto.h" static X509_REVOKED * X509_REVOKED_dup(X509_REVOKED *orig) { X509_REVOKED *dupe = NULL; dupe = X509_REVOKED_new(); if (dupe == NULL) { return NULL; } if (orig->serialNumber) { dupe->serialNumber = M_ASN1_INTEGER_dup(orig->serialNumber); } if (orig->revocationDate) { dupe->revocationDate = M_ASN1_INTEGER_dup(orig->revocationDate); } if (orig->extensions) { STACK_OF(X509_EXTENSION) *sk = NULL; X509_EXTENSION * ext; int j; sk = sk_X509_EXTENSION_new_null(); for (j = 0; j < sk_X509_EXTENSION_num(orig->extensions); j++) { ext = sk_X509_EXTENSION_value(orig->extensions, j); ext = X509_EXTENSION_dup(ext); sk_X509_EXTENSION_push(sk, ext); } dupe->extensions = sk; } dupe->sequence = orig->sequence; return dupe; } static char crypto_CRL_get_revoked_doc[] = "\n\ Return revoked portion of the CRL structure (by value\n\ not reference).\n\ \n\ @return: A tuple of Revoked objects.\n\ "; static PyObject * crypto_CRL_get_revoked(crypto_CRLObj *self, PyObject *args) { int j, num_rev; X509_REVOKED *r = NULL; PyObject *obj = NULL, *rev_obj; if (!PyArg_ParseTuple(args, ":get_revoked")) { return NULL; } num_rev = sk_X509_REVOKED_num(self->crl->crl->revoked); if (num_rev < 0) { Py_INCREF(Py_None); return Py_None; } if ((obj = PyTuple_New(num_rev)) == NULL) { return NULL; } for (j = 0; j < num_rev; j++) { r = sk_X509_REVOKED_value(self->crl->crl->revoked, j); r = X509_REVOKED_dup(r); if (r == NULL ) { goto error; } rev_obj = (PyObject *) crypto_Revoked_New(r); if (rev_obj == NULL) { goto error; } r = NULL; /* it's now owned by rev_obj */ PyTuple_SET_ITEM(obj, j, rev_obj); } return obj; error: if (r) { X509_REVOKED_free(r); } Py_XDECREF(obj); return NULL; } static char crypto_CRL_add_revoked_doc[] = "\n\ Add a revoked (by value not reference) to the CRL structure\n\ \n\ @param cert: The new revoked.\n\ @type cert: L{X509}\n\ @return: None\n\ "; static PyObject * crypto_CRL_add_revoked(crypto_CRLObj *self, PyObject *args, PyObject *keywds) { crypto_RevokedObj * rev_obj = NULL; static char *kwlist[] = {"revoked", NULL}; X509_REVOKED * dup; if (!PyArg_ParseTupleAndKeywords(args, keywds, "O!:add_revoked", kwlist, &crypto_Revoked_Type, &rev_obj)) { return NULL; } dup = X509_REVOKED_dup( rev_obj->revoked ); if (dup == NULL) { return NULL; } X509_CRL_add0_revoked(self->crl, dup); Py_INCREF(Py_None); return Py_None; } static char crypto_CRL_export_doc[] = "\n\ export(cert, key[, type[, days]]) -> export a CRL as a string\n\ \n\ @param cert: Used to sign CRL.\n\ @type cert: L{X509}\n\ @param key: Used to sign CRL.\n\ @type key: L{PKey}\n\ @param type: The export format, either L{FILETYPE_PEM}, L{FILETYPE_ASN1}, or L{FILETYPE_TEXT}.\n\ @param days: The number of days until the next update of this CRL.\n\ @type days: L{int}\n\ @return: L{str}\n\ "; static PyObject * crypto_CRL_export(crypto_CRLObj *self, PyObject *args, PyObject *keywds) { int ret, buf_len, type = X509_FILETYPE_PEM, days = 100; char *temp; BIO *bio; PyObject *buffer; crypto_PKeyObj *key; ASN1_TIME *tmptm; crypto_X509Obj *x509; static char *kwlist[] = {"cert", "key", "type", "days", NULL}; if (!PyArg_ParseTupleAndKeywords(args, keywds, "O!O!|ii:dump_crl", kwlist, &crypto_X509_Type, &x509, &crypto_PKey_Type, &key, &type, &days)) { return NULL; } bio = BIO_new(BIO_s_mem()); tmptm = ASN1_TIME_new(); if (!tmptm) { return 0; } X509_gmtime_adj(tmptm,0); X509_CRL_set_lastUpdate(self->crl, tmptm); X509_gmtime_adj(tmptm,days*24*60*60); X509_CRL_set_nextUpdate(self->crl, tmptm); ASN1_TIME_free(tmptm); X509_CRL_set_issuer_name(self->crl, X509_get_subject_name(x509->x509)); X509_CRL_sign(self->crl, key->pkey, EVP_md5()); switch (type) { case X509_FILETYPE_PEM: ret = PEM_write_bio_X509_CRL(bio, self->crl); break; case X509_FILETYPE_ASN1: ret = (int) i2d_X509_CRL_bio(bio, self->crl); break; case X509_FILETYPE_TEXT: ret = X509_CRL_print(bio, self->crl); break; default: PyErr_SetString( PyExc_ValueError, "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT"); return NULL; } if (!ret) { exception_from_error_queue(crypto_Error); BIO_free(bio); return NULL; } buf_len = BIO_get_mem_data(bio, &temp); buffer = PyBytes_FromStringAndSize(temp, buf_len); BIO_free(bio); return buffer; } crypto_CRLObj * crypto_CRL_New(X509_CRL *crl) { crypto_CRLObj *self; self = PyObject_New(crypto_CRLObj, &crypto_CRL_Type); if (self == NULL) { return NULL; } self->crl = crl; return self; } /* * ADD_METHOD(name) expands to a correct PyMethodDef declaration * { 'name', (PyCFunction)crypto_CRL_name, METH_VARARGS, crypto_CRL_name_doc } * for convenience */ #define ADD_METHOD(name) \ { #name, (PyCFunction)crypto_CRL_##name, METH_VARARGS, crypto_CRL_##name##_doc } #define ADD_KW_METHOD(name) \ { #name, (PyCFunction)crypto_CRL_##name, METH_VARARGS | METH_KEYWORDS, crypto_CRL_##name##_doc } static PyMethodDef crypto_CRL_methods[] = { ADD_KW_METHOD(add_revoked), ADD_METHOD(get_revoked), ADD_KW_METHOD(export), { NULL, NULL } }; #undef ADD_METHOD static void crypto_CRL_dealloc(crypto_CRLObj *self) { X509_CRL_free(self->crl); self->crl = NULL; PyObject_Del(self); } static char crypto_CRL_doc[] = "\n\ CRL() -> CRL instance\n\ \n\ Create a new empty CRL object.\n\ \n\ @returns: The CRL object\n\ "; static PyObject* crypto_CRL_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) { if (!PyArg_ParseTuple(args, ":CRL")) { return NULL; } return (PyObject *)crypto_CRL_New(X509_CRL_new()); } PyTypeObject crypto_CRL_Type = { PyOpenSSL_HEAD_INIT(&PyType_Type, 0) "CRL", sizeof(crypto_CRLObj), 0, (destructor)crypto_CRL_dealloc, NULL, /* print */ NULL, /* getattr */ NULL, /* setattr */ NULL, /* compare */ NULL, /* repr */ NULL, /* as_number */ NULL, /* as_sequence */ NULL, /* as_mapping */ NULL, /* hash */ NULL, /* call */ NULL, /* str */ NULL, /* getattro */ NULL, /* setattro */ NULL, /* as_buffer */ Py_TPFLAGS_DEFAULT, crypto_CRL_doc, /* doc */ NULL, /* traverse */ NULL, /* clear */ NULL, /* tp_richcompare */ 0, /* tp_weaklistoffset */ NULL, /* tp_iter */ NULL, /* tp_iternext */ crypto_CRL_methods, /* tp_methods */ NULL, /* tp_members */ NULL, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ NULL, /* tp_descr_get */ NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ NULL, /* tp_init */ NULL, /* tp_alloc */ crypto_CRL_new, /* tp_new */ }; int init_crypto_crl(PyObject *module) { if (PyType_Ready(&crypto_CRL_Type) < 0) { return 0; } /* PyModule_AddObject steals a reference. */ Py_INCREF((PyObject *)&crypto_CRL_Type); if (PyModule_AddObject(module, "CRL", (PyObject *)&crypto_CRL_Type) != 0) { return 0; } return 1; } pyOpenSSL-0.13/OpenSSL/crypto/crl.h0000644000214500021450000000056411630175105016777 0ustar bb-slavebb-slave#ifndef PyOpenSSL_crypto_CRL_H_ #define PyOpenSSL_crypto_CRL_H_ #include extern int init_crypto_crl (PyObject *); extern PyTypeObject crypto_CRL_Type; #define crypto_CRL_Check(v) ((v)->ob_type == &crypto_CRL_Type) typedef struct { PyObject_HEAD X509_CRL *crl; } crypto_CRLObj; crypto_CRLObj * crypto_CRL_New(X509_CRL *crl); #endif pyOpenSSL-0.13/OpenSSL/crypto/crypto.c0000644000214500021450000005726511630175105017544 0ustar bb-slavebb-slave/* * crypto.c * * Copyright (C) AB Strakt * Copyright (C) Keyphrene * Copyright (C) Jean-Paul Calderone * See LICENSE for details. * * Main file of crypto sub module. * See the file RATIONALE for a short explanation of why this module was written. * * Reviewed 2001-07-23 */ #include #define crypto_MODULE #include "crypto.h" #include "pkcs12.h" static char crypto_doc[] = "\n\ Main file of crypto sub module.\n\ See the file RATIONALE for a short explanation of why this module was written.\n\ "; void **ssl_API; PyObject *crypto_Error; int crypto_byte_converter(PyObject *input, void* output) { char **message = output; if (input == Py_None) { *message = NULL; } else if (PyBytes_CheckExact(input)) { *message = PyBytes_AsString(input); } else { return 0; } return 1; } static int global_passphrase_callback(char *buf, int len, int rwflag, void *cb_arg) { PyObject *func, *argv, *ret; int nchars; func = (PyObject *)cb_arg; argv = Py_BuildValue("(i)", rwflag); ret = PyEval_CallObject(func, argv); Py_DECREF(argv); if (ret == NULL) return 0; if (!PyBytes_Check(ret)) { PyErr_SetString(PyExc_ValueError, "String expected"); return 0; } nchars = PyBytes_Size(ret); if (nchars > len) nchars = len; strncpy(buf, PyBytes_AsString(ret), nchars); return nchars; } static char crypto_load_privatekey_doc[] = "\n\ Load a private key from a buffer\n\ \n\ @param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\ @param buffer: The buffer the key is stored in\n\ @param passphrase: (optional) if encrypted PEM format, this can be\n\ either the passphrase to use, or a callback for\n\ providing the passphrase.\n\ \n\ @return: The PKey object\n\ "; static PyObject * crypto_load_privatekey(PyObject *spam, PyObject *args) { crypto_PKeyObj *crypto_PKey_New(EVP_PKEY *, int); int type, len; char *buffer; PyObject *pw = NULL; pem_password_cb *cb = NULL; void *cb_arg = NULL; BIO *bio; EVP_PKEY *pkey; if (!PyArg_ParseTuple(args, "is#|O:load_privatekey", &type, &buffer, &len, &pw)) return NULL; if (pw != NULL) { if (PyBytes_Check(pw)) { cb = NULL; cb_arg = PyBytes_AsString(pw); } else if (PyCallable_Check(pw)) { cb = global_passphrase_callback; cb_arg = pw; } else { PyErr_SetString(PyExc_TypeError, "Last argument must be string or callable"); return NULL; } } bio = BIO_new_mem_buf(buffer, len); switch (type) { case X509_FILETYPE_PEM: pkey = PEM_read_bio_PrivateKey(bio, NULL, cb, cb_arg); break; case X509_FILETYPE_ASN1: pkey = d2i_PrivateKey_bio(bio, NULL); break; default: PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM or FILETYPE_ASN1"); BIO_free(bio); return NULL; } BIO_free(bio); if (pkey == NULL) { exception_from_error_queue(crypto_Error); return NULL; } return (PyObject *)crypto_PKey_New(pkey, 1); } static char crypto_dump_privatekey_doc[] = "\n\ Dump a private key to a buffer\n\ \n\ @param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\ @param pkey: The PKey to dump\n\ @param cipher: (optional) if encrypted PEM format, the cipher to\n\ use\n\ @param passphrase - (optional) if encrypted PEM format, this can be either\n\ the passphrase to use, or a callback for providing the\n\ passphrase.\n\ @return: The buffer with the dumped key in\n\ @rtype: C{str}\n\ "; static PyObject * crypto_dump_privatekey(PyObject *spam, PyObject *args) { int type, ret, buf_len; char *temp; PyObject *buffer; char *cipher_name = NULL; const EVP_CIPHER *cipher = NULL; PyObject *pw = NULL; pem_password_cb *cb = NULL; void *cb_arg = NULL; BIO *bio; RSA *rsa; crypto_PKeyObj *pkey; if (!PyArg_ParseTuple(args, "iO!|sO:dump_privatekey", &type, &crypto_PKey_Type, &pkey, &cipher_name, &pw)) return NULL; if (cipher_name != NULL && pw == NULL) { PyErr_SetString(PyExc_ValueError, "Illegal number of arguments"); return NULL; } if (cipher_name != NULL) { cipher = EVP_get_cipherbyname(cipher_name); if (cipher == NULL) { PyErr_SetString(PyExc_ValueError, "Invalid cipher name"); return NULL; } if (PyBytes_Check(pw)) { cb = NULL; cb_arg = PyBytes_AsString(pw); } else if (PyCallable_Check(pw)) { cb = global_passphrase_callback; cb_arg = pw; } else { PyErr_SetString(PyExc_TypeError, "Last argument must be string or callable"); return NULL; } } bio = BIO_new(BIO_s_mem()); switch (type) { case X509_FILETYPE_PEM: ret = PEM_write_bio_PrivateKey(bio, pkey->pkey, cipher, NULL, 0, cb, cb_arg); if (PyErr_Occurred()) { BIO_free(bio); return NULL; } break; case X509_FILETYPE_ASN1: ret = i2d_PrivateKey_bio(bio, pkey->pkey); break; case X509_FILETYPE_TEXT: rsa = EVP_PKEY_get1_RSA(pkey->pkey); ret = RSA_print(bio, rsa, 0); RSA_free(rsa); break; default: PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT"); BIO_free(bio); return NULL; } if (ret == 0) { BIO_free(bio); exception_from_error_queue(crypto_Error); return NULL; } buf_len = BIO_get_mem_data(bio, &temp); buffer = PyBytes_FromStringAndSize(temp, buf_len); BIO_free(bio); return buffer; } static char crypto_load_certificate_doc[] = "\n\ Load a certificate from a buffer\n\ \n\ @param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\ buffer - The buffer the certificate is stored in\n\ @return: The X509 object\n\ "; static PyObject * crypto_load_certificate(PyObject *spam, PyObject *args) { crypto_X509Obj *crypto_X509_New(X509 *, int); int type, len; char *buffer; BIO *bio; X509 *cert; if (!PyArg_ParseTuple(args, "is#:load_certificate", &type, &buffer, &len)) return NULL; bio = BIO_new_mem_buf(buffer, len); switch (type) { case X509_FILETYPE_PEM: cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); break; case X509_FILETYPE_ASN1: cert = d2i_X509_bio(bio, NULL); break; default: PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM or FILETYPE_ASN1"); BIO_free(bio); return NULL; } BIO_free(bio); if (cert == NULL) { exception_from_error_queue(crypto_Error); return NULL; } return (PyObject *)crypto_X509_New(cert, 1); } static char crypto_dump_certificate_doc[] = "\n\ Dump a certificate to a buffer\n\ \n\ @param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\ @param cert: The certificate to dump\n\ @return: The buffer with the dumped certificate in\n\ "; static PyObject * crypto_dump_certificate(PyObject *spam, PyObject *args) { int type, ret, buf_len; char *temp; PyObject *buffer; BIO *bio; crypto_X509Obj *cert; if (!PyArg_ParseTuple(args, "iO!:dump_certificate", &type, &crypto_X509_Type, &cert)) return NULL; bio = BIO_new(BIO_s_mem()); switch (type) { case X509_FILETYPE_PEM: ret = PEM_write_bio_X509(bio, cert->x509); break; case X509_FILETYPE_ASN1: ret = i2d_X509_bio(bio, cert->x509); break; case X509_FILETYPE_TEXT: ret = X509_print_ex(bio, cert->x509, 0, 0); break; default: PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT"); BIO_free(bio); return NULL; } if (ret == 0) { BIO_free(bio); exception_from_error_queue(crypto_Error); return NULL; } buf_len = BIO_get_mem_data(bio, &temp); buffer = PyBytes_FromStringAndSize(temp, buf_len); BIO_free(bio); return buffer; } static char crypto_load_certificate_request_doc[] = "\n\ Load a certificate request from a buffer\n\ \n\ @param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\ buffer - The buffer the certificate request is stored in\n\ @return: The X509Req object\n\ "; static PyObject * crypto_load_certificate_request(PyObject *spam, PyObject *args) { crypto_X509ReqObj *crypto_X509Req_New(X509_REQ *, int); int type, len; char *buffer; BIO *bio; X509_REQ *req; if (!PyArg_ParseTuple(args, "is#:load_certificate_request", &type, &buffer, &len)) return NULL; bio = BIO_new_mem_buf(buffer, len); switch (type) { case X509_FILETYPE_PEM: req = PEM_read_bio_X509_REQ(bio, NULL, NULL, NULL); break; case X509_FILETYPE_ASN1: req = d2i_X509_REQ_bio(bio, NULL); break; default: PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM or FILETYPE_ASN1"); BIO_free(bio); return NULL; } BIO_free(bio); if (req == NULL) { exception_from_error_queue(crypto_Error); return NULL; } return (PyObject *)crypto_X509Req_New(req, 1); } static char crypto_dump_certificate_request_doc[] = "\n\ Dump a certificate request to a buffer\n\ \n\ @param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\ req - The certificate request to dump\n\ @return: The buffer with the dumped certificate request in\n\ "; static PyObject * crypto_dump_certificate_request(PyObject *spam, PyObject *args) { int type, ret, buf_len; char *temp; PyObject *buffer; BIO *bio; crypto_X509ReqObj *req; if (!PyArg_ParseTuple(args, "iO!:dump_certificate_request", &type, &crypto_X509Req_Type, &req)) return NULL; bio = BIO_new(BIO_s_mem()); switch (type) { case X509_FILETYPE_PEM: ret = PEM_write_bio_X509_REQ(bio, req->x509_req); break; case X509_FILETYPE_ASN1: ret = i2d_X509_REQ_bio(bio, req->x509_req); break; case X509_FILETYPE_TEXT: ret = X509_REQ_print_ex(bio, req->x509_req, 0, 0); break; default: PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT"); BIO_free(bio); return NULL; } if (ret == 0) { BIO_free(bio); exception_from_error_queue(crypto_Error); return NULL; } buf_len = BIO_get_mem_data(bio, &temp); buffer = PyBytes_FromStringAndSize(temp, buf_len); BIO_free(bio); return buffer; } static char crypto_load_crl_doc[] = "\n\ Load a certificate revocation list from a buffer\n\ \n\ @param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\ @param buffer: The buffer the CRL is stored in\n\ \n\ @return: The PKey object\n\ "; static PyObject * crypto_load_crl(PyObject *spam, PyObject *args) { int type, len; char *buffer; BIO *bio; X509_CRL *crl; if (!PyArg_ParseTuple(args, "is#:load_crl", &type, &buffer, &len)) { return NULL; } bio = BIO_new_mem_buf(buffer, len); switch (type) { case X509_FILETYPE_PEM: crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL); break; case X509_FILETYPE_ASN1: crl = d2i_X509_CRL_bio(bio, NULL); break; default: PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM or FILETYPE_ASN1"); BIO_free(bio); return NULL; } BIO_free(bio); if (crl == NULL) { exception_from_error_queue(crypto_Error); return NULL; } return (PyObject *)crypto_CRL_New(crl); } static char crypto_load_pkcs7_data_doc[] = "\n\ Load pkcs7 data from a buffer\n\ \n\ @param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)\n\ buffer - The buffer with the pkcs7 data.\n\ @return: The PKCS7 object\n\ "; static PyObject * crypto_load_pkcs7_data(PyObject *spam, PyObject *args) { int type, len; char *buffer; BIO *bio; PKCS7 *pkcs7 = NULL; if (!PyArg_ParseTuple(args, "is#:load_pkcs7_data", &type, &buffer, &len)) return NULL; /* * Try to read the pkcs7 data from the bio */ bio = BIO_new_mem_buf(buffer, len); switch (type) { case X509_FILETYPE_PEM: pkcs7 = PEM_read_bio_PKCS7(bio, NULL, NULL, NULL); break; case X509_FILETYPE_ASN1: pkcs7 = d2i_PKCS7_bio(bio, NULL); break; default: PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM or FILETYPE_ASN1"); return NULL; } BIO_free(bio); /* * Check if we got a PKCS7 structure */ if (pkcs7 == NULL) { exception_from_error_queue(crypto_Error); return NULL; } return (PyObject *)crypto_PKCS7_New(pkcs7, 1); } static char crypto_load_pkcs12_doc[] = "\n\ Load a PKCS12 object from a buffer\n\ \n\ @param buffer: The buffer the certificate is stored in\n\ passphrase (Optional) - The password to decrypt the PKCS12 lump\n\ @returns: The PKCS12 object\n\ "; static PyObject * crypto_load_pkcs12(PyObject *spam, PyObject *args) { int len; char *buffer, *passphrase = NULL; BIO *bio; PKCS12 *p12; if (!PyArg_ParseTuple(args, "s#|s:load_pkcs12", &buffer, &len, &passphrase)) return NULL; bio = BIO_new_mem_buf(buffer, len); if ((p12 = d2i_PKCS12_bio(bio, NULL)) == NULL) { BIO_free(bio); exception_from_error_queue(crypto_Error); return NULL; } BIO_free(bio); return (PyObject *)crypto_PKCS12_New(p12, passphrase); } static char crypto_X509_verify_cert_error_string_doc[] = "\n\ Get X509 verify certificate error string.\n\ \n\ @param errnum: The error number.\n\ @return: Error string as a Python string\n\ "; static PyObject * crypto_X509_verify_cert_error_string(PyObject *spam, PyObject *args) { int errnum; const char *str; if (!PyArg_ParseTuple(args, "i", &errnum)) return NULL; str = X509_verify_cert_error_string(errnum); return PyText_FromString(str); } static char crypto_exception_from_error_queue_doc[] = "\n\ Raise an exception from the current OpenSSL error queue.\n\ "; static PyObject * crypto_exception_from_error_queue(PyObject *spam, PyObject *eggs) { exception_from_error_queue(crypto_Error); return NULL; } static char crypto_sign_doc[] = "\n\ Sign data with a digest\n\ \n\ @param pkey: Pkey to sign with\n\ @param data: data to be signed\n\ @param digest: message digest to use\n\ @return: signature\n\ "; static PyObject * crypto_sign(PyObject *spam, PyObject *args) { PyObject *buffer; crypto_PKeyObj *pkey; char *data = NULL; int data_len; char *digest_name; int err; unsigned int sig_len; const EVP_MD *digest; EVP_MD_CTX md_ctx; unsigned char sig_buf[512]; if (!PyArg_ParseTuple( args, "O!" BYTESTRING_FMT "#s:sign", &crypto_PKey_Type, &pkey, &data, &data_len, &digest_name)) { return NULL; } if ((digest = EVP_get_digestbyname(digest_name)) == NULL) { PyErr_SetString(PyExc_ValueError, "No such digest method"); return NULL; } EVP_SignInit(&md_ctx, digest); EVP_SignUpdate(&md_ctx, data, data_len); sig_len = sizeof(sig_buf); err = EVP_SignFinal(&md_ctx, sig_buf, &sig_len, pkey->pkey); if (err != 1) { exception_from_error_queue(crypto_Error); return NULL; } buffer = PyBytes_FromStringAndSize((char*)sig_buf, sig_len); return buffer; } static char crypto_verify_doc[] = "\n\ Verify a signature\n\ \n\ @param cert: signing certificate (X509 object)\n\ @param signature: signature returned by sign function\n\ @param data: data to be verified\n\ @param digest: message digest to use\n\ @return: None if the signature is correct, raise exception otherwise\n\ "; static PyObject * crypto_verify(PyObject *spam, PyObject *args) { crypto_X509Obj *cert; unsigned char *signature; int sig_len; char *data, *digest_name; int data_len; int err; const EVP_MD *digest; EVP_MD_CTX md_ctx; EVP_PKEY *pkey; #ifdef PY3 if (!PyArg_ParseTuple(args, "O!" BYTESTRING_FMT "#" BYTESTRING_FMT "#s:verify", &crypto_X509_Type, &cert, &signature, &sig_len, &data, &data_len, &digest_name)) { #else if (!PyArg_ParseTuple(args, "O!t#s#s:verify", &crypto_X509_Type, &cert, &signature, &sig_len, &data, &data_len, &digest_name)) { #endif return NULL; } if ((digest = EVP_get_digestbyname(digest_name)) == NULL){ PyErr_SetString(PyExc_ValueError, "No such digest method"); return NULL; } pkey = X509_get_pubkey(cert->x509); if (pkey == NULL) { PyErr_SetString(PyExc_ValueError, "No public key"); return NULL; } EVP_VerifyInit(&md_ctx, digest); EVP_VerifyUpdate(&md_ctx, data, data_len); err = EVP_VerifyFinal(&md_ctx, signature, sig_len, pkey); EVP_PKEY_free(pkey); if (err != 1) { exception_from_error_queue(crypto_Error); return NULL; } Py_INCREF(Py_None); return Py_None; } /* Methods in the OpenSSL.crypto module (i.e. none) */ static PyMethodDef crypto_methods[] = { /* Module functions */ { "load_privatekey", (PyCFunction)crypto_load_privatekey, METH_VARARGS, crypto_load_privatekey_doc }, { "dump_privatekey", (PyCFunction)crypto_dump_privatekey, METH_VARARGS, crypto_dump_privatekey_doc }, { "load_certificate", (PyCFunction)crypto_load_certificate, METH_VARARGS, crypto_load_certificate_doc }, { "dump_certificate", (PyCFunction)crypto_dump_certificate, METH_VARARGS, crypto_dump_certificate_doc }, { "load_certificate_request", (PyCFunction)crypto_load_certificate_request, METH_VARARGS, crypto_load_certificate_request_doc }, { "dump_certificate_request", (PyCFunction)crypto_dump_certificate_request, METH_VARARGS, crypto_dump_certificate_request_doc }, { "load_crl", (PyCFunction)crypto_load_crl, METH_VARARGS, crypto_load_crl_doc }, { "load_pkcs7_data", (PyCFunction)crypto_load_pkcs7_data, METH_VARARGS, crypto_load_pkcs7_data_doc }, { "load_pkcs12", (PyCFunction)crypto_load_pkcs12, METH_VARARGS, crypto_load_pkcs12_doc }, { "sign", (PyCFunction)crypto_sign, METH_VARARGS, crypto_sign_doc }, { "verify", (PyCFunction)crypto_verify, METH_VARARGS, crypto_verify_doc }, { "X509_verify_cert_error_string", (PyCFunction)crypto_X509_verify_cert_error_string, METH_VARARGS, crypto_X509_verify_cert_error_string_doc }, { "_exception_from_error_queue", (PyCFunction)crypto_exception_from_error_queue, METH_NOARGS, crypto_exception_from_error_queue_doc }, { NULL, NULL } }; #ifdef WITH_THREAD #include /** * This array will store all of the mutexes available to OpenSSL. */ static PyThread_type_lock *mutex_buf = NULL; /** * Callback function supplied to OpenSSL to acquire or release a lock. * */ static void locking_function(int mode, int n, const char * file, int line) { if (mode & CRYPTO_LOCK) { PyThread_acquire_lock(mutex_buf[n], WAIT_LOCK); } else { PyThread_release_lock(mutex_buf[n]); } } /** * Initialize OpenSSL for use from multiple threads. * * Returns: 0 if initialization fails, 1 otherwise. */ static int init_openssl_threads(void) { int i; mutex_buf = (PyThread_type_lock *)malloc( CRYPTO_num_locks() * sizeof(PyThread_type_lock)); if (!mutex_buf) { return 0; } for (i = 0; i < CRYPTO_num_locks(); ++i) { mutex_buf[i] = PyThread_allocate_lock(); } CRYPTO_set_id_callback((unsigned long (*)(void))PyThread_get_thread_ident); CRYPTO_set_locking_callback(locking_function); return 1; } /* /\** */ /* * Clean up after OpenSSL thread initialization. */ /* *\/ */ /* static int deinit_openssl_threads() { */ /* int i; */ /* if (!mutex_buf) { */ /* return 0; */ /* } */ /* CRYPTO_set_id_callback(NULL); */ /* CRYPTO_set_locking_callback(NULL); */ /* for (i = 0; i < CRYPTO_num_locks(); i++) { */ /* PyThread_free_lock(mutex_buf[i]); */ /* } */ /* free(mutex_buf); */ /* mutex_buf = NULL; */ /* return 1; */ /* } */ #endif #ifdef PY3 static struct PyModuleDef cryptomodule = { PyModuleDef_HEAD_INIT, "crypto", crypto_doc, -1, crypto_methods }; #endif /* * Initialize crypto sub module * * Arguments: None * Returns: None */ PyOpenSSL_MODINIT(crypto) { #ifndef PY3 static void *crypto_API[crypto_API_pointers]; PyObject *c_api_object; #endif PyObject *module; ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); #ifdef PY3 module = PyModule_Create(&cryptomodule); #else module = Py_InitModule3("crypto", crypto_methods, crypto_doc); #endif if (module == NULL) { PyOpenSSL_MODRETURN(NULL); } #ifndef PY3 /* Initialize the C API pointer array */ crypto_API[crypto_X509_New_NUM] = (void *)crypto_X509_New; crypto_API[crypto_X509Name_New_NUM] = (void *)crypto_X509Name_New; crypto_API[crypto_X509Req_New_NUM] = (void *)crypto_X509Req_New; crypto_API[crypto_X509Store_New_NUM] = (void *)crypto_X509Store_New; crypto_API[crypto_PKey_New_NUM] = (void *)crypto_PKey_New; crypto_API[crypto_X509Extension_New_NUM] = (void *)crypto_X509Extension_New; crypto_API[crypto_PKCS7_New_NUM] = (void *)crypto_PKCS7_New; crypto_API[crypto_NetscapeSPKI_New_NUM] = (void *)crypto_NetscapeSPKI_New; c_api_object = PyCObject_FromVoidPtr((void *)crypto_API, NULL); if (c_api_object != NULL) { /* PyModule_AddObject steals a reference. */ Py_INCREF(c_api_object); PyModule_AddObject(module, "_C_API", c_api_object); } #endif crypto_Error = PyErr_NewException("OpenSSL.crypto.Error", NULL, NULL); if (crypto_Error == NULL) goto error; /* PyModule_AddObject steals a reference. */ Py_INCREF(crypto_Error); if (PyModule_AddObject(module, "Error", crypto_Error) != 0) goto error; PyModule_AddIntConstant(module, "FILETYPE_PEM", X509_FILETYPE_PEM); PyModule_AddIntConstant(module, "FILETYPE_ASN1", X509_FILETYPE_ASN1); PyModule_AddIntConstant(module, "FILETYPE_TEXT", X509_FILETYPE_TEXT); PyModule_AddIntConstant(module, "TYPE_RSA", crypto_TYPE_RSA); PyModule_AddIntConstant(module, "TYPE_DSA", crypto_TYPE_DSA); #ifdef WITH_THREAD if (!init_openssl_threads()) goto error; #endif if (!init_crypto_x509(module)) goto error; if (!init_crypto_x509name(module)) goto error; if (!init_crypto_x509store(module)) goto error; if (!init_crypto_x509req(module)) goto error; if (!init_crypto_pkey(module)) goto error; if (!init_crypto_x509extension(module)) goto error; if (!init_crypto_pkcs7(module)) goto error; if (!init_crypto_pkcs12(module)) goto error; if (!init_crypto_netscape_spki(module)) goto error; if (!init_crypto_crl(module)) goto error; if (!init_crypto_revoked(module)) goto error; PyOpenSSL_MODRETURN(module); error: PyOpenSSL_MODRETURN(NULL); ; } pyOpenSSL-0.13/OpenSSL/crypto/crypto.h0000644000214500021450000001205011630175105017530 0ustar bb-slavebb-slave/* * crypto.h * * Copyright (C) AB Strakt * See LICENSE for details. * * Exports from crypto.c. * See the file RATIONALE for a short explanation of why this module was written. * * Reviewed 2001-07-23 * */ #ifndef PyOpenSSL_CRYPTO_H_ #define PyOpenSSL_CRYPTO_H_ #include /* Work around a bug in OpenSSL 1.0.0 which is caused by winsock.h being included (from dtls1.h) too late by the OpenSSL header files, overriding the fixes (in ossl_typ.h) for symbol clashes caused by this OS header file. In order to have those fixes still take effect, we include winsock.h here, prior to including any OpenSSL header files. */ #ifdef _WIN32 # include "winsock.h" #endif #include "x509.h" #include "x509name.h" #include "netscape_spki.h" #include "x509store.h" #include "x509req.h" #include "pkey.h" #include "x509ext.h" #include "pkcs7.h" #include "pkcs12.h" #include "crl.h" #include "revoked.h" #include "../util.h" extern PyObject *crypto_Error; #define crypto_X509_New_NUM 0 #define crypto_X509_New_RETURN crypto_X509Obj * #define crypto_X509_New_PROTO (X509 *, int) #define crypto_X509Req_New_NUM 1 #define crypto_X509Req_New_RETURN crypto_X509ReqObj * #define crypto_X509Req_New_PROTO (X509_REQ *, int) #define crypto_X509Store_New_NUM 2 #define crypto_X509Store_New_RETURN crypto_X509StoreObj * #define crypto_X509Store_New_PROTO (X509_STORE *, int) #define crypto_PKey_New_NUM 3 #define crypto_PKey_New_RETURN crypto_PKeyObj * #define crypto_PKey_New_PROTO (EVP_PKEY *, int) #define crypto_X509Name_New_NUM 4 #define crypto_X509Name_New_RETURN crypto_X509NameObj * #define crypto_X509Name_New_PROTO (X509_NAME *, int) #define crypto_X509Extension_New_NUM 5 #define crypto_X509Extension_New_RETURN crypto_X509ExtensionObj * #define crypto_X509Extension_New_PROTO (char *, int, char *, crypto_X509Obj *, crypto_X509Obj *) #define crypto_PKCS7_New_NUM 6 #define crypto_PKCS7_New_RETURN crypto_PKCS7Obj * #define crypto_PKCS7_New_PROTO (PKCS7 *, int) #define crypto_NetscapeSPKI_New_NUM 7 #define crypto_NetscapeSPKI_New_RETURN crypto_NetscapeSPKIObj * #define crypto_NetscapeSPKI_New_PROTO (NETSCAPE_SPKI *, int) #define crypto_API_pointers 8 #if defined(PY3) || defined(crypto_MODULE) #ifdef _WIN32 #define EXPORT __declspec(dllexport) #else #define EXPORT #endif extern EXPORT crypto_X509_New_RETURN crypto_X509_New crypto_X509_New_PROTO; extern EXPORT crypto_X509Name_New_RETURN crypto_X509Name_New crypto_X509Name_New_PROTO; extern crypto_X509Req_New_RETURN crypto_X509Req_New crypto_X509Req_New_PROTO; extern EXPORT crypto_X509Store_New_RETURN crypto_X509Store_New crypto_X509Store_New_PROTO; extern crypto_PKey_New_RETURN crypto_PKey_New crypto_PKey_New_PROTO; extern crypto_X509Extension_New_RETURN crypto_X509Extension_New crypto_X509Extension_New_PROTO; extern crypto_PKCS7_New_RETURN crypto_PKCS7_New crypto_PKCS7_New_PROTO; extern crypto_NetscapeSPKI_New_RETURN crypto_NetscapeSPKI_New crypto_NetscapeSPKI_New_PROTO; int crypto_byte_converter(PyObject *input, void *output); #else /* crypto_MODULE */ extern void **crypto_API; #define crypto_X509_New \ (*(crypto_X509_New_RETURN (*)crypto_X509_New_PROTO) crypto_API[crypto_X509_New_NUM]) #define crypto_X509Name_New \ (*(crypto_X509Name_New_RETURN (*)crypto_X509Name_New_PROTO) crypto_API[crypto_X509Name_New_NUM]) #define crypto_X509Req_New \ (*(crypto_X509Req_New_RETURN (*)crypto_X509Req_New_PROTO) crypto_API[crypto_X509Req_New_NUM]) #define crypto_X509Store_New \ (*(crypto_X509Store_New_RETURN (*)crypto_X509Store_New_PROTO) crypto_API[crypto_X509Store_New_NUM]) #define crypto_PKey_New \ (*(crypto_PKey_New_RETURN (*)crypto_PKey_New_PROTO) crypto_API[crypto_PKey_New_NUM]) #define crypto_X509Extension_New\ (*(crypto_X509Extension_New_RETURN (*)crypto_X509Extension_New_PROTO) crypto_API[crypto_X509Extension_New_NUM]) #define crypto_PKCS7_New \ (*(crypto_PKCS7_New_RETURN (*)crypto_PKCS7_New_PROTO) crypto_API[crypto_PKCS7_New_NUM]) #define crypto_NetscapeSPKI_New \ (*(crypto_NetscapeSPKI_New_RETURN (*)crypto_NetscapeSPKI_New_PROTO) crypto_API[crypto_NetscapeSPKI_New_NUM]) #define import_crypto() \ { \ PyObject *crypto_module = PyImport_ImportModule("OpenSSL.crypto"); \ if (crypto_module != NULL) { \ PyObject *crypto_dict, *crypto_api_object; \ crypto_dict = PyModule_GetDict(crypto_module); \ crypto_api_object = PyDict_GetItemString(crypto_dict, "_C_API"); \ if (crypto_api_object && PyCObject_Check(crypto_api_object)) { \ crypto_API = (void **)PyCObject_AsVoidPtr(crypto_api_object); \ } \ } \ } #endif /* crypto_MODULE */ /* Define a new type for emitting text. Hopefully these don't collide with * future official OpenSSL constants, but the switch statement of * dump_certificate() will alert us if it matters. */ #ifndef X509_FILETYPE_TEXT #define X509_FILETYPE_TEXT (58) #endif #endif /* PyOpenSSL_CRYPTO_H_ */ pyOpenSSL-0.13/OpenSSL/crypto/netscape_spki.c0000644000214500021450000001722011630175105021037 0ustar bb-slavebb-slave/* * netscape_spki.c * * Copyright (C) Tollef Fog Heen * See LICENSE for details. * * Netscape SPKI handling, thin wrapper */ #include #define crypto_MODULE #include "crypto.h" /* * Constructor for Nestcape_SPKI, never called by Python code directly * * Arguments: name - A "real" NetscapeSPKI object * dealloc - Boolean value to specify whether the destructor should * free the "real" NetscapeSPKI object * Returns: The newly created NetscapeSPKI object */ crypto_NetscapeSPKIObj * crypto_NetscapeSPKI_New(NETSCAPE_SPKI *name, int dealloc) { crypto_NetscapeSPKIObj *self; self = PyObject_New(crypto_NetscapeSPKIObj, &crypto_NetscapeSPKI_Type); if (self == NULL) return NULL; self->netscape_spki = name; self->dealloc = dealloc; return self; } static char crypto_NetscapeSPKI_doc[] = "\n\ NetscapeSPKI([enc]) -> NetscapeSPKI instance\n\ \n\ @param enc: Base64 encoded NetscapeSPKI object.\n\ @type enc: C{str}\n\ @return: The NetscapeSPKI object\n\ "; static PyObject * crypto_NetscapeSPKI_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) { char *enc = NULL; int enc_len = -1; NETSCAPE_SPKI *spki; if (!PyArg_ParseTuple(args, "|s#:NetscapeSPKI", &enc, &enc_len)) return NULL; if (enc_len >= 0) spki = NETSCAPE_SPKI_b64_decode(enc, enc_len); else spki = NETSCAPE_SPKI_new(); if (spki == NULL) { exception_from_error_queue(crypto_Error); return NULL; } return (PyObject *)crypto_NetscapeSPKI_New(spki, 1); } /* * Deallocate the memory used by the NetscapeSPKI object * * Arguments: self - The NetscapeSPKI object * Returns: None */ static void crypto_NetscapeSPKI_dealloc(crypto_NetscapeSPKIObj *self) { /* Sometimes we don't have to dealloc this */ if (self->dealloc) NETSCAPE_SPKI_free(self->netscape_spki); PyObject_Del(self); } static char crypto_NetscapeSPKI_sign_doc[] = "\n\ Sign the certificate request using the supplied key and digest\n\ \n\ @param pkey: The key to sign with\n\ @param digest: The message digest to use\n\ @return: None\n\ "; static PyObject * crypto_NetscapeSPKI_sign(crypto_NetscapeSPKIObj *self, PyObject *args) { crypto_PKeyObj *pkey; char *digest_name; const EVP_MD *digest; if (!PyArg_ParseTuple(args, "O!s:sign", &crypto_PKey_Type, &pkey, &digest_name)) return NULL; if (pkey->only_public) { PyErr_SetString(PyExc_ValueError, "Key has only public part"); return NULL; } if (!pkey->initialized) { PyErr_SetString(PyExc_ValueError, "Key is uninitialized"); return NULL; } if ((digest = EVP_get_digestbyname(digest_name)) == NULL) { PyErr_SetString(PyExc_ValueError, "No such digest method"); return NULL; } if (!NETSCAPE_SPKI_sign(self->netscape_spki, pkey->pkey, digest)) { exception_from_error_queue(crypto_Error); return NULL; } Py_INCREF(Py_None); return Py_None; } static char crypto_NetscapeSPKI_verify_doc[] = "\n\ Verifies a certificate request using the supplied public key\n\ \n\ @param key: a public key\n\ @return: True if the signature is correct.\n\ @raise OpenSSL.crypto.Error: If the signature is invalid or there is a\n\ problem verifying the signature.\n\ "; PyObject * crypto_NetscapeSPKI_verify(crypto_NetscapeSPKIObj *self, PyObject *args) { crypto_PKeyObj *pkey; int answer; if (!PyArg_ParseTuple(args, "O!:verify", &crypto_PKey_Type, &pkey)) { return NULL; } if ((answer = NETSCAPE_SPKI_verify(self->netscape_spki, pkey->pkey)) <= 0) { exception_from_error_queue(crypto_Error); return NULL; } return PyLong_FromLong((long)answer); } static char crypto_NetscapeSPKI_b64_encode_doc[] = "\n\ Generate a base64 encoded string from an SPKI\n\ \n\ @return: The base64 encoded string\n\ "; PyObject * crypto_NetscapeSPKI_b64_encode(crypto_NetscapeSPKIObj *self, PyObject *args) { char *str; if (!PyArg_ParseTuple(args, ":b64_encode")) return NULL; str = NETSCAPE_SPKI_b64_encode(self->netscape_spki); return PyBytes_FromString(str); } static char crypto_NetscapeSPKI_get_pubkey_doc[] = "\n\ Get the public key of the certificate\n\ \n\ @return: The public key\n\ "; static PyObject * crypto_NetscapeSPKI_get_pubkey(crypto_NetscapeSPKIObj *self, PyObject *args) { crypto_PKeyObj *crypto_PKey_New(EVP_PKEY *, int); EVP_PKEY *pkey; crypto_PKeyObj *py_pkey; if (!PyArg_ParseTuple(args, ":get_pubkey")) return NULL; if ((pkey = NETSCAPE_SPKI_get_pubkey(self->netscape_spki)) == NULL) { exception_from_error_queue(crypto_Error); return NULL; } py_pkey = crypto_PKey_New(pkey, 1); if (py_pkey != NULL) { py_pkey->only_public = 1; } return (PyObject *)py_pkey; } static char crypto_NetscapeSPKI_set_pubkey_doc[] = "\n\ Set the public key of the certificate\n\ \n\ @param pkey: The public key\n\ @return: None\n\ "; static PyObject * crypto_NetscapeSPKI_set_pubkey(crypto_NetscapeSPKIObj *self, PyObject *args) { crypto_PKeyObj *pkey; if (!PyArg_ParseTuple(args, "O!:set_pubkey", &crypto_PKey_Type, &pkey)) return NULL; if (!NETSCAPE_SPKI_set_pubkey(self->netscape_spki, pkey->pkey)) { exception_from_error_queue(crypto_Error); return NULL; } Py_INCREF(Py_None); return Py_None; } /* * ADD_METHOD(name) expands to a correct PyMethodDef declaration * { 'name', (PyCFunction)crypto_NetscapeSPKI_name, METH_VARARGS } * for convenience */ #define ADD_METHOD(name) \ { #name, (PyCFunction)crypto_NetscapeSPKI_##name, METH_VARARGS, crypto_NetscapeSPKI_##name##_doc } static PyMethodDef crypto_NetscapeSPKI_methods[] = { ADD_METHOD(get_pubkey), ADD_METHOD(set_pubkey), ADD_METHOD(b64_encode), ADD_METHOD(sign), ADD_METHOD(verify), { NULL, NULL } }; #undef ADD_METHOD PyTypeObject crypto_NetscapeSPKI_Type = { PyOpenSSL_HEAD_INIT(&PyType_Type, 0) "NetscapeSPKI", sizeof(crypto_NetscapeSPKIObj), 0, (destructor)crypto_NetscapeSPKI_dealloc, NULL, /* print */ NULL, /* getattr */ NULL, /* setattr */ NULL, /* compare */ NULL, /* repr */ NULL, /* as_number */ NULL, /* as_sequence */ NULL, /* as_mapping */ NULL, /* hash */ NULL, /* call */ NULL, /* str */ NULL, /* getattro */ NULL, /* setattro */ NULL, /* as_buffer */ Py_TPFLAGS_DEFAULT, crypto_NetscapeSPKI_doc, /* doc */ NULL, /* traverse */ NULL, /* clear */ NULL, /* tp_richcompare */ 0, /* tp_weaklistoffset */ NULL, /* tp_iter */ NULL, /* tp_iternext */ crypto_NetscapeSPKI_methods, /* tp_methods */ NULL, /* tp_members */ NULL, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ NULL, /* tp_descr_get */ NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ NULL, /* tp_init */ NULL, /* tp_alloc */ crypto_NetscapeSPKI_new, /* tp_new */ }; /* * Initialize the X509Name part of the crypto module * * Arguments: module - The crypto module * Returns: None */ int init_crypto_netscape_spki(PyObject *module) { if (PyType_Ready(&crypto_NetscapeSPKI_Type) < 0) { return 0; } /* PyModule_AddObject steals a reference */ Py_INCREF((PyObject *)&crypto_NetscapeSPKI_Type); if (PyModule_AddObject(module, "NetscapeSPKI", (PyObject *)&crypto_NetscapeSPKI_Type) != 0) { return 0; } /* PyModule_AddObject steals a reference */ Py_INCREF((PyObject *)&crypto_NetscapeSPKI_Type); if (PyModule_AddObject(module, "NetscapeSPKIType", (PyObject *)&crypto_NetscapeSPKI_Type) != 0) { return 0; } return 1; } pyOpenSSL-0.13/OpenSSL/crypto/netscape_spki.h0000644000214500021450000000120311630175105021036 0ustar bb-slavebb-slave/* * netscape_spki.h * * Copyright (C) Tollef Fog Heen * See LICENSE for details. * * Handle Netscape SPKI (challenge response) certificate requests. * * */ #ifndef PyOpenSSL_crypto_Netscape_SPKI_H_ #define PyOpenSSL_crypto_Netscape_SPKI_H_ #include #include extern int init_crypto_netscape_spki (PyObject *); extern PyTypeObject crypto_NetscapeSPKI_Type; #define crypto_NetscapeSPKI_Check(v) ((v)->ob_type == &crypto_NetscapeSPKI_Type) typedef struct { PyObject_HEAD NETSCAPE_SPKI *netscape_spki; int dealloc; } crypto_NetscapeSPKIObj; #endif pyOpenSSL-0.13/OpenSSL/crypto/pkcs12.c0000644000214500021450000004070211630175105017313 0ustar bb-slavebb-slave/* * pkcs12.c * * Copyright (C) AB Strakt * See LICENSE for details. * * Certificate transport (PKCS12) handling code, * mostly thin wrappers around OpenSSL. * See the file RATIONALE for a short explanation of why * this module was written. * * Reviewed 2001-07-23 */ #include #define crypto_MODULE #include "crypto.h" /* * PKCS12 is a standard exchange format for digital certificates. * See e.g. the OpenSSL homepage http://www.openssl.org/ for more information */ static void crypto_PKCS12_dealloc(crypto_PKCS12Obj *self); static int crypto_PKCS12_clear(crypto_PKCS12Obj *self); static char crypto_PKCS12_get_certificate_doc[] = "\n\ Return certificate portion of the PKCS12 structure\n\ \n\ @return: X509 object containing the certificate\n\ "; static PyObject * crypto_PKCS12_get_certificate(crypto_PKCS12Obj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":get_certificate")) return NULL; Py_INCREF(self->cert); return self->cert; } static char crypto_PKCS12_set_certificate_doc[] = "\n\ Replace the certificate portion of the PKCS12 structure\n\ \n\ @param cert: The new certificate.\n\ @type cert: L{X509} or L{NoneType}\n\ @return: None\n\ "; static PyObject * crypto_PKCS12_set_certificate(crypto_PKCS12Obj *self, PyObject *args, PyObject *keywds) { PyObject *cert = NULL; static char *kwlist[] = {"cert", NULL}; if (!PyArg_ParseTupleAndKeywords(args, keywds, "O:set_certificate", kwlist, &cert)) return NULL; if (cert != Py_None && ! crypto_X509_Check(cert)) { PyErr_SetString(PyExc_TypeError, "cert must be type X509 or None"); return NULL; } Py_INCREF(cert); /* Make consistent before calling Py_DECREF() */ Py_DECREF(self->cert); self->cert = cert; Py_INCREF(Py_None); return Py_None; } static char crypto_PKCS12_get_privatekey_doc[] = "\n\ Return private key portion of the PKCS12 structure\n\ \n\ @returns: PKey object containing the private key\n\ "; static crypto_PKeyObj * crypto_PKCS12_get_privatekey(crypto_PKCS12Obj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":get_privatekey")) return NULL; Py_INCREF(self->key); return (crypto_PKeyObj *) self->key; } static char crypto_PKCS12_set_privatekey_doc[] = "\n\ Replace or set the certificate portion of the PKCS12 structure\n\ \n\ @param pkey: The new private key.\n\ @type pkey: L{PKey}\n\ @return: None\n\ "; static PyObject * crypto_PKCS12_set_privatekey(crypto_PKCS12Obj *self, PyObject *args, PyObject *keywds) { PyObject *pkey = NULL; static char *kwlist[] = {"pkey", NULL}; if (!PyArg_ParseTupleAndKeywords(args, keywds, "O:set_privatekey", kwlist, &pkey)) return NULL; if (pkey != Py_None && ! crypto_PKey_Check(pkey)) { PyErr_SetString(PyExc_TypeError, "pkey must be type X509 or None"); return NULL; } Py_INCREF(pkey); /* Make consistent before calling Py_DECREF() */ Py_DECREF(self->key); self->key = pkey; Py_INCREF(Py_None); return Py_None; } static char crypto_PKCS12_get_ca_certificates_doc[] = "\n\ Return CA certificates within of the PKCS12 object\n\ \n\ @return: A newly created tuple containing the CA certificates in the chain,\n\ if any are present, or None if no CA certificates are present.\n\ "; static PyObject * crypto_PKCS12_get_ca_certificates(crypto_PKCS12Obj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":get_ca_certificates")) return NULL; Py_INCREF(self->cacerts); return self->cacerts; } static char crypto_PKCS12_set_ca_certificates_doc[] = "\n\ Replace or set the CA certificates withing the PKCS12 object.\n\ \n\ @param cacerts: The new CA certificates.\n\ @type cacerts: Iterable of L{X509} or L{NoneType}\n\ @return: None\n\ "; static PyObject * crypto_PKCS12_set_ca_certificates(crypto_PKCS12Obj *self, PyObject *args, PyObject *keywds) { PyObject *obj; PyObject *cacerts; static char *kwlist[] = {"cacerts", NULL}; int i, len; /* Py_ssize_t for Python 2.5+ */ if (!PyArg_ParseTupleAndKeywords(args, keywds, "O:set_ca_certificates", kwlist, &cacerts)) return NULL; if (cacerts == Py_None) { Py_INCREF(cacerts); } else { /* It's iterable */ cacerts = PySequence_Tuple(cacerts); if (cacerts == NULL) { return NULL; } len = PyTuple_Size(cacerts); /* Check is's a simple list filled only with X509 objects. */ for (i = 0; i < len; i++) { obj = PyTuple_GetItem(cacerts, i); if (!crypto_X509_Check(obj)) { Py_DECREF(cacerts); PyErr_SetString(PyExc_TypeError, "iterable must only contain X509Type"); return NULL; } } } Py_DECREF(self->cacerts); self->cacerts = cacerts; Py_INCREF(Py_None); return Py_None; } static char crypto_PKCS12_get_friendlyname_doc[] = "\n\ Return friendly name portion of the PKCS12 structure\n\ \n\ @returns: String containing the friendlyname\n\ "; static PyObject * crypto_PKCS12_get_friendlyname(crypto_PKCS12Obj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":get_friendlyname")) return NULL; Py_INCREF(self->friendlyname); return (PyObject *) self->friendlyname; } static char crypto_PKCS12_set_friendlyname_doc[] = "\n\ Replace or set the certificate portion of the PKCS12 structure\n\ \n\ @param name: The new friendly name.\n\ @type name: L{str}\n\ @return: None\n\ "; static PyObject * crypto_PKCS12_set_friendlyname(crypto_PKCS12Obj *self, PyObject *args, PyObject *keywds) { PyObject *name = NULL; static char *kwlist[] = {"name", NULL}; if (!PyArg_ParseTupleAndKeywords(args, keywds, "O:set_friendlyname", kwlist, &name)) return NULL; if (name != Py_None && ! PyBytes_CheckExact(name)) { PyErr_SetString(PyExc_TypeError, "name must be a byte string or None"); return NULL; } Py_INCREF(name); /* Make consistent before calling Py_DECREF() */ Py_DECREF(self->friendlyname); self->friendlyname = name; Py_INCREF(Py_None); return Py_None; } static char crypto_PKCS12_export_doc[] = "\n\ export([passphrase=None][, friendly_name=None][, iter=2048][, maciter=1]\n\ Dump a PKCS12 object as a string. See also \"man PKCS12_create\".\n\ \n\ @param passphrase: used to encrypt the PKCS12\n\ @type passphrase: L{str}\n\ @param iter: How many times to repeat the encryption\n\ @type iter: L{int}\n\ @param maciter: How many times to repeat the MAC\n\ @type maciter: L{int}\n\ @return: The string containing the PKCS12\n\ "; static PyObject * crypto_PKCS12_export(crypto_PKCS12Obj *self, PyObject *args, PyObject *keywds) { int i; /* Py_ssize_t for Python 2.5+ */ PyObject *obj; int buf_len; PyObject *buffer; char *temp, *passphrase = NULL, *friendly_name = NULL; BIO *bio; PKCS12 *p12; EVP_PKEY *pkey = NULL; STACK_OF(X509) *cacerts = NULL; X509 *x509 = NULL; int iter = 0; /* defaults to PKCS12_DEFAULT_ITER */ int maciter = 0; static char *kwlist[] = {"passphrase", "iter", "maciter", NULL}; if (!PyArg_ParseTupleAndKeywords(args, keywds, "|zii:export", kwlist, &passphrase, &iter, &maciter)) return NULL; if (self->key != Py_None) { pkey = ((crypto_PKeyObj*) self->key)->pkey; } if (self->cert != Py_None) { x509 = ((crypto_X509Obj*) self->cert)->x509; } if (self->cacerts != Py_None) { cacerts = sk_X509_new_null(); for (i = 0; i < PyTuple_Size(self->cacerts); i++) { /* For each CA cert */ obj = PySequence_GetItem(self->cacerts, i); /* assert(PyObject_IsInstance(obj, (PyObject *) &crypto_X509_Type )); */ sk_X509_push(cacerts, (( crypto_X509Obj* ) obj)->x509); Py_DECREF(obj); } } if (self->friendlyname != Py_None) { friendly_name = PyBytes_AsString(self->friendlyname); } p12 = PKCS12_create(passphrase, friendly_name, pkey, x509, cacerts, NID_pbe_WithSHA1And3_Key_TripleDES_CBC, NID_pbe_WithSHA1And3_Key_TripleDES_CBC, iter, maciter, 0); sk_X509_free(cacerts); /* NULL safe. Free just the container. */ if (p12 == NULL) { exception_from_error_queue(crypto_Error); return NULL; } bio = BIO_new(BIO_s_mem()); i2d_PKCS12_bio(bio, p12); buf_len = BIO_get_mem_data(bio, &temp); buffer = PyBytes_FromStringAndSize(temp, buf_len); BIO_free(bio); return buffer; } /* * ADD_METHOD(name) expands to a correct PyMethodDef declaration * { 'name', (PyCFunction)crypto_PKCS12_name, METH_VARARGS, crypto_PKCS12_name_doc } * for convenience */ #define ADD_METHOD(name) \ { #name, (PyCFunction)crypto_PKCS12_##name, METH_VARARGS, crypto_PKCS12_##name##_doc } #define ADD_KW_METHOD(name) \ { #name, (PyCFunction)crypto_PKCS12_##name, METH_VARARGS | METH_KEYWORDS, crypto_PKCS12_##name##_doc } static PyMethodDef crypto_PKCS12_methods[] = { ADD_METHOD(get_certificate), ADD_KW_METHOD(set_certificate), ADD_METHOD(get_privatekey), ADD_KW_METHOD(set_privatekey), ADD_METHOD(get_ca_certificates), ADD_KW_METHOD(set_ca_certificates), ADD_METHOD(get_friendlyname), ADD_KW_METHOD(set_friendlyname), ADD_KW_METHOD(export), { NULL, NULL } }; #undef ADD_METHOD /* * Constructor for PKCS12 objects, never called by Python code directly. * The strategy for this object is to create all the Python objects * corresponding to the cert/key/CA certs right away * * Arguments: p12 - A "real" PKCS12 object or NULL * passphrase - Passphrase to use when decrypting the PKCS12 object * Returns: The newly created PKCS12 object */ crypto_PKCS12Obj * crypto_PKCS12_New(PKCS12 *p12, char *passphrase) { crypto_PKCS12Obj *self = NULL; PyObject *cacertobj = NULL; unsigned char *alias_str; int alias_len; X509 *cert = NULL; EVP_PKEY *pkey = NULL; STACK_OF(X509) *cacerts = NULL; int i, cacert_count = 0; /* allocate space for the CA cert stack */ if((cacerts = sk_X509_new_null()) == NULL) { goto error; /* out of memory? */ } /* parse the PKCS12 lump */ if (p12) { if (!PKCS12_parse(p12, passphrase, &pkey, &cert, &cacerts)) { /* * If PKCS12_parse fails, and it allocated cacerts, it seems to * free cacerts, but not re-NULL the pointer. Zounds! Make sure * it is re-set to NULL here, else we'll have a double-free below. */ cacerts = NULL; exception_from_error_queue(crypto_Error); goto error; } else { /* * OpenSSL 1.0.0 sometimes leaves an X509_check_private_key error in * the queue for no particular reason. This error isn't interesting * to anyone outside this function. It's not even interesting to * us. Get rid of it. */ flush_error_queue(); } } if (!(self = PyObject_GC_New(crypto_PKCS12Obj, &crypto_PKCS12_Type))) { goto error; } /* client certificate and friendlyName */ if (cert == NULL) { Py_INCREF(Py_None); self->cert = Py_None; Py_INCREF(Py_None); self->friendlyname = Py_None; } else { if ((self->cert = (PyObject *)crypto_X509_New(cert, 1)) == NULL) { goto error; } /* Now we need to extract the friendlyName of the PKCS12 * that was stored by PKCS_parse() in the alias of the * certificate. */ alias_str = X509_alias_get0(cert, &alias_len); if (alias_str) { self->friendlyname = Py_BuildValue(BYTESTRING_FMT "#", alias_str, alias_len); if (!self->friendlyname) { /* * XXX Untested */ goto error; } /* success */ } else { Py_INCREF(Py_None); self->friendlyname = Py_None; } } /* private key */ if (pkey == NULL) { Py_INCREF(Py_None); self->key = Py_None; } else { if ((self->key = (PyObject *)crypto_PKey_New(pkey, 1)) == NULL) goto error; } /* CA certs */ cacert_count = sk_X509_num(cacerts); if (cacert_count <= 0) { Py_INCREF(Py_None); self->cacerts = Py_None; } else { if ((self->cacerts = PyTuple_New(cacert_count)) == NULL) { goto error; } for (i = 0; i < cacert_count; i++) { cert = sk_X509_value(cacerts, i); if ((cacertobj = (PyObject *)crypto_X509_New(cert, 1)) == NULL) { goto error; } PyTuple_SET_ITEM(self->cacerts, i, cacertobj); } } sk_X509_free(cacerts); /* Don't free the certs, just the container. */ PyObject_GC_Track(self); return self; error: sk_X509_free(cacerts); /* NULL safe. Free just the container. */ if (self) { crypto_PKCS12_clear(self); PyObject_GC_Del(self); } return NULL; } static char crypto_PKCS12_doc[] = "\n\ PKCS12() -> PKCS12 instance\n\ \n\ Create a new empty PKCS12 object.\n\ \n\ @returns: The PKCS12 object\n\ "; static PyObject * crypto_PKCS12_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) { if (!PyArg_ParseTuple(args, ":PKCS12")) { return NULL; } return (PyObject *)crypto_PKCS12_New(NULL, NULL); } /* * Call the visitproc on all contained objects. * * Arguments: self - The PKCS12 object * visit - Function to call * arg - Extra argument to visit * Returns: 0 if all goes well, otherwise the return code from the first * call that gave non-zero result. */ static int crypto_PKCS12_traverse(crypto_PKCS12Obj *self, visitproc visit, void *arg) { int ret = 0; if (ret == 0 && self->cert != NULL) ret = visit(self->cert, arg); if (ret == 0 && self->key != NULL) ret = visit(self->key, arg); if (ret == 0 && self->cacerts != NULL) ret = visit(self->cacerts, arg); if (ret == 0 && self->friendlyname != NULL) ret = visit(self->friendlyname, arg); return ret; } /* * Decref all contained objects and zero the pointers. * * Arguments: self - The PKCS12 object * Returns: Always 0. */ static int crypto_PKCS12_clear(crypto_PKCS12Obj *self) { Py_XDECREF(self->cert); self->cert = NULL; Py_XDECREF(self->key); self->key = NULL; Py_XDECREF(self->cacerts); self->cacerts = NULL; Py_XDECREF(self->friendlyname); self->friendlyname = NULL; return 0; } /* * Deallocate the memory used by the PKCS12 object * * Arguments: self - The PKCS12 object * Returns: None */ static void crypto_PKCS12_dealloc(crypto_PKCS12Obj *self) { PyObject_GC_UnTrack(self); crypto_PKCS12_clear(self); PyObject_GC_Del(self); } PyTypeObject crypto_PKCS12_Type = { PyOpenSSL_HEAD_INIT(&PyType_Type, 0) "PKCS12", sizeof(crypto_PKCS12Obj), 0, (destructor)crypto_PKCS12_dealloc, NULL, /* print */ NULL, /* getattr */ NULL, /* setattr */ NULL, /* compare */ NULL, /* repr */ NULL, /* as_number */ NULL, /* as_sequence */ NULL, /* as_mapping */ NULL, /* hash */ NULL, /* call */ NULL, /* str */ NULL, /* getattro */ NULL, /* setattro */ NULL, /* as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, crypto_PKCS12_doc, (traverseproc)crypto_PKCS12_traverse, (inquiry)crypto_PKCS12_clear, NULL, /* tp_richcompare */ 0, /* tp_weaklistoffset */ NULL, /* tp_iter */ NULL, /* tp_iternext */ crypto_PKCS12_methods, /* tp_methods */ NULL, /* tp_members */ NULL, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ NULL, /* tp_descr_get */ NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ NULL, /* tp_init */ NULL, /* tp_alloc */ crypto_PKCS12_new, /* tp_new */ }; /* * Initialize the PKCS12 part of the crypto sub module * * Arguments: module - The crypto module * Returns: None */ int init_crypto_pkcs12(PyObject *module) { if (PyType_Ready(&crypto_PKCS12_Type) < 0) { return 0; } /* PyModule_AddObject steals a reference. */ Py_INCREF((PyObject *)&crypto_PKCS12_Type); if (PyModule_AddObject(module, "PKCS12", (PyObject *)&crypto_PKCS12_Type) != 0) { return 0; } /* PyModule_AddObject steals a reference. */ Py_INCREF((PyObject *)&crypto_PKCS12_Type); if (PyModule_AddObject(module, "PKCS12Type", (PyObject *)&crypto_PKCS12_Type) != 0) { return 0; } return 1; } pyOpenSSL-0.13/OpenSSL/crypto/pkcs12.h0000644000214500021450000000160511630175105017317 0ustar bb-slavebb-slave/* * pkcs12.h * * Copyright (C) AB Strakt * See LICENSE for details. * * Export PKCS12 functions and data structure. * */ #ifndef PyOpenSSL_crypto_PKCS12_H_ #define PyOpenSSL_crypto_PKCS12_H_ #include #include #include extern int init_crypto_pkcs12 (PyObject *); extern PyTypeObject crypto_PKCS12_Type; #define crypto_PKCS12_Check(v) ((v)->ob_type == &crypto_PKCS12_Type) typedef struct { PyObject_HEAD /* * These either refer to a PyObject* of the appropriate type, or Py_None if * they don't have a value. They aren't set to NULL except during * finalization. */ PyObject *cert; PyObject *key; PyObject *cacerts; PyObject *friendlyname; } crypto_PKCS12Obj; crypto_PKCS12Obj * crypto_PKCS12_New(PKCS12 *p12, char *passphrase); #endif pyOpenSSL-0.13/OpenSSL/crypto/pkcs7.c0000644000214500021450000001220511630175105017234 0ustar bb-slavebb-slave/* * pkcs7.c * * Copyright (C) AB Strakt * See LICENSE for details. * * PKCS7 handling code, mostly thin wrappers around OpenSSL. * See the file RATIONALE for a short explanation of why this module was written. * */ #include #define crypto_MODULE #include "crypto.h" static char crypto_PKCS7_type_is_signed_doc[] = "\n\ Check if this NID_pkcs7_signed object\n\ \n\ @return: True if the PKCS7 is of type signed\n\ "; static PyObject * crypto_PKCS7_type_is_signed(crypto_PKCS7Obj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":type_is_signed")) return NULL; if (PKCS7_type_is_signed(self->pkcs7)) return PyLong_FromLong(1L); else return PyLong_FromLong(0L); } static char crypto_PKCS7_type_is_enveloped_doc[] = "\n\ Check if this NID_pkcs7_enveloped object\n\ \n\ @returns: True if the PKCS7 is of type enveloped\n\ "; static PyObject * crypto_PKCS7_type_is_enveloped(crypto_PKCS7Obj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":type_is_enveloped")) return NULL; if (PKCS7_type_is_enveloped(self->pkcs7)) return PyLong_FromLong(1L); else return PyLong_FromLong(0L); } static char crypto_PKCS7_type_is_signedAndEnveloped_doc[] = "\n\ Check if this NID_pkcs7_signedAndEnveloped object\n\ \n\ @returns: True if the PKCS7 is of type signedAndEnveloped\n\ "; static PyObject * crypto_PKCS7_type_is_signedAndEnveloped(crypto_PKCS7Obj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":type_is_signedAndEnveloped")) return NULL; if (PKCS7_type_is_signedAndEnveloped(self->pkcs7)) return PyLong_FromLong(1L); else return PyLong_FromLong(0L); } static char crypto_PKCS7_type_is_data_doc[] = "\n\ Check if this NID_pkcs7_data object\n\ \n\ @return: True if the PKCS7 is of type data\n\ "; static PyObject * crypto_PKCS7_type_is_data(crypto_PKCS7Obj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":type_is_data")) return NULL; if (PKCS7_type_is_data(self->pkcs7)) return PyLong_FromLong(1L); else return PyLong_FromLong(0L); } static char crypto_PKCS7_get_type_name_doc[] = "\n\ Returns the type name of the PKCS7 structure\n\ \n\ @return: A string with the typename\n\ "; static PyObject * crypto_PKCS7_get_type_name(crypto_PKCS7Obj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":get_type_name")) return NULL; /* * return a string with the typename */ return PyBytes_FromString(OBJ_nid2sn(OBJ_obj2nid(self->pkcs7->type))); } /* * ADD_METHOD(name) expands to a correct PyMethodDef declaration * { 'name', (PyCFunction)crypto_PKCS7_name, METH_VARARGS } * for convenience */ #define ADD_METHOD(name) \ { #name, (PyCFunction)crypto_PKCS7_##name, METH_VARARGS, crypto_PKCS7_##name##_doc } static PyMethodDef crypto_PKCS7_methods[] = { ADD_METHOD(type_is_signed), ADD_METHOD(type_is_enveloped), ADD_METHOD(type_is_signedAndEnveloped), ADD_METHOD(type_is_data), ADD_METHOD(get_type_name), { NULL, NULL } }; #undef ADD_METHOD /* * Constructor for PKCS7 objects, never called by Python code directly * * Arguments: pkcs7 - A "real" pkcs7 certificate object * dealloc - Boolean value to specify whether the destructor should * free the "real" pkcs7 object * Returns: The newly created pkcs7 object */ crypto_PKCS7Obj * crypto_PKCS7_New(PKCS7 *pkcs7, int dealloc) { crypto_PKCS7Obj *self; self = PyObject_New(crypto_PKCS7Obj, &crypto_PKCS7_Type); if (self == NULL) return NULL; self->pkcs7 = pkcs7; self->dealloc = dealloc; return self; } /* * Deallocate the memory used by the PKCS7 object * * Arguments: self - The PKCS7 object * Returns: None */ static void crypto_PKCS7_dealloc(crypto_PKCS7Obj *self) { /* Sometimes we don't have to dealloc the "real" PKCS7 pointer ourselves */ if (self->dealloc) PKCS7_free(self->pkcs7); PyObject_Del(self); } PyTypeObject crypto_PKCS7_Type = { PyOpenSSL_HEAD_INIT(&PyType_Type, 0) "PKCS7", sizeof(crypto_PKCS7Obj), 0, (destructor)crypto_PKCS7_dealloc, NULL, /* print */ NULL, /* getattr */ NULL, /* setattr */ NULL, /* compare */ NULL, /* repr */ NULL, /* as_number */ NULL, /* as_sequence */ NULL, /* as_mapping */ NULL, /* hash */ NULL, /* call */ NULL, /* str */ NULL, /* getattro */ NULL, /* setattro */ NULL, /* as_buffer */ Py_TPFLAGS_DEFAULT, NULL, /* doc */ NULL, /* traverse */ NULL, /* clear */ NULL, /* tp_richcompare */ 0, /* tp_weaklistoffset */ NULL, /* tp_iter */ NULL, /* tp_iternext */ crypto_PKCS7_methods, /* tp_methods */ }; /* * Initialize the PKCS7 part of the crypto sub module * * Arguments: module - The crypto module * Returns: None */ int init_crypto_pkcs7(PyObject *module) { if (PyType_Ready(&crypto_PKCS7_Type) < 0) { return 0; } /* PyModule_AddObject steals a reference. */ Py_INCREF((PyObject *)&crypto_PKCS7_Type); if (PyModule_AddObject(module, "PKCS7Type", (PyObject *)&crypto_PKCS7_Type) != 0) { return 0; } return 1; } pyOpenSSL-0.13/OpenSSL/crypto/pkcs7.h0000644000214500021450000000116011630175105017237 0ustar bb-slavebb-slave/* * pkcs7.h * * Copyright (C) AB Strakt * See LICENSE for details. * * Export pkcs7 functions and data structure. * See the file RATIONALE for a short explanation of why this module was written. * */ #ifndef PyOpenSSL_crypto_PKCS7_H_ #define PyOpenSSL_crypto_PKCS7_H_ #include #include extern int init_crypto_pkcs7 (PyObject *); extern PyTypeObject crypto_PKCS7_Type; #define crypto_PKCS7_Check(v) ((v)->ob_type == &crypto_PKCS7_Type) typedef struct { PyObject_HEAD PKCS7 *pkcs7; int dealloc; } crypto_PKCS7Obj; #endif pyOpenSSL-0.13/OpenSSL/crypto/pkey.c0000644000214500021450000001604711630175105017165 0ustar bb-slavebb-slave/* * pkey.c * * Copyright (C) AB Strakt * Copyright (C) Jean-Paul Calderone * See LICENSE for details. * * Public/rivate key handling code, mostly thin wrappers around OpenSSL. * See the file RATIONALE for a short explanation of why this module was written. * */ #include #define crypto_MODULE #include "crypto.h" /* * This is done every time something fails, so turning it into a macro is * really nice. * * Arguments: None * Returns: Doesn't return */ #define FAIL() \ do { \ exception_from_error_queue(crypto_Error); \ return NULL; \ } while (0) static char crypto_PKey_generate_key_doc[] = "\n\ Generate a key of a given type, with a given number of a bits\n\ \n\ @param type: The key type (TYPE_RSA or TYPE_DSA)\n\ @param bits: The number of bits\n\ @return: None\n\ "; static PyObject * crypto_PKey_generate_key(crypto_PKeyObj *self, PyObject *args) { int type, bits; RSA *rsa; DSA *dsa; if (!PyArg_ParseTuple(args, "ii:generate_key", &type, &bits)) return NULL; switch (type) { case crypto_TYPE_RSA: if (bits <= 0) { PyErr_SetString(PyExc_ValueError, "Invalid number of bits"); return NULL; } if ((rsa = RSA_generate_key(bits, 0x10001, NULL, NULL)) == NULL) FAIL(); if (!EVP_PKEY_assign_RSA(self->pkey, rsa)) FAIL(); break; case crypto_TYPE_DSA: if ((dsa = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL)) == NULL) FAIL(); if (!DSA_generate_key(dsa)) FAIL(); if (!EVP_PKEY_assign_DSA(self->pkey, dsa)) FAIL(); break; default: PyErr_SetString(crypto_Error, "No such key type"); return NULL; } self->initialized = 1; Py_INCREF(Py_None); return Py_None; } static char crypto_PKey_bits_doc[] = "\n\ Returns the number of bits of the key\n\ \n\ @return: The number of bits of the key.\n\ "; static PyObject * crypto_PKey_bits(crypto_PKeyObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":bits")) return NULL; return PyLong_FromLong(EVP_PKEY_bits(self->pkey)); } static char crypto_PKey_type_doc[] = "\n\ Returns the type of the key\n\ \n\ @return: The type of the key.\n\ "; static PyObject * crypto_PKey_type(crypto_PKeyObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":type")) return NULL; return PyLong_FromLong(self->pkey->type); } static char crypto_PKey_check_doc[] = "\n\ Check the consistency of an RSA private key.\n\ \n\ @return: True if key is consistent.\n\ @raise Error: if the key is inconsistent.\n\ @raise TypeError: if the key is of a type which cannot be checked.\n\ Only RSA keys can currently be checked.\n\ "; static PyObject * crypto_PKey_check(crypto_PKeyObj *self, PyObject *args) { int r; if (!PyArg_ParseTuple(args, ":check")) { return NULL; } if (self->pkey->type == EVP_PKEY_RSA) { RSA *rsa; rsa = EVP_PKEY_get1_RSA(self->pkey); r = RSA_check_key(rsa); if (r == 1) { return PyBool_FromLong(1L); } else { FAIL(); } } else { PyErr_SetString(PyExc_TypeError, "key type unsupported"); return NULL; } } /* * ADD_METHOD(name) expands to a correct PyMethodDef declaration * { 'name', (PyCFunction)crypto_PKey_name, METH_VARARGS } * for convenience */ #define ADD_METHOD(name) \ { #name, (PyCFunction)crypto_PKey_##name, METH_VARARGS, crypto_PKey_##name##_doc } static PyMethodDef crypto_PKey_methods[] = { ADD_METHOD(generate_key), ADD_METHOD(bits), ADD_METHOD(type), ADD_METHOD(check), { NULL, NULL } }; #undef ADD_METHOD /* * Constructor for PKey objects, never called by Python code directly * * Arguments: pkey - A "real" EVP_PKEY object * dealloc - Boolean value to specify whether the destructor should * free the "real" EVP_PKEY object * Returns: The newly created PKey object */ crypto_PKeyObj * crypto_PKey_New(EVP_PKEY *pkey, int dealloc) { crypto_PKeyObj *self; self = PyObject_New(crypto_PKeyObj, &crypto_PKey_Type); if (self == NULL) return NULL; self->pkey = pkey; self->dealloc = dealloc; self->only_public = 0; /* * Heuristic. Most call-sites pass an initialized EVP_PKEY. Not * necessarily the case that they will, though. That's part of why this is * a hack. -exarkun */ self->initialized = 1; return self; } static char crypto_PKey_doc[] = "\n\ PKey() -> PKey instance\n\ \n\ Create a new PKey object.\n\ \n\ @return: The PKey object\n\ "; static PyObject* crypto_PKey_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) { crypto_PKeyObj *self; if (!PyArg_ParseTuple(args, ":PKey")) { return NULL; } self = crypto_PKey_New(EVP_PKEY_new(), 1); if (self) { self->initialized = 0; } return (PyObject *)self; } /* * Deallocate the memory used by the PKey object * * Arguments: self - The PKey object * Returns: None */ static void crypto_PKey_dealloc(crypto_PKeyObj *self) { /* Sometimes we don't have to dealloc the "real" EVP_PKEY pointer ourselves */ if (self->dealloc) EVP_PKEY_free(self->pkey); PyObject_Del(self); } PyTypeObject crypto_PKey_Type = { PyOpenSSL_HEAD_INIT(&PyType_Type, 0) "OpenSSL.crypto.PKey", sizeof(crypto_PKeyObj), 0, (destructor)crypto_PKey_dealloc, NULL, /* print */ NULL, /* getattr */ NULL, /* setattr */ NULL, /* compare */ NULL, /* repr */ NULL, /* as_number */ NULL, /* as_sequence */ NULL, /* as_mapping */ NULL, /* hash */ NULL, /* call */ NULL, /* str */ NULL, /* getattro */ NULL, /* setattro */ NULL, /* as_buffer */ Py_TPFLAGS_DEFAULT, crypto_PKey_doc, /* doc */ NULL, /* traverse */ NULL, /* clear */ NULL, /* tp_richcompare */ 0, /* tp_weaklistoffset */ NULL, /* tp_iter */ NULL, /* tp_iternext */ crypto_PKey_methods, /* tp_methods */ NULL, /* tp_members */ NULL, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ NULL, /* tp_descr_get */ NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ NULL, /* tp_init */ NULL, /* tp_alloc */ crypto_PKey_new, /* tp_new */ }; /* * Initialize the PKey part of the crypto sub module * * Arguments: module - The crypto module * Returns: None */ int init_crypto_pkey(PyObject *module) { if (PyType_Ready(&crypto_PKey_Type) < 0) { return 0; } /* PyModule_AddObject steals a reference. */ Py_INCREF((PyObject *)&crypto_PKey_Type); if (PyModule_AddObject(module, "PKey", (PyObject *)&crypto_PKey_Type) != 0) { return 0; } /* PyModule_AddObject steals a reference. */ Py_INCREF((PyObject *)&crypto_PKey_Type); if (PyModule_AddObject(module, "PKeyType", (PyObject *)&crypto_PKey_Type) != 0) { return 0; } return 1; } pyOpenSSL-0.13/OpenSSL/crypto/pkey.h0000644000214500021450000000257111630175105017167 0ustar bb-slavebb-slave/* * pkey.h * * Copyright (C) AB Strakt * Copyright (C) Jean-Paul Calderone * See LICENSE for details. * * Export pkey functions and data structure. * See the file RATIONALE for a short explanation of why this module was written. * */ #ifndef PyOpenSSL_crypto_PKEY_H_ #define PyOpenSSL_crypto_PKEY_H_ extern int init_crypto_pkey (PyObject *); extern PyTypeObject crypto_PKey_Type; #define crypto_PKey_Check(v) ((v)->ob_type == &crypto_PKey_Type) typedef struct { PyObject_HEAD /* * A pointer to the underlying OpenSSL structure. */ EVP_PKEY *pkey; /* * A flag indicating the underlying pkey object has no private parts (so it * can't sign, for example). This is a bit of a temporary hack. * Public-only should be represented as a different type. -exarkun */ int only_public; /* * A flag indicating whether the underlying pkey object has no meaningful * data in it whatsoever. This is a temporary hack. It should be * impossible to create PKeys in an unusable state. -exarkun */ int initialized; /* * A flag indicating whether pkey will be freed when this object is freed. */ int dealloc; } crypto_PKeyObj; #define crypto_TYPE_RSA EVP_PKEY_RSA #define crypto_TYPE_DSA EVP_PKEY_DSA #endif pyOpenSSL-0.13/OpenSSL/crypto/revoked.c0000644000214500021450000002570111630175105017651 0ustar bb-slavebb-slave#include #define crypto_MODULE #include "crypto.h" #ifdef _WIN32 #define strcasecmp(string1, string2) _stricmp(string1, string2) #endif /* http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_ */ /* which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches */ /* OCSP_crl_reason_str. We use the latter, just like the command line program. */ static const char *crl_reasons[] = { "unspecified", "keyCompromise", "CACompromise", "affiliationChanged", "superseded", "cessationOfOperation", "certificateHold", NULL, "removeFromCRL", }; #define NUM_REASONS (sizeof(crl_reasons) / sizeof(char *)) static char crypto_Revoked_all_reasons_doc[] = "\n\ Return a list of all the supported reason strings.\n\ \n\ @return: A list of reason strings.\n\ "; static PyObject * crypto_Revoked_all_reasons(crypto_RevokedObj *self, PyObject *args) { PyObject *list, *str; int j; list = PyList_New(0); for (j = 0; j < NUM_REASONS; j++) { if(crl_reasons[j]) { str = PyBytes_FromString(crl_reasons[j]); PyList_Append(list, str); Py_DECREF(str); } } return list; } static PyObject * X509_EXTENSION_value_to_PyString(X509_EXTENSION *ex) { BIO *bio = NULL; PyObject *str = NULL; int str_len; char *tmp_str; /* Create a openssl BIO buffer */ bio = BIO_new(BIO_s_mem()); if (bio == NULL) { goto err; } /* These are not the droids you are looking for. */ if (!X509V3_EXT_print(bio, ex, 0, 0)) { if (M_ASN1_OCTET_STRING_print(bio, ex->value) == 0) { goto err; } } /* Convert to a Python string. */ str_len = BIO_get_mem_data(bio, &tmp_str); str = PyBytes_FromStringAndSize(tmp_str, str_len); /* Cleanup */ BIO_free(bio); return str; err: if (bio) { BIO_free(bio); } if (str) { Py_DECREF(str); } return NULL; } static void delete_reason(STACK_OF(X509_EXTENSION) *sk) { X509_EXTENSION * ext; int j; for (j = 0; j < sk_X509_EXTENSION_num(sk); j++) { ext = sk_X509_EXTENSION_value(sk, j); if (OBJ_obj2nid(ext->object) == NID_crl_reason) { X509_EXTENSION_free(ext); (void) sk_X509_EXTENSION_delete(sk, j); break; } } } static int reason_str_to_code(const char * reason_str) { int reason_code = -1, j; char *spaceless_reason, * sp; /* Remove spaces so that the responses of * get_reason() work in set_reason() */ if ((spaceless_reason = strdup(reason_str)) == NULL) { return -1; } while ((sp = strchr(spaceless_reason, ' '))) { memmove(sp, sp+1, strlen(sp)); } for (j = 0; j < NUM_REASONS; j++) { if(crl_reasons[j] && !strcasecmp(spaceless_reason, crl_reasons[j])) { reason_code = j; break; } } free(spaceless_reason); return reason_code; } static char crypto_Revoked_set_reason_doc[] = "\n\ Set the reason of a Revoked object.\n\ \n\ @param reason: The reason string.\n\ @type reason: L{str}\n\ @return: None\n\ "; static PyObject * crypto_Revoked_set_reason(crypto_RevokedObj *self, PyObject *args, PyObject *keywds) { static char *kwlist[] = {"reason", NULL}; const char *reason_str = NULL; int reason_code; ASN1_ENUMERATED *rtmp = NULL; if (!PyArg_ParseTupleAndKeywords( args, keywds, "O&:set_reason", kwlist, crypto_byte_converter, &reason_str)) { return NULL; } if(reason_str == NULL) { delete_reason(self->revoked->extensions); goto done; } reason_code = reason_str_to_code(reason_str); if (reason_code == -1) { PyErr_SetString(PyExc_ValueError, "bad reason string"); return NULL; } rtmp = ASN1_ENUMERATED_new(); if (!rtmp || !ASN1_ENUMERATED_set(rtmp, reason_code)) { goto err; } delete_reason(self->revoked->extensions); if (!X509_REVOKED_add1_ext_i2d(self->revoked, NID_crl_reason, rtmp, 0, 0)) { goto err; } done: Py_INCREF(Py_None); return Py_None; err: exception_from_error_queue(crypto_Error); return NULL; } static char crypto_Revoked_get_reason_doc[] = "\n\ Return the reason of a Revoked object.\n\ \n\ @return: The reason as a string\n\ "; static PyObject * crypto_Revoked_get_reason(crypto_RevokedObj *self, PyObject *args) { X509_EXTENSION * ext; int j; STACK_OF(X509_EXTENSION) *sk = NULL; if (!PyArg_ParseTuple(args, ":get_reason")) { return NULL; } sk = self->revoked->extensions; for (j = 0; j < sk_X509_EXTENSION_num(sk); j++) { ext = sk_X509_EXTENSION_value(sk, j); if (OBJ_obj2nid(ext->object) == NID_crl_reason) { return X509_EXTENSION_value_to_PyString(ext); } } Py_INCREF(Py_None); return Py_None; } static char crypto_Revoked_get_rev_date_doc[] = "\n\ Retrieve the revocation date\n\ \n\ @return: A string giving the timestamp, in the format:\n\ \n\ YYYYMMDDhhmmssZ\n\ YYYYMMDDhhmmss+hhmm\n\ YYYYMMDDhhmmss-hhmm\n\ "; static PyObject* crypto_Revoked_get_rev_date(crypto_RevokedObj *self, PyObject *args) { /* returns a borrowed reference. */ return _get_asn1_time( ":get_rev_date", self->revoked->revocationDate, args); } static char crypto_Revoked_set_rev_date_doc[] = "\n\ Set the revocation timestamp\n\ \n\ @param when: A string giving the timestamp, in the format:\n\ \n\ YYYYMMDDhhmmssZ\n\ YYYYMMDDhhmmss+hhmm\n\ YYYYMMDDhhmmss-hhmm\n\ \n\ @return: None\n\ "; static PyObject* crypto_Revoked_set_rev_date(crypto_RevokedObj *self, PyObject *args) { return _set_asn1_time( BYTESTRING_FMT ":set_rev_date", self->revoked->revocationDate, args); } /* The integer is converted to an upper-case hex string * without a '0x' prefix. */ static PyObject * ASN1_INTEGER_to_PyString(ASN1_INTEGER *asn1_int) { BIO *bio = NULL; PyObject *str = NULL; int str_len; char *tmp_str; /* Create a openssl BIO buffer */ bio = BIO_new(BIO_s_mem()); if (bio == NULL) { goto err; } /* Write the integer to the BIO as a hex string. */ if (i2a_ASN1_INTEGER(bio, asn1_int) < 0) { goto err; } /* Convert to a Python string. */ str_len = BIO_get_mem_data(bio, &tmp_str); str = PyBytes_FromStringAndSize(tmp_str, str_len); /* Cleanup */ BIO_free(bio); return str; err: if (bio) { BIO_free(bio); } if (str) { Py_DECREF(str); } return NULL; } static char crypto_Revoked_get_serial_doc[] = "\n\ Return the serial number of a Revoked structure\n\ \n\ @return: The serial number as a string\n\ "; static PyObject * crypto_Revoked_get_serial(crypto_RevokedObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":get_serial")) { return NULL; } if (self->revoked->serialNumber == NULL) { /* never happens */ Py_INCREF(Py_None); return Py_None; } else { return ASN1_INTEGER_to_PyString(self->revoked->serialNumber); } } static char crypto_Revoked_set_serial_doc[] = "\n\ Set the serial number of a revoked Revoked structure\n\ \n\ @param hex_str: The new serial number.\n\ @type hex_str: L{str}\n\ @return: None\n\ "; static PyObject * crypto_Revoked_set_serial(crypto_RevokedObj *self, PyObject *args, PyObject *keywds) { static char *kwlist[] = {"hex_str", NULL}; const char *hex_str = NULL; BIGNUM *serial = NULL; ASN1_INTEGER *tmpser = NULL; if (!PyArg_ParseTupleAndKeywords(args, keywds, BYTESTRING_FMT ":set_serial", kwlist, &hex_str)) { return NULL; } if (!BN_hex2bn(&serial, hex_str) ) { PyErr_SetString(PyExc_ValueError, "bad hex string"); return NULL; } tmpser = BN_to_ASN1_INTEGER(serial, NULL); BN_free(serial); serial = NULL; X509_REVOKED_set_serialNumber(self->revoked, tmpser); ASN1_INTEGER_free(tmpser); Py_INCREF(Py_None); return Py_None; } crypto_RevokedObj * crypto_Revoked_New(X509_REVOKED *revoked) { crypto_RevokedObj *self; self = PyObject_New(crypto_RevokedObj, &crypto_Revoked_Type); if (self == NULL) { return NULL; } self->revoked = revoked; return self; } /* * ADD_METHOD(name) expands to a correct PyMethodDef declaration * { 'name', (PyCFunction)crypto_Revoked_name, METH_VARARGS, crypto_Revoked_name_doc } * for convenience */ #define ADD_METHOD(name) \ { #name, (PyCFunction)crypto_Revoked_##name, METH_VARARGS, crypto_Revoked_##name##_doc } #define ADD_KW_METHOD(name) \ { #name, (PyCFunction)crypto_Revoked_##name, METH_VARARGS | METH_KEYWORDS, crypto_Revoked_##name##_doc } static PyMethodDef crypto_Revoked_methods[] = { ADD_METHOD(all_reasons), ADD_METHOD(get_reason), ADD_KW_METHOD(set_reason), ADD_METHOD(get_rev_date), ADD_METHOD(set_rev_date), ADD_METHOD(get_serial), ADD_KW_METHOD(set_serial), { NULL, NULL } }; #undef ADD_METHOD static void crypto_Revoked_dealloc(crypto_RevokedObj *self) { X509_REVOKED_free(self->revoked); self->revoked = NULL; PyObject_Del(self); } static char crypto_Revoked_doc[] = "\n\ Revoked() -> Revoked instance\n\ \n\ Create a new empty Revoked object.\n\ \n\ @returns: The Revoked object\n\ "; static PyObject* crypto_Revoked_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) { if (!PyArg_ParseTuple(args, ":Revoked")) { return NULL; } return (PyObject *)crypto_Revoked_New(X509_REVOKED_new()); } PyTypeObject crypto_Revoked_Type = { PyOpenSSL_HEAD_INIT(&PyType_Type, 0) "Revoked", sizeof(crypto_RevokedObj), 0, (destructor)crypto_Revoked_dealloc, NULL, /* print */ NULL, /* getattr */ NULL, /* setattr */ NULL, /* compare */ NULL, /* repr */ NULL, /* as_number */ NULL, /* as_sequence */ NULL, /* as_mapping */ NULL, /* hash */ NULL, /* call */ NULL, /* str */ NULL, /* getattro */ NULL, /* setattro */ NULL, /* as_buffer */ Py_TPFLAGS_DEFAULT, crypto_Revoked_doc, /* doc */ NULL, /* traverse */ NULL, /* clear */ NULL, /* tp_richcompare */ 0, /* tp_weaklistoffset */ NULL, /* tp_iter */ NULL, /* tp_iternext */ crypto_Revoked_methods, /* tp_methods */ NULL, /* tp_members */ NULL, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ NULL, /* tp_descr_get */ NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ NULL, /* tp_init */ NULL, /* tp_alloc */ crypto_Revoked_new, /* tp_new */ }; int init_crypto_revoked(PyObject *module) { if(PyType_Ready(&crypto_Revoked_Type) < 0) { return 0; } /* PyModule_AddObject steals a reference. */ Py_INCREF((PyObject *)&crypto_Revoked_Type); if (PyModule_AddObject(module, "Revoked", (PyObject *)&crypto_Revoked_Type) != 0) { return 0; } return 1; } pyOpenSSL-0.13/OpenSSL/crypto/revoked.h0000644000214500021450000000065611630175105017660 0ustar bb-slavebb-slave#ifndef PyOpenSSL_crypto_REVOKED_H_ #define PyOpenSSL_crypto_REVOKED_H_ #include extern PyTypeObject crypto_Revoked_Type; #define crypto_Revoked_Check(v) ((v)->ob_type == &crypto_Revoked_Type) typedef struct { PyObject_HEAD X509_REVOKED *revoked; } crypto_RevokedObj; extern int init_crypto_revoked (PyObject *); extern crypto_RevokedObj * crypto_Revoked_New(X509_REVOKED *revoked); #endif pyOpenSSL-0.13/OpenSSL/crypto/x509.c0000644000214500021450000005444711630175105016730 0ustar bb-slavebb-slave/* * x509.c * * Copyright (C) AB Strakt * Copyright (C) Jean-Paul Calderone * See LICENSE for details. * * Certificate (X.509) handling code, mostly thin wrappers around OpenSSL. * See the file RATIONALE for a short explanation of why this module was written. * * Reviewed 2001-07-23 */ #include #define crypto_MODULE #include "crypto.h" #include "x509ext.h" /* * X.509 is a standard for digital certificates. See e.g. the OpenSSL homepage * http://www.openssl.org/ for more information */ static char crypto_X509_get_version_doc[] = "\n\ Return version number of the certificate\n\ \n\ @return: Version number as a Python integer\n\ "; static PyObject * crypto_X509_get_version(crypto_X509Obj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":get_version")) return NULL; return PyLong_FromLong((long)X509_get_version(self->x509)); } static char crypto_X509_set_version_doc[] = "\n\ Set version number of the certificate\n\ \n\ @param version: The version number\n\ @return: None\n\ "; static PyObject * crypto_X509_set_version(crypto_X509Obj *self, PyObject *args) { int version; if (!PyArg_ParseTuple(args, "i:set_version", &version)) return NULL; X509_set_version(self->x509, version); Py_INCREF(Py_None); return Py_None; } static char crypto_X509_get_serial_number_doc[] = "\n\ Return serial number of the certificate\n\ \n\ @return: Serial number as a Python integer\n\ "; static PyObject * crypto_X509_get_serial_number(crypto_X509Obj *self, PyObject *args) { ASN1_INTEGER *asn1_i; BIGNUM *bignum; char *hex; PyObject *res; if (!PyArg_ParseTuple(args, ":get_serial_number")) return NULL; asn1_i = X509_get_serialNumber(self->x509); bignum = ASN1_INTEGER_to_BN(asn1_i, NULL); hex = BN_bn2hex(bignum); res = PyLong_FromString(hex, NULL, 16); BN_free(bignum); free(hex); return res; } static char crypto_X509_set_serial_number_doc[] = "\n\ Set serial number of the certificate\n\ \n\ @param serial: The serial number\n\ @return: None\n\ "; static PyObject * crypto_X509_set_serial_number(crypto_X509Obj *self, PyObject *args) { long small_serial; PyObject *serial = NULL; PyObject *hex = NULL; ASN1_INTEGER *asn1_i = NULL; BIGNUM *bignum = NULL; char *hexstr; if (!PyArg_ParseTuple(args, "O:set_serial_number", &serial)) { return NULL; } if (!PyOpenSSL_Integer_Check(serial)) { PyErr_SetString( PyExc_TypeError, "serial number must be integer"); goto err; } if ((hex = PyOpenSSL_LongToHex(serial)) == NULL) { goto err; } #ifdef PY3 { PyObject *hexbytes = PyUnicode_AsASCIIString(hex); Py_DECREF(hex); hex = hexbytes; } #endif /** * BN_hex2bn stores the result in &bignum. Unless it doesn't feel like * it. If bignum is still NULL after this call, then the return value * is actually the result. I hope. -exarkun */ hexstr = PyBytes_AsString(hex); if (hexstr[1] == 'x') { /* +2 to skip the "0x" */ hexstr += 2; } small_serial = BN_hex2bn(&bignum, hexstr); Py_DECREF(hex); hex = NULL; if (bignum == NULL) { if (ASN1_INTEGER_set(X509_get_serialNumber(self->x509), small_serial)) { exception_from_error_queue(crypto_Error); goto err; } } else { asn1_i = BN_to_ASN1_INTEGER(bignum, NULL); BN_free(bignum); bignum = NULL; if (asn1_i == NULL) { exception_from_error_queue(crypto_Error); goto err; } if (!X509_set_serialNumber(self->x509, asn1_i)) { exception_from_error_queue(crypto_Error); goto err; } ASN1_INTEGER_free(asn1_i); asn1_i = NULL; } Py_INCREF(Py_None); return Py_None; err: if (hex) { Py_DECREF(hex); } if (bignum) { BN_free(bignum); } if (asn1_i) { ASN1_INTEGER_free(asn1_i); } return NULL; } static char crypto_X509_get_issuer_doc[] = "\n\ Create an X509Name object for the issuer of the certificate\n\ \n\ @return: An X509Name object\n\ "; static PyObject * crypto_X509_get_issuer(crypto_X509Obj *self, PyObject *args) { crypto_X509NameObj *pyname; X509_NAME *name; if (!PyArg_ParseTuple(args, ":get_issuer")) return NULL; name = X509_get_issuer_name(self->x509); pyname = crypto_X509Name_New(name, 0); if (pyname != NULL) { pyname->parent_cert = (PyObject *)self; Py_INCREF(self); } return (PyObject *)pyname; } static char crypto_X509_set_issuer_doc[] = "\n\ Set the issuer of the certificate\n\ \n\ @param issuer: The issuer name\n\ @type issuer: L{X509Name}\n\ @return: None\n\ "; static PyObject * crypto_X509_set_issuer(crypto_X509Obj *self, PyObject *args) { crypto_X509NameObj *issuer; if (!PyArg_ParseTuple(args, "O!:set_issuer", &crypto_X509Name_Type, &issuer)) return NULL; if (!X509_set_issuer_name(self->x509, issuer->x509_name)) { exception_from_error_queue(crypto_Error); return NULL; } Py_INCREF(Py_None); return Py_None; } static char crypto_X509_get_subject_doc[] = "\n\ Create an X509Name object for the subject of the certificate\n\ \n\ @return: An X509Name object\n\ "; static PyObject * crypto_X509_get_subject(crypto_X509Obj *self, PyObject *args) { crypto_X509NameObj *pyname; X509_NAME *name; if (!PyArg_ParseTuple(args, ":get_subject")) return NULL; name = X509_get_subject_name(self->x509); pyname = crypto_X509Name_New(name, 0); if (pyname != NULL) { pyname->parent_cert = (PyObject *)self; Py_INCREF(self); } return (PyObject *)pyname; } static char crypto_X509_set_subject_doc[] = "\n\ Set the subject of the certificate\n\ \n\ @param subject: The subject name\n\ @type subject: L{X509Name}\n\ @return: None\n\ "; static PyObject * crypto_X509_set_subject(crypto_X509Obj *self, PyObject *args) { crypto_X509NameObj *subject; if (!PyArg_ParseTuple(args, "O!:set_subject", &crypto_X509Name_Type, &subject)) return NULL; if (!X509_set_subject_name(self->x509, subject->x509_name)) { exception_from_error_queue(crypto_Error); return NULL; } Py_INCREF(Py_None); return Py_None; } static char crypto_X509_get_pubkey_doc[] = "\n\ Get the public key of the certificate\n\ \n\ @return: The public key\n\ "; static PyObject * crypto_X509_get_pubkey(crypto_X509Obj *self, PyObject *args) { crypto_PKeyObj *crypto_PKey_New(EVP_PKEY *, int); EVP_PKEY *pkey; crypto_PKeyObj *py_pkey; if (!PyArg_ParseTuple(args, ":get_pubkey")) return NULL; if ((pkey = X509_get_pubkey(self->x509)) == NULL) { exception_from_error_queue(crypto_Error); return NULL; } py_pkey = crypto_PKey_New(pkey, 1); if (py_pkey != NULL) { py_pkey->only_public = 1; } return (PyObject *)py_pkey; } static char crypto_X509_set_pubkey_doc[] = "\n\ Set the public key of the certificate\n\ \n\ @param pkey: The public key\n\ @return: None\n\ "; static PyObject * crypto_X509_set_pubkey(crypto_X509Obj *self, PyObject *args) { crypto_PKeyObj *pkey; if (!PyArg_ParseTuple(args, "O!:set_pubkey", &crypto_PKey_Type, &pkey)) return NULL; if (!X509_set_pubkey(self->x509, pkey->pkey)) { exception_from_error_queue(crypto_Error); return NULL; } Py_INCREF(Py_None); return Py_None; } PyObject* _set_asn1_time(char *format, ASN1_TIME* timestamp, PyObject *args) { char *when; if (!PyArg_ParseTuple(args, format, &when)) return NULL; if (ASN1_GENERALIZEDTIME_set_string(timestamp, when) == 0) { ASN1_GENERALIZEDTIME dummy; dummy.type = V_ASN1_GENERALIZEDTIME; dummy.length = strlen(when); dummy.data = (unsigned char *)when; if (!ASN1_GENERALIZEDTIME_check(&dummy)) { PyErr_SetString(PyExc_ValueError, "Invalid string"); } else { PyErr_SetString(PyExc_RuntimeError, "Unknown ASN1_GENERALIZEDTIME_set_string failure"); } return NULL; } Py_INCREF(Py_None); return Py_None; } static char crypto_X509_set_notBefore_doc[] = "\n\ Set the time stamp for when the certificate starts being valid\n\ \n\ @param when: A string giving the timestamp, in the format:\n\ \n\ YYYYMMDDhhmmssZ\n\ YYYYMMDDhhmmss+hhmm\n\ YYYYMMDDhhmmss-hhmm\n\ \n\ @return: None\n\ "; static PyObject* crypto_X509_set_notBefore(crypto_X509Obj *self, PyObject *args) { return _set_asn1_time( BYTESTRING_FMT ":set_notBefore", X509_get_notBefore(self->x509), args); } static char crypto_X509_set_notAfter_doc[] = "\n\ Set the time stamp for when the certificate stops being valid\n\ \n\ @param when: A string giving the timestamp, in the format:\n\ \n\ YYYYMMDDhhmmssZ\n\ YYYYMMDDhhmmss+hhmm\n\ YYYYMMDDhhmmss-hhmm\n\ \n\ @return: None\n\ "; static PyObject* crypto_X509_set_notAfter(crypto_X509Obj *self, PyObject *args) { return _set_asn1_time( BYTESTRING_FMT ":set_notAfter", X509_get_notAfter(self->x509), args); } PyObject* _get_asn1_time(char *format, ASN1_TIME* timestamp, PyObject *args) { ASN1_GENERALIZEDTIME *gt_timestamp = NULL; PyObject *py_timestamp = NULL; if (!PyArg_ParseTuple(args, format)) { return NULL; } /* * http://www.columbia.edu/~ariel/ssleay/asn1-time.html */ /* * There must be a way to do this without touching timestamp->data * directly. -exarkun */ if (timestamp->length == 0) { Py_INCREF(Py_None); return Py_None; } else if (timestamp->type == V_ASN1_GENERALIZEDTIME) { return PyBytes_FromString((char *)timestamp->data); } else { ASN1_TIME_to_generalizedtime(timestamp, >_timestamp); if (gt_timestamp == NULL) { exception_from_error_queue(crypto_Error); return NULL; } else { py_timestamp = PyBytes_FromString((char *)gt_timestamp->data); ASN1_GENERALIZEDTIME_free(gt_timestamp); return py_timestamp; } } } static char crypto_X509_get_notBefore_doc[] = "\n\ Retrieve the time stamp for when the certificate starts being valid\n\ \n\ @return: A string giving the timestamp, in the format:\n\ \n\ YYYYMMDDhhmmssZ\n\ YYYYMMDDhhmmss+hhmm\n\ YYYYMMDDhhmmss-hhmm\n\ or None if there is no value set.\n\ "; static PyObject* crypto_X509_get_notBefore(crypto_X509Obj *self, PyObject *args) { /* * X509_get_notBefore returns a borrowed reference. */ return _get_asn1_time( ":get_notBefore", X509_get_notBefore(self->x509), args); } static char crypto_X509_get_notAfter_doc[] = "\n\ Retrieve the time stamp for when the certificate stops being valid\n\ \n\ @return: A string giving the timestamp, in the format:\n\ \n\ YYYYMMDDhhmmssZ\n\ YYYYMMDDhhmmss+hhmm\n\ YYYYMMDDhhmmss-hhmm\n\ or None if there is no value set.\n\ "; static PyObject* crypto_X509_get_notAfter(crypto_X509Obj *self, PyObject *args) { /* * X509_get_notAfter returns a borrowed reference. */ return _get_asn1_time( ":get_notAfter", X509_get_notAfter(self->x509), args); } static char crypto_X509_gmtime_adj_notBefore_doc[] = "\n\ Change the timestamp for when the certificate starts being valid to the current\n\ time plus an offset.\n \ \n\ @param amount: The number of seconds by which to adjust the starting validity\n\ time.\n\ @return: None\n\ "; static PyObject * crypto_X509_gmtime_adj_notBefore(crypto_X509Obj *self, PyObject *args) { long amount; if (!PyArg_ParseTuple(args, "l:gmtime_adj_notBefore", &amount)) return NULL; X509_gmtime_adj(X509_get_notBefore(self->x509), amount); Py_INCREF(Py_None); return Py_None; } static char crypto_X509_gmtime_adj_notAfter_doc[] = "\n\ Adjust the time stamp for when the certificate stops being valid\n\ \n\ @param amount: The number of seconds by which to adjust the ending validity\n\ time.\n\ @return: None\n\ "; static PyObject * crypto_X509_gmtime_adj_notAfter(crypto_X509Obj *self, PyObject *args) { long amount; if (!PyArg_ParseTuple(args, "l:gmtime_adj_notAfter", &amount)) return NULL; X509_gmtime_adj(X509_get_notAfter(self->x509), amount); Py_INCREF(Py_None); return Py_None; } static char crypto_X509_get_signature_algorithm_doc[] = "\n\ Retrieve the signature algorithm used in the certificate\n\ \n\ @return: A byte string giving the name of the signature algorithm used in\n\ the certificate.\n\ @raise ValueError: If the signature algorithm is undefined.\n\ "; static PyObject * crypto_X509_get_signature_algorithm(crypto_X509Obj *self, PyObject *args) { ASN1_OBJECT *alg; int nid; if (!PyArg_ParseTuple(args, ":get_signature_algorithm")) { return NULL; } alg = self->x509->cert_info->signature->algorithm; nid = OBJ_obj2nid(alg); if (nid == NID_undef) { PyErr_SetString(PyExc_ValueError, "Undefined signature algorithm"); return NULL; } return PyBytes_FromString(OBJ_nid2ln(nid)); } static char crypto_X509_sign_doc[] = "\n\ Sign the certificate using the supplied key and digest\n\ \n\ @param pkey: The key to sign with\n\ @param digest: The message digest to use\n\ @return: None\n\ "; static PyObject * crypto_X509_sign(crypto_X509Obj *self, PyObject *args) { crypto_PKeyObj *pkey; char *digest_name; const EVP_MD *digest; if (!PyArg_ParseTuple(args, "O!s:sign", &crypto_PKey_Type, &pkey, &digest_name)) return NULL; if (pkey->only_public) { PyErr_SetString(PyExc_ValueError, "Key has only public part"); return NULL; } if (!pkey->initialized) { PyErr_SetString(PyExc_ValueError, "Key is uninitialized"); return NULL; } if ((digest = EVP_get_digestbyname(digest_name)) == NULL) { PyErr_SetString(PyExc_ValueError, "No such digest method"); return NULL; } if (!X509_sign(self->x509, pkey->pkey, digest)) { exception_from_error_queue(crypto_Error); return NULL; } Py_INCREF(Py_None); return Py_None; } static char crypto_X509_has_expired_doc[] = "\n\ Check whether the certificate has expired.\n\ \n\ @return: True if the certificate has expired, false otherwise\n\ "; static PyObject * crypto_X509_has_expired(crypto_X509Obj *self, PyObject *args) { time_t tnow; if (!PyArg_ParseTuple(args, ":has_expired")) return NULL; tnow = time(NULL); if (ASN1_UTCTIME_cmp_time_t(X509_get_notAfter(self->x509), tnow) < 0) return PyLong_FromLong(1L); else return PyLong_FromLong(0L); } static char crypto_X509_subject_name_hash_doc[] = "\n\ Return the hash of the X509 subject.\n\ \n\ @return: The hash of the subject\n\ "; static PyObject * crypto_X509_subject_name_hash(crypto_X509Obj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":subject_name_hash")) return NULL; return PyLong_FromLongLong(X509_subject_name_hash(self->x509)); } static char crypto_X509_digest_doc[] = "\n\ Return the digest of the X509 object.\n\ \n\ @return: The digest of the object\n\ "; static PyObject * crypto_X509_digest(crypto_X509Obj *self, PyObject *args) { unsigned char fp[EVP_MAX_MD_SIZE]; char *tmp; char *digest_name; unsigned int len,i; PyObject *ret; const EVP_MD *digest; if (!PyArg_ParseTuple(args, "s:digest", &digest_name)) return NULL; if ((digest = EVP_get_digestbyname(digest_name)) == NULL) { PyErr_SetString(PyExc_ValueError, "No such digest method"); return NULL; } if (!X509_digest(self->x509,digest,fp,&len)) { exception_from_error_queue(crypto_Error); } tmp = malloc(3*len+1); memset(tmp, 0, 3*len+1); for (i = 0; i < len; i++) { sprintf(tmp+i*3,"%02X:",fp[i]); } tmp[3*len-1] = 0; ret = PyBytes_FromStringAndSize(tmp,3*len-1); free(tmp); return ret; } static char crypto_X509_add_extensions_doc[] = "\n\ Add extensions to the certificate.\n\ \n\ @param extensions: a sequence of X509Extension objects\n\ @return: None\n\ "; static PyObject * crypto_X509_add_extensions(crypto_X509Obj *self, PyObject *args) { PyObject *extensions, *seq; crypto_X509ExtensionObj *ext; int nr_of_extensions, i; if (!PyArg_ParseTuple(args, "O:add_extensions", &extensions)) return NULL; seq = PySequence_Fast(extensions, "Expected a sequence"); if (seq == NULL) return NULL; nr_of_extensions = PySequence_Fast_GET_SIZE(seq); for (i = 0; i < nr_of_extensions; i++) { ext = (crypto_X509ExtensionObj *)PySequence_Fast_GET_ITEM(seq, i); if (!crypto_X509Extension_Check(ext)) { Py_DECREF(seq); PyErr_SetString(PyExc_ValueError, "One of the elements is not an X509Extension"); return NULL; } if (!X509_add_ext(self->x509, ext->x509_extension, -1)) { Py_DECREF(seq); exception_from_error_queue(crypto_Error); return NULL; } } Py_INCREF(Py_None); return Py_None; } static char crypto_X509_get_extension_count_doc[] = "\n\ Get the number of extensions on the certificate.\n\ \n\ @return: Number of extensions as a Python integer\n\ "; static PyObject * crypto_X509_get_extension_count(crypto_X509Obj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":get_extension_count")) { return NULL; } return PyLong_FromLong((long)X509_get_ext_count(self->x509)); } static char crypto_X509_get_extension_doc[] = "\n\ Get a specific extension of the certificate by index.\n\ \n\ @param index: The index of the extension to retrieve.\n\ @return: The X509Extension object at the specified index.\n\ "; static PyObject * crypto_X509_get_extension(crypto_X509Obj *self, PyObject *args) { crypto_X509ExtensionObj *extobj; int loc; X509_EXTENSION *ext; if (!PyArg_ParseTuple(args, "i:get_extension", &loc)) { return NULL; } /* will return NULL if loc is outside the range of extensions, not registered as an error*/ ext = X509_get_ext(self->x509, loc); if (!ext) { PyErr_SetString(PyExc_IndexError, "extension index out of bounds"); return NULL; /* Should be reported as an IndexError ? */ } extobj = PyObject_New(crypto_X509ExtensionObj, &crypto_X509Extension_Type); extobj->x509_extension = X509_EXTENSION_dup(ext); return (PyObject*)extobj; } /* * ADD_METHOD(name) expands to a correct PyMethodDef declaration * { 'name', (PyCFunction)crypto_X509_name, METH_VARARGS } * for convenience */ #define ADD_METHOD(name) \ { #name, (PyCFunction)crypto_X509_##name, METH_VARARGS, crypto_X509_##name##_doc } static PyMethodDef crypto_X509_methods[] = { ADD_METHOD(get_version), ADD_METHOD(set_version), ADD_METHOD(get_serial_number), ADD_METHOD(set_serial_number), ADD_METHOD(get_issuer), ADD_METHOD(set_issuer), ADD_METHOD(get_subject), ADD_METHOD(set_subject), ADD_METHOD(get_pubkey), ADD_METHOD(set_pubkey), ADD_METHOD(get_notBefore), ADD_METHOD(set_notBefore), ADD_METHOD(get_notAfter), ADD_METHOD(set_notAfter), ADD_METHOD(gmtime_adj_notBefore), ADD_METHOD(gmtime_adj_notAfter), ADD_METHOD(get_signature_algorithm), ADD_METHOD(sign), ADD_METHOD(has_expired), ADD_METHOD(subject_name_hash), ADD_METHOD(digest), ADD_METHOD(add_extensions), ADD_METHOD(get_extension), ADD_METHOD(get_extension_count), { NULL, NULL } }; #undef ADD_METHOD /* * Constructor for X509 objects, never called by Python code directly * * Arguments: cert - A "real" X509 certificate object * dealloc - Boolean value to specify whether the destructor should * free the "real" X509 object * Returns: The newly created X509 object */ crypto_X509Obj * crypto_X509_New(X509 *cert, int dealloc) { crypto_X509Obj *self; self = PyObject_New(crypto_X509Obj, &crypto_X509_Type); if (self == NULL) return NULL; self->x509 = cert; self->dealloc = dealloc; return self; } static char crypto_X509_doc[] = "\n\ X509() -> X509 instance\n\ \n\ Create a new X509 object.\n\ \n\ @returns: The X509 object\n\ "; static PyObject * crypto_X509_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) { if (!PyArg_ParseTuple(args, ":X509")) { return NULL; } return (PyObject *)crypto_X509_New(X509_new(), 1); } /* * Deallocate the memory used by the X509 object * * Arguments: self - The X509 object * Returns: None */ static void crypto_X509_dealloc(crypto_X509Obj *self) { /* Sometimes we don't have to dealloc the "real" X509 pointer ourselves */ if (self->dealloc) X509_free(self->x509); PyObject_Del(self); } PyTypeObject crypto_X509_Type = { PyOpenSSL_HEAD_INIT(&PyType_Type, 0) "X509", sizeof(crypto_X509Obj), 0, (destructor)crypto_X509_dealloc, NULL, /* print */ NULL, /* getattr */ NULL, /* setattr */ NULL, /* compare */ NULL, /* repr */ NULL, /* as_number */ NULL, /* as_sequence */ NULL, /* as_mapping */ NULL, /* hash */ NULL, /* call */ NULL, /* str */ NULL, /* getattro */ NULL, /* setattro */ NULL, /* as_buffer */ Py_TPFLAGS_DEFAULT, crypto_X509_doc, /* doc */ NULL, /* traverse */ NULL, /* clear */ NULL, /* tp_richcompare */ 0, /* tp_weaklistoffset */ NULL, /* tp_iter */ NULL, /* tp_iternext */ crypto_X509_methods, /* tp_methods */ NULL, /* tp_members */ NULL, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ NULL, /* tp_descr_get */ NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ NULL, /* tp_init */ NULL, /* tp_alloc */ crypto_X509_new, /* tp_new */ }; /* * Initialize the X509 part of the crypto sub module * * Arguments: module - The crypto module * Returns: None */ int init_crypto_x509(PyObject *module) { if (PyType_Ready(&crypto_X509_Type) < 0) { return 0; } /* PyModule_AddObject steals a reference. */ Py_INCREF((PyObject *)&crypto_X509_Type); if (PyModule_AddObject(module, "X509", (PyObject *)&crypto_X509_Type) != 0) { return 0; } Py_INCREF((PyObject *)&crypto_X509_Type); if (PyModule_AddObject(module, "X509Type", (PyObject *)&crypto_X509_Type) != 0) { return 0; } return 1; } pyOpenSSL-0.13/OpenSSL/crypto/x509.h0000644000214500021450000000143111630175105016716 0ustar bb-slavebb-slave/* * x509.h * * Copyright (C) AB Strakt * See LICENSE for details. * * Export x509 functions and data structure. * See the file RATIONALE for a short explanation of why this module was written. * * Reviewed 2001-07-23 * */ #ifndef PyOpenSSL_crypto_X509_H_ #define PyOpenSSL_crypto_X509_H_ #include #include extern PyTypeObject crypto_X509_Type; #define crypto_X509_Check(v) ((v)->ob_type == &crypto_X509_Type) typedef struct { PyObject_HEAD X509 *x509; int dealloc; } crypto_X509Obj; PyObject* _set_asn1_time(char *format, ASN1_TIME* timestamp, PyObject *args); PyObject* _get_asn1_time(char *format, ASN1_TIME* timestamp, PyObject *args); extern int init_crypto_x509 (PyObject *); #endif pyOpenSSL-0.13/OpenSSL/crypto/x509ext.c0000644000214500021450000002232311630175105017435 0ustar bb-slavebb-slave/* * x509ext.c * * Copyright (C) Jean-Paul Calderone * See LICENSE for details. * * Export X.509 extension functions and data structures. * See the file RATIONALE for a short explanation of why this module was written. * */ #include #define crypto_MODULE #include "crypto.h" static char crypto_X509Extension_get_critical_doc[] = "\n\ Returns the critical field of the X509Extension\n\ \n\ @return: The critical field.\n\ "; static PyObject * crypto_X509Extension_get_critical(crypto_X509ExtensionObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":get_critical")) return NULL; return PyLong_FromLong(X509_EXTENSION_get_critical(self->x509_extension)); } static char crypto_X509Extension_get_short_name_doc[] = "\n\ Returns the short version of the type name of the X509Extension\n\ \n\ @return: The short type name.\n\ "; static PyObject * crypto_X509Extension_get_short_name(crypto_X509ExtensionObj *self, PyObject *args) { ASN1_OBJECT *obj; const char *extname; if (!PyArg_ParseTuple(args, ":get_short_name")) { return NULL; } /* Returns an internal pointer to x509_extension, not a copy */ obj = X509_EXTENSION_get_object(self->x509_extension); extname = OBJ_nid2sn(OBJ_obj2nid(obj)); return PyBytes_FromString(extname); } static char crypto_X509Extension_get_data_doc[] = "\n\ Returns the data of the X509Extension\n\ \n\ @return: A C{str} giving the X509Extension's ASN.1 encoded data.\n\ "; static PyObject * crypto_X509Extension_get_data(crypto_X509ExtensionObj *self, PyObject *args) { ASN1_OCTET_STRING *data; PyObject *result; if (!PyArg_ParseTuple(args, ":get_data")) { return NULL; } data = X509_EXTENSION_get_data(self->x509_extension); result = PyBytes_FromStringAndSize((const char*)data->data, data->length); return result; } /* * ADD_METHOD(name) expands to a correct PyMethodDef declaration * { 'name', (PyCFunction)crypto_X509Extension_name, METH_VARARGS } * for convenience */ #define ADD_METHOD(name) \ { #name, (PyCFunction)crypto_X509Extension_##name, METH_VARARGS, crypto_X509Extension_##name##_doc } static PyMethodDef crypto_X509Extension_methods[] = { ADD_METHOD(get_critical), ADD_METHOD(get_short_name), ADD_METHOD(get_data), { NULL, NULL } }; #undef ADD_METHOD /* * Constructor for X509Extension, never called by Python code directly * * Arguments: type_name - ??? * critical - ??? * value - ??? * subject - An x509v3 certificate which is the subject for this extension. * issuer - An x509v3 certificate which is the issuer for this extension. * Returns: The newly created X509Extension object */ crypto_X509ExtensionObj * crypto_X509Extension_New(char *type_name, int critical, char *value, crypto_X509Obj *subject, crypto_X509Obj *issuer) { X509V3_CTX ctx; crypto_X509ExtensionObj *self; char* value_with_critical = NULL; /* * A context is necessary for any extension which uses the r2i conversion * method. That is, X509V3_EXT_nconf may segfault if passed a NULL ctx. * Start off by initializing most of the fields to NULL. */ X509V3_set_ctx(&ctx, NULL, NULL, NULL, NULL, 0); /* * We have no configuration database - but perhaps we should (some * extensions may require it). */ X509V3_set_ctx_nodb(&ctx); /* * Initialize the subject and issuer, if appropriate. ctx is a local, and * as far as I can tell none of the X509V3_* APIs invoked here steal any * references, so no need to incref subject or issuer. */ if (subject) { ctx.subject_cert = subject->x509; } if (issuer) { ctx.issuer_cert = issuer->x509; } self = PyObject_New(crypto_X509ExtensionObj, &crypto_X509Extension_Type); if (self == NULL) { goto error; } self->dealloc = 0; /* There are other OpenSSL APIs which would let us pass in critical * separately, but they're harder to use, and since value is already a pile * of crappy junk smuggling a ton of utterly important structured data, * what's the point of trying to avoid nasty stuff with strings? (However, * X509V3_EXT_i2d in particular seems like it would be a better API to * invoke. I do not know where to get the ext_struc it desires for its * last parameter, though.) */ value_with_critical = malloc(strlen("critical,") + strlen(value) + 1); if (!value_with_critical) { goto critical_malloc_error; } if (critical) { strcpy(value_with_critical, "critical,"); strcpy(value_with_critical + strlen("critical,"), value); } else { strcpy(value_with_critical, value); } self->x509_extension = X509V3_EXT_nconf( NULL, &ctx, type_name, value_with_critical); free(value_with_critical); if (!self->x509_extension) { goto nconf_error; } self->dealloc = 1; return self; nconf_error: exception_from_error_queue(crypto_Error); critical_malloc_error: Py_XDECREF(self); error: return NULL; } static char crypto_X509Extension_doc[] = "\n\ X509Extension(typename, critical, value[, subject][, issuer]) -> \n\ X509Extension instance\n\ \n\ @param typename: The name of the extension to create.\n\ @type typename: C{str}\n\ @param critical: A flag indicating whether this is a critical extension.\n\ @param value: The value of the extension.\n\ @type value: C{str}\n\ @param subject: Optional X509 cert to use as subject.\n\ @type subject: C{X509}\n\ @param issuer: Optional X509 cert to use as issuer.\n\ @type issuer: C{X509}\n\ @return: The X509Extension object\n\ "; static PyObject * crypto_X509Extension_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) { char *type_name, *value; int critical = 0; crypto_X509Obj * subject = NULL; crypto_X509Obj * issuer = NULL; static char *kwlist[] = {"type_name", "critical", "value", "subject", "issuer", NULL}; if (!PyArg_ParseTupleAndKeywords( args, kwargs, BYTESTRING_FMT "i" BYTESTRING_FMT "|O!O!:X509Extension", kwlist, &type_name, &critical, &value, &crypto_X509_Type, &subject, &crypto_X509_Type, &issuer )) { return NULL; } return (PyObject *)crypto_X509Extension_New(type_name, critical, value, subject, issuer); } /* * Deallocate the memory used by the X509Extension object * * Arguments: self - The X509Extension object * Returns: None */ static void crypto_X509Extension_dealloc(crypto_X509ExtensionObj *self) { /* Sometimes we don't have to dealloc this */ if (self->dealloc) X509_EXTENSION_free(self->x509_extension); PyObject_Del(self); } /* * Print a nice text representation of the certificate request. */ static PyObject * crypto_X509Extension_str(crypto_X509ExtensionObj *self) { int str_len; char *tmp_str; PyObject *str; BIO *bio = BIO_new(BIO_s_mem()); if (!X509V3_EXT_print(bio, self->x509_extension, 0, 0)) { BIO_free(bio); exception_from_error_queue(crypto_Error); return NULL; } str_len = BIO_get_mem_data(bio, &tmp_str); str = PyText_FromStringAndSize(tmp_str, str_len); BIO_free(bio); return str; } PyTypeObject crypto_X509Extension_Type = { PyOpenSSL_HEAD_INIT(&PyType_Type, 0) "X509Extension", sizeof(crypto_X509ExtensionObj), 0, (destructor)crypto_X509Extension_dealloc, NULL, /* print */ NULL, /* getattr */ NULL, /* setattr (setattrfunc)crypto_X509Name_setattr, */ NULL, /* compare */ NULL, /* repr */ NULL, /* as_number */ NULL, /* as_sequence */ NULL, /* as_mapping */ NULL, /* hash */ NULL, /* call */ (reprfunc)crypto_X509Extension_str, /* str */ NULL, /* getattro */ NULL, /* setattro */ NULL, /* as_buffer */ Py_TPFLAGS_DEFAULT, crypto_X509Extension_doc, /* doc */ NULL, /* traverse */ NULL, /* clear */ NULL, /* tp_richcompare */ 0, /* tp_weaklistoffset */ NULL, /* tp_iter */ NULL, /* tp_iternext */ crypto_X509Extension_methods, /* tp_methods */ NULL, /* tp_members */ NULL, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ NULL, /* tp_descr_get */ NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ NULL, /* tp_init */ NULL, /* tp_alloc */ crypto_X509Extension_new, /* tp_new */ }; /* * Initialize the X509Extension part of the crypto module * * Arguments: dict - The crypto module * Returns: None */ int init_crypto_x509extension(PyObject *module) { if (PyType_Ready(&crypto_X509Extension_Type) < 0) { return 0; } /* PyModule_AddObject steals a reference. */ Py_INCREF((PyObject *)&crypto_X509Extension_Type); if (PyModule_AddObject(module, "X509Extension", (PyObject *)&crypto_X509Extension_Type) != 0) { return 0; } /* PyModule_AddObject steals a reference. */ Py_INCREF((PyObject *)&crypto_X509Extension_Type); if (PyModule_AddObject(module, "X509ExtensionType", (PyObject *)&crypto_X509Extension_Type) != 0) { return 0; } return 1; } pyOpenSSL-0.13/OpenSSL/crypto/x509ext.h0000644000214500021450000000142011630175105017435 0ustar bb-slavebb-slave/* * x509ext.h * * Copyright (C) Awanim * See LICENSE for details. * * Export X.509 extension functions and data structures. * See the file RATIONALE for a short explanation of why this module was written. * */ #ifndef PyOpenSSL_crypto_X509EXTENSION_H_ #define PyOpenSSL_crypto_X509EXTENSION_H_ #include #include #include extern int init_crypto_x509extension (PyObject *); extern PyTypeObject crypto_X509Extension_Type; #define crypto_X509Extension_Check(v) ( \ PyObject_TypeCheck((v), \ &crypto_X509Extension_Type)) typedef struct { PyObject_HEAD X509_EXTENSION *x509_extension; int dealloc; } crypto_X509ExtensionObj; #endif pyOpenSSL-0.13/OpenSSL/crypto/x509name.c0000644000214500021450000003275211630175105017564 0ustar bb-slavebb-slave/* * x509name.c * * Copyright (C) AB Strakt * Copyright (C) Jean-Paul Calderone * See LICENSE for details. * * X.509 Name handling, mostly thin wrapping. * See the file RATIONALE for a short explanation of why this module was written. * * Reviewed 2001-07-23 */ #include #define crypto_MODULE #include "crypto.h" static PyMethodDef crypto_X509Name_methods[4]; /* * Constructor for X509Name, never called by Python code directly * * Arguments: name - A "real" X509_NAME object * dealloc - Boolean value to specify whether the destructor should * free the "real" X509_NAME object * Returns: The newly created X509Name object */ crypto_X509NameObj * crypto_X509Name_New(X509_NAME *name, int dealloc) { crypto_X509NameObj *self; self = PyObject_GC_New(crypto_X509NameObj, &crypto_X509Name_Type); if (self == NULL) return NULL; self->x509_name = name; self->dealloc = dealloc; self->parent_cert = NULL; PyObject_GC_Track(self); return self; } static char crypto_X509Name_doc[] = "\n\ X509Name(name) -> New X509Name object\n\ \n\ Create a new X509Name, copying the given X509Name instance.\n\ \n\ @param name: An X509Name object to copy\n\ @return: The X509Name object\n\ "; static PyObject * crypto_X509Name_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) { crypto_X509NameObj *name; if (!PyArg_ParseTuple(args, "O!:X509Name", &crypto_X509Name_Type, &name)) { return NULL; } return (PyObject *)crypto_X509Name_New(X509_NAME_dup(name->x509_name), 1); } /* * Return a name string given a X509_NAME object and a name identifier. Used * by the getattr function. * * Arguments: name - The X509_NAME object * nid - The name identifier * Returns: The name as a Python string object */ static int get_name_by_nid(X509_NAME *name, int nid, char **utf8string) { int entry_idx; X509_NAME_ENTRY *entry; ASN1_STRING *data; int len; if ((entry_idx = X509_NAME_get_index_by_NID(name, nid, -1)) == -1) { return 0; } entry = X509_NAME_get_entry(name, entry_idx); data = X509_NAME_ENTRY_get_data(entry); if ((len = ASN1_STRING_to_UTF8((unsigned char **)utf8string, data)) < 0) { exception_from_error_queue(crypto_Error); return -1; } return len; } /* * Given a X509_NAME object and a name identifier, set the corresponding * attribute to the given string. Used by the setattr function. * * Arguments: name - The X509_NAME object * nid - The name identifier * value - The string to set * Returns: 0 for success, -1 on failure */ static int set_name_by_nid(X509_NAME *name, int nid, char *utf8string) { X509_NAME_ENTRY *ne; int i, entry_count, temp_nid; /* If there's an old entry for this NID, remove it */ entry_count = X509_NAME_entry_count(name); for (i = 0; i < entry_count; i++) { ne = X509_NAME_get_entry(name, i); temp_nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(ne)); if (temp_nid == nid) { ne = X509_NAME_delete_entry(name, i); X509_NAME_ENTRY_free(ne); break; } } /* Add the new entry */ if (!X509_NAME_add_entry_by_NID(name, nid, MBSTRING_UTF8, (unsigned char *)utf8string, -1, -1, 0)) { exception_from_error_queue(crypto_Error); return -1; } return 0; } /* * Find attribute. An X509Name object has the following attributes: * countryName (alias C), stateOrProvince (alias ST), locality (alias L), * organization (alias O), organizationalUnit (alias OU), commonName (alias * CN) and more... * * Arguments: self - The X509Name object * name - The attribute name * Returns: A Python object for the attribute, or NULL if something went * wrong */ static PyObject * crypto_X509Name_getattro(crypto_X509NameObj *self, PyObject *nameobj) { int nid, len; char *utf8string; char *name; #ifdef PY3 name = PyBytes_AsString(PyUnicode_AsASCIIString(nameobj)); #else name = PyBytes_AsString(nameobj); #endif if ((nid = OBJ_txt2nid(name)) == NID_undef) { /* * This is a bit weird. OBJ_txt2nid indicated failure, but it seems * a lower level function, a2d_ASN1_OBJECT, also feels the need to * push something onto the error queue. If we don't clean that up * now, someone else will bump into it later and be quite confused. * See lp#314814. */ flush_error_queue(); return PyObject_GenericGetAttr((PyObject*)self, nameobj); } len = get_name_by_nid(self->x509_name, nid, &utf8string); if (len < 0) return NULL; else if (len == 0) { Py_INCREF(Py_None); return Py_None; } else { PyObject* result = PyUnicode_Decode(utf8string, len, "utf-8", NULL); OPENSSL_free(utf8string); return result; } } /* * Set attribute * * Arguments: self - The X509Name object * name - The attribute name * value - The value to set */ static int crypto_X509Name_setattro(crypto_X509NameObj *self, PyObject *nameobj, PyObject *value) { int nid; int result; char *buffer; char *name; if (!PyBytes_CheckExact(nameobj) && !PyUnicode_CheckExact(nameobj)) { PyErr_Format(PyExc_TypeError, "attribute name must be string, not '%.200s'", Py_TYPE(nameobj)->tp_name); return -1; } #ifdef PY3 name = PyBytes_AsString(PyUnicode_AsASCIIString(nameobj)); #else name = PyBytes_AsString(nameobj); #endif if ((nid = OBJ_txt2nid(name)) == NID_undef) { /* Just like the case in the getattr function */ flush_error_queue(); PyErr_SetString(PyExc_AttributeError, "No such attribute"); return -1; } /* Something of a hack to get nice unicode behaviour */ if (!PyArg_Parse(value, "es:setattr", "utf-8", &buffer)) return -1; result = set_name_by_nid(self->x509_name, nid, buffer); PyMem_Free(buffer); return result; } /* * Compare two X509Name structures. * * Arguments: n - The first X509Name * m - The second X509Name * Returns: <0 if n < m, 0 if n == m and >0 if n > m */ static PyObject * crypto_X509Name_richcompare(PyObject *n, PyObject *m, int op) { int result; if (!crypto_X509Name_Check(n) || !crypto_X509Name_Check(m)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } result = X509_NAME_cmp( ((crypto_X509NameObj*)n)->x509_name, ((crypto_X509NameObj*)m)->x509_name); switch (op) { case Py_EQ: result = (result == 0); break; case Py_NE: result = (result != 0); break; case Py_LT: result = (result < 0); break; case Py_LE: result = (result <= 0); break; case Py_GT: result = (result > 0); break; case Py_GE: result = (result >= 0); break; default: /* Should be impossible */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } if (result) { Py_INCREF(Py_True); return Py_True; } else { Py_INCREF(Py_False); return Py_False; } } /* * String representation of an X509Name * * Arguments: self - The X509Name object * Returns: A string representation of the object */ static PyObject * crypto_X509Name_repr(crypto_X509NameObj *self) { char tmpbuf[512] = ""; char realbuf[512+64]; if (X509_NAME_oneline(self->x509_name, tmpbuf, 512) == NULL) { exception_from_error_queue(crypto_Error); return NULL; } else { /* This is safe because tmpbuf is max 512 characters */ sprintf(realbuf, "", tmpbuf); return PyText_FromString(realbuf); } } static char crypto_X509Name_hash_doc[] = "\n\ Return the hash value of this name\n\ \n\ @return: None\n\ "; /* * First four bytes of the MD5 digest of the DER form of an X509Name. * * Arguments: self - The X509Name object * Returns: An integer giving the hash. */ static PyObject * crypto_X509Name_hash(crypto_X509NameObj *self, PyObject* args) { unsigned long hash; if (!PyArg_ParseTuple(args, ":hash")) { return NULL; } hash = X509_NAME_hash(self->x509_name); return PyLong_FromLong(hash); } static char crypto_X509Name_der_doc[] = "\n\ Return the DER encoding of this name\n\ \n\ @return: None\n\ "; /* * Arguments: self - The X509Name object * Returns: The DER form of an X509Name. */ static PyObject * crypto_X509Name_der(crypto_X509NameObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":der")) { return NULL; } i2d_X509_NAME(self->x509_name, 0); return PyBytes_FromStringAndSize(self->x509_name->bytes->data, self->x509_name->bytes->length); } static char crypto_X509Name_get_components_doc[] = "\n\ Returns the split-up components of this name.\n\ \n\ @return: List of tuples (name, value).\n\ "; static PyObject * crypto_X509Name_get_components(crypto_X509NameObj *self, PyObject *args) { int n, i; X509_NAME *name = self->x509_name; PyObject *list; if (!PyArg_ParseTuple(args, ":get_components")) return NULL; n = X509_NAME_entry_count(name); list = PyList_New(n); for (i = 0; i < n; i++) { X509_NAME_ENTRY *ent; ASN1_OBJECT *fname; ASN1_STRING *fval; int nid; int l; unsigned char *str; PyObject *tuple; ent = X509_NAME_get_entry(name, i); fname = X509_NAME_ENTRY_get_object(ent); fval = X509_NAME_ENTRY_get_data(ent); l = ASN1_STRING_length(fval); str = ASN1_STRING_data(fval); nid = OBJ_obj2nid(fname); /* printf("fname is %s len=%d str=%s\n", OBJ_nid2sn(nid), l, str); */ tuple = PyTuple_New(2); PyTuple_SetItem(tuple, 0, PyBytes_FromString(OBJ_nid2sn(nid))); PyTuple_SetItem(tuple, 1, PyBytes_FromStringAndSize((char *)str, l)); PyList_SetItem(list, i, tuple); } return list; } /* * Call the visitproc on all contained objects. * * Arguments: self - The Connection object * visit - Function to call * arg - Extra argument to visit * Returns: 0 if all goes well, otherwise the return code from the first * call that gave non-zero result. */ static int crypto_X509Name_traverse(crypto_X509NameObj *self, visitproc visit, void *arg) { int ret = 0; if (ret == 0 && self->parent_cert != NULL) ret = visit(self->parent_cert, arg); return ret; } /* * Decref all contained objects and zero the pointers. * * Arguments: self - The Connection object * Returns: Always 0. */ static int crypto_X509Name_clear(crypto_X509NameObj *self) { Py_XDECREF(self->parent_cert); self->parent_cert = NULL; return 0; } /* * Deallocate the memory used by the X509Name object * * Arguments: self - The X509Name object * Returns: None */ static void crypto_X509Name_dealloc(crypto_X509NameObj *self) { PyObject_GC_UnTrack(self); /* Sometimes we don't have to dealloc this */ if (self->dealloc) X509_NAME_free(self->x509_name); crypto_X509Name_clear(self); PyObject_GC_Del(self); } /* * ADD_METHOD(name) expands to a correct PyMethodDef declaration * { 'name', (PyCFunction)crypto_X509_name, METH_VARARGS } * for convenience */ #define ADD_METHOD(name) \ { #name, (PyCFunction)crypto_X509Name_##name, METH_VARARGS, crypto_X509Name_##name##_doc } static PyMethodDef crypto_X509Name_methods[] = { ADD_METHOD(hash), ADD_METHOD(der), ADD_METHOD(get_components), { NULL, NULL } }; #undef ADD_METHOD PyTypeObject crypto_X509Name_Type = { PyOpenSSL_HEAD_INIT(&PyType_Type, 0) "X509Name", sizeof(crypto_X509NameObj), 0, (destructor)crypto_X509Name_dealloc, NULL, /* print */ NULL, /* getattr */ NULL, /* setattr */ NULL, /* reserved */ (reprfunc)crypto_X509Name_repr, NULL, /* as_number */ NULL, /* as_sequence */ NULL, /* as_mapping */ NULL, /* hash */ NULL, /* call */ NULL, /* str */ (getattrofunc)crypto_X509Name_getattro, /* getattro */ (setattrofunc)crypto_X509Name_setattro, /* setattro */ NULL, /* as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ crypto_X509Name_doc, /* tp_doc */ (traverseproc)crypto_X509Name_traverse, /* tp_traverse */ (inquiry)crypto_X509Name_clear, /* tp_clear */ crypto_X509Name_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ NULL, /* tp_iter */ NULL, /* tp_iternext */ crypto_X509Name_methods, /* tp_methods */ NULL, /* tp_members */ NULL, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ NULL, /* tp_descr_get */ NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ NULL, /* tp_init */ NULL, /* tp_alloc */ crypto_X509Name_new, /* tp_new */ }; /* * Initialize the X509Name part of the crypto module * * Arguments: module - The crypto module * Returns: None */ int init_crypto_x509name(PyObject *module) { if (PyType_Ready(&crypto_X509Name_Type) < 0) { return 0; } /* PyModule_AddObject steals a reference. */ Py_INCREF((PyObject *)&crypto_X509Name_Type); if (PyModule_AddObject(module, "X509Name", (PyObject *)&crypto_X509Name_Type) != 0) { return 0; } /* PyModule_AddObject steals a reference. */ Py_INCREF((PyObject *)&crypto_X509Name_Type); if (PyModule_AddObject(module, "X509NameType", (PyObject *)&crypto_X509Name_Type) != 0) { return 0; } return 1; } pyOpenSSL-0.13/OpenSSL/crypto/x509name.h0000644000214500021450000000132111630175105017555 0ustar bb-slavebb-slave/* * x509name.h * * Copyright (C) AB Strakt * See LICENSE for details. * * Export X.509 name functions and data structures. * See the file RATIONALE for a short explanation of why this module was written. * * Reviewed 2001-07-23 * */ #ifndef PyOpenSSL_crypto_X509NAME_H_ #define PyOpenSSL_crypto_X509NAME_H_ #include #include extern int init_crypto_x509name (PyObject *); extern PyTypeObject crypto_X509Name_Type; #define crypto_X509Name_Check(v) ((v)->ob_type == &crypto_X509Name_Type) typedef struct { PyObject_HEAD X509_NAME *x509_name; int dealloc; PyObject *parent_cert; } crypto_X509NameObj; #endif pyOpenSSL-0.13/OpenSSL/crypto/x509req.c0000644000214500021450000002424011630175105017424 0ustar bb-slavebb-slave/* * x509req.c * * Copyright (C) AB Strakt * Copyright (C) Jean-Paul Calderone * See LICENSE for details. * * X.509 Request handling, mostly thin wrapping. * See the file RATIONALE for a short explanation of why this module was written. */ #include #define crypto_MODULE #include "crypto.h" static char crypto_X509Req_get_subject_doc[] = "\n\ Create an X509Name object for the subject of the certificate request\n\ \n\ @return: An X509Name object\n\ "; static PyObject * crypto_X509Req_get_subject(crypto_X509ReqObj *self, PyObject *args) { crypto_X509NameObj *crypto_X509Name_New(X509_NAME *, int); X509_NAME *name; crypto_X509NameObj* pyname; if (!PyArg_ParseTuple(args, ":get_subject")) return NULL; if ((name = X509_REQ_get_subject_name(self->x509_req)) == NULL) { exception_from_error_queue(crypto_Error); return NULL; } if ((pyname = crypto_X509Name_New(name, 0)) != NULL) { pyname->parent_cert = (PyObject *)self; Py_INCREF(self); } return (PyObject *)pyname; } static char crypto_X509Req_get_pubkey_doc[] = "\n\ Get the public key from the certificate request\n\ \n\ @return: The public key\n\ "; static PyObject * crypto_X509Req_get_pubkey(crypto_X509ReqObj *self, PyObject *args) { crypto_PKeyObj *crypto_PKey_New(EVP_PKEY *, int); EVP_PKEY *pkey; crypto_PKeyObj *py_pkey; if (!PyArg_ParseTuple(args, ":get_pubkey")) return NULL; if ((pkey = X509_REQ_get_pubkey(self->x509_req)) == NULL) { exception_from_error_queue(crypto_Error); return NULL; } py_pkey = crypto_PKey_New(pkey, 1); if (py_pkey != NULL) { py_pkey->only_public = 1; } return (PyObject *)py_pkey; } static char crypto_X509Req_set_pubkey_doc[] = "\n\ Set the public key of the certificate request\n\ \n\ @param pkey: The public key to use\n\ @return: None\n\ "; static PyObject * crypto_X509Req_set_pubkey(crypto_X509ReqObj *self, PyObject *args) { crypto_PKeyObj *pkey; if (!PyArg_ParseTuple(args, "O!:set_pubkey", &crypto_PKey_Type, &pkey)) return NULL; if (!X509_REQ_set_pubkey(self->x509_req, pkey->pkey)) { exception_from_error_queue(crypto_Error); return NULL; } Py_INCREF(Py_None); return Py_None; } static char crypto_X509Req_sign_doc[] = "\n\ Sign the certificate request using the supplied key and digest\n\ \n\ @param pkey: The key to sign with\n\ @param digest: The message digest to use\n\ @return: None\n\ "; static PyObject * crypto_X509Req_sign(crypto_X509ReqObj *self, PyObject *args) { crypto_PKeyObj *pkey; char *digest_name; const EVP_MD *digest; if (!PyArg_ParseTuple(args, "O!s:sign", &crypto_PKey_Type, &pkey, &digest_name)) return NULL; if (pkey->only_public) { PyErr_SetString(PyExc_ValueError, "Key has only public part"); return NULL; } if (!pkey->initialized) { PyErr_SetString(PyExc_ValueError, "Key is uninitialized"); return NULL; } if ((digest = EVP_get_digestbyname(digest_name)) == NULL) { PyErr_SetString(PyExc_ValueError, "No such digest method"); return NULL; } if (!X509_REQ_sign(self->x509_req, pkey->pkey, digest)) { exception_from_error_queue(crypto_Error); return NULL; } Py_INCREF(Py_None); return Py_None; } static char crypto_X509Req_verify_doc[] = "\n\ Verifies a certificate request using the supplied public key\n\ \n\ @param key: a public key\n\ @return: True if the signature is correct.\n\ @raise OpenSSL.crypto.Error: If the signature is invalid or there is a\n\ problem verifying the signature.\n\ "; PyObject * crypto_X509Req_verify(crypto_X509ReqObj *self, PyObject *args) { PyObject *obj; crypto_PKeyObj *key; int answer; if (!PyArg_ParseTuple(args, "O!:verify", &crypto_PKey_Type, &obj)) { return NULL; } key = (crypto_PKeyObj *)obj; if ((answer = X509_REQ_verify(self->x509_req, key->pkey)) <= 0) { exception_from_error_queue(crypto_Error); return NULL; } return PyLong_FromLong(answer); } static char crypto_X509Req_add_extensions_doc[] = "\n\ Add extensions to the request.\n\ \n\ @param extensions: a sequence of X509Extension objects\n\ @return: None\n\ "; static PyObject * crypto_X509Req_add_extensions(crypto_X509ReqObj *self, PyObject *args) { PyObject *extensions; crypto_X509ExtensionObj *ext; STACK_OF(X509_EXTENSION) *exts; int nr_of_extensions, i; if (!PyArg_ParseTuple(args, "O:add_extensions", &extensions)) return NULL; if (!PySequence_Check(extensions)) { PyErr_SetString(PyExc_TypeError, "Expected a sequence"); return NULL; } /* Make a STACK_OF(X509_EXTENSION) from sequence */ if ((exts = sk_X509_EXTENSION_new_null()) == NULL) { exception_from_error_queue(crypto_Error); return NULL; } /* Put the extensions in a stack */ nr_of_extensions = PySequence_Length(extensions); for (i = 0; i < nr_of_extensions; i++) { ext = (crypto_X509ExtensionObj *)PySequence_GetItem(extensions, i); if (!(crypto_X509Extension_Check(ext))) { PyErr_SetString(PyExc_ValueError, "One of the elements is not an X509Extension"); sk_X509_EXTENSION_free(exts); return NULL; } sk_X509_EXTENSION_push(exts, ext->x509_extension); } if (!X509_REQ_add_extensions(self->x509_req, exts)) { sk_X509_EXTENSION_free(exts); exception_from_error_queue(crypto_Error); return NULL; } sk_X509_EXTENSION_free(exts); Py_INCREF(Py_None); return Py_None; } static char crypto_X509Req_set_version_doc[] = "\n\ Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate\n\ request.\n\ \n\ @param version: The version number\n\ @return: None\n\ "; static PyObject * crypto_X509Req_set_version(crypto_X509ReqObj *self, PyObject *args) { long version; if (!PyArg_ParseTuple(args, "l:set_version", &version)) { return NULL; } if (!X509_REQ_set_version(self->x509_req, version)) { return NULL; } Py_INCREF(Py_None); return Py_None; } static char crypto_X509Req_get_version_doc[] = "\n\ Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate\n\ request.\n\ \n\ @return: an integer giving the value of the version subfield\n\ "; static PyObject * crypto_X509Req_get_version(crypto_X509ReqObj *self, PyObject *args) { long version; if (!PyArg_ParseTuple(args, ":get_version")) { return NULL; } version = X509_REQ_get_version(self->x509_req); return PyLong_FromLong(version); } /* * ADD_METHOD(name) expands to a correct PyMethodDef declaration * { 'name', (PyCFunction)crypto_X509Req_name, METH_VARARGS } * for convenience */ #define ADD_METHOD(name) \ { #name, (PyCFunction)crypto_X509Req_##name, METH_VARARGS, crypto_X509Req_##name##_doc } static PyMethodDef crypto_X509Req_methods[] = { ADD_METHOD(get_subject), ADD_METHOD(get_pubkey), ADD_METHOD(set_pubkey), ADD_METHOD(sign), ADD_METHOD(verify), ADD_METHOD(add_extensions), ADD_METHOD(set_version), ADD_METHOD(get_version), { NULL, NULL } }; #undef ADD_METHOD /* * Constructor for X509Req, never called by Python code directly * * Arguments: name - A "real" X509_REQ object * dealloc - Boolean value to specify whether the destructor should * free the "real" X509_REQ object * Returns: The newly created X509Req object */ crypto_X509ReqObj * crypto_X509Req_New(X509_REQ *req, int dealloc) { crypto_X509ReqObj *self; self = PyObject_New(crypto_X509ReqObj, &crypto_X509Req_Type); if (self == NULL) return NULL; self->x509_req = req; self->dealloc = dealloc; return self; } static char crypto_X509Req_doc[] = "\n\ X509Req() -> X509Req instance\n\ \n\ Create a new X509Req object.\n\ \n\ @return: The X509Req object\n\ "; static PyObject * crypto_X509Req_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) { if (!PyArg_ParseTuple(args, ":X509Req")) { return NULL; } return (PyObject *)crypto_X509Req_New(X509_REQ_new(), 1); } /* * Deallocate the memory used by the X509Req object * * Arguments: self - The X509Req object * Returns: None */ static void crypto_X509Req_dealloc(crypto_X509ReqObj *self) { /* Sometimes we don't have to dealloc this */ if (self->dealloc) X509_REQ_free(self->x509_req); PyObject_Del(self); } PyTypeObject crypto_X509Req_Type = { PyOpenSSL_HEAD_INIT(&PyType_Type, 0) "X509Req", sizeof(crypto_X509ReqObj), 0, (destructor)crypto_X509Req_dealloc, NULL, /* print */ NULL, /* getattr */ NULL, /* setattr */ NULL, /* compare */ NULL, /* repr */ NULL, /* as_number */ NULL, /* as_sequence */ NULL, /* as_mapping */ NULL, /* hash */ NULL, /* call */ NULL, /* str */ NULL, /* getattro */ NULL, /* setattro */ NULL, /* as_buffer */ Py_TPFLAGS_DEFAULT, crypto_X509Req_doc, /* doc */ NULL, /* traverse */ NULL, /* clear */ NULL, /* tp_richcompare */ 0, /* tp_weaklistoffset */ NULL, /* tp_iter */ NULL, /* tp_iternext */ crypto_X509Req_methods, /* tp_methods */ NULL, /* tp_members */ NULL, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ NULL, /* tp_descr_get */ NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ NULL, /* tp_init */ NULL, /* tp_alloc */ crypto_X509Req_new, /* tp_new */ }; /* * Initialize the X509Req part of the crypto module * * Arguments: module - The crypto module * Returns: None */ int init_crypto_x509req(PyObject *module) { if (PyType_Ready(&crypto_X509Req_Type) < 0) { return 0; } /* PyModule_AddObject steals a reference. */ Py_INCREF((PyObject *)&crypto_X509Req_Type); if (PyModule_AddObject(module, "X509Req", (PyObject *)&crypto_X509Req_Type) != 0) { return 0; } /* PyModule_AddObject steals a reference. */ Py_INCREF((PyObject *)&crypto_X509Req_Type); if (PyModule_AddObject(module, "X509ReqType", (PyObject *)&crypto_X509Req_Type) != 0) { return 0; } return 1; } pyOpenSSL-0.13/OpenSSL/crypto/x509req.h0000644000214500021450000000120211630175105017422 0ustar bb-slavebb-slave/* * x509req.h * * Copyright (C) AB Strakt * See LICENSE for details. * * Export X509 request functions and data structures. * See the file RATIONALE for a short explanation of why this module was written. * */ #ifndef PyOpenSSL_SSL_X509REQ_H_ #define PyOpenSSL_SSL_X509REQ_H_ #include #include extern int init_crypto_x509req (PyObject *); extern PyTypeObject crypto_X509Req_Type; #define crypto_X509Req_Check(v) ((v)->ob_type == &crypto_X509Req_Type) typedef struct { PyObject_HEAD X509_REQ *x509_req; int dealloc; } crypto_X509ReqObj; #endif pyOpenSSL-0.13/OpenSSL/crypto/x509store.c0000644000214500021450000000655411630175105020001 0ustar bb-slavebb-slave/* * x509store.c * * Copyright (C) AB Strakt * See LICENSE for details. * * X.509 Store handling, mostly thin wrapping. * See the file RATIONALE for a short explanation of why this module was written. */ #include #define crypto_MODULE #include "crypto.h" static char crypto_X509Store_add_cert_doc[] = "\n\ Add a certificate\n\ \n\ @param cert: The certificate to add\n\ @return: None\n\ "; static PyObject * crypto_X509Store_add_cert(crypto_X509StoreObj *self, PyObject *args) { crypto_X509Obj *cert; if (!PyArg_ParseTuple(args, "O!:add_cert", &crypto_X509_Type, &cert)) return NULL; if (!X509_STORE_add_cert(self->x509_store, cert->x509)) { exception_from_error_queue(crypto_Error); return NULL; } Py_INCREF(Py_None); return Py_None; } /* * ADD_METHOD(name) expands to a correct PyMethodDef declaration * { 'name', (PyCFunction)crypto_X509Store_name, METH_VARARGS } * for convenience */ #define ADD_METHOD(name) \ { #name, (PyCFunction)crypto_X509Store_##name, METH_VARARGS, crypto_X509Store_##name##_doc } static PyMethodDef crypto_X509Store_methods[] = { ADD_METHOD(add_cert), { NULL, NULL } }; #undef ADD_METHOD /* * Constructor for X509Store, never called by Python code directly * * Arguments: name - A "real" X509_STORE object * dealloc - Boolean value to specify whether the destructor should * free the "real" X509_STORE object * Returns: The newly created X509Store object */ crypto_X509StoreObj * crypto_X509Store_New(X509_STORE *store, int dealloc) { crypto_X509StoreObj *self; self = PyObject_New(crypto_X509StoreObj, &crypto_X509Store_Type); if (self == NULL) return NULL; self->x509_store = store; self->dealloc = dealloc; return self; } /* * Deallocate the memory used by the X509Store object * * Arguments: self - The X509Store object * Returns: None */ static void crypto_X509Store_dealloc(crypto_X509StoreObj *self) { /* Sometimes we don't have to dealloc this */ if (self->dealloc) X509_STORE_free(self->x509_store); PyObject_Del(self); } PyTypeObject crypto_X509Store_Type = { PyOpenSSL_HEAD_INIT(&PyType_Type, 0) "X509Store", sizeof(crypto_X509StoreObj), 0, (destructor)crypto_X509Store_dealloc, NULL, /* print */ NULL, /* getattr */ NULL, /* setattr */ NULL, /* compare */ NULL, /* repr */ NULL, /* as_number */ NULL, /* as_sequence */ NULL, /* as_mapping */ NULL, /* hash */ NULL, /* call */ NULL, /* str */ NULL, /* getattro */ NULL, /* setattro */ NULL, /* as_buffer */ Py_TPFLAGS_DEFAULT, NULL, /* doc */ NULL, /* traverse */ NULL, /* clear */ NULL, /* tp_richcompare */ 0, /* tp_weaklistoffset */ NULL, /* tp_iter */ NULL, /* tp_iternext */ crypto_X509Store_methods, /* tp_methods */ }; /* * Initialize the X509Store part of the crypto module * * Arguments: module - The crypto module * Returns: None */ int init_crypto_x509store(PyObject *module) { if (PyType_Ready(&crypto_X509Store_Type) < 0) { return 0; } /* PyModule_AddObject steals a reference. */ Py_INCREF((PyObject *)&crypto_X509Store_Type); if (PyModule_AddObject(module, "X509StoreType", (PyObject *)&crypto_X509Store_Type) != 0) { return 0; } return 1; } pyOpenSSL-0.13/OpenSSL/crypto/x509store.h0000644000214500021450000000122511630175105017774 0ustar bb-slavebb-slave/* * x509store.h * * Copyright (C) AB Strakt * See LICENSE for details. * * Export X509 store functions and data structures. * See the file RATIONALE for a short explanation of why this module was written. * */ #ifndef PyOpenSSL_SSL_X509STORE_H_ #define PyOpenSSL_SSL_X509STORE_H_ #include #include extern int init_crypto_x509store (PyObject *); extern PyTypeObject crypto_X509Store_Type; #define crypto_X509Store_Check(v) ((v)->ob_type == &crypto_X509Store_Type) typedef struct { PyObject_HEAD X509_STORE *x509_store; int dealloc; } crypto_X509StoreObj; #endif pyOpenSSL-0.13/OpenSSL/rand/0000755000214500021450000000000011630175113015444 5ustar bb-slavebb-slavepyOpenSSL-0.13/OpenSSL/rand/rand.c0000644000214500021450000001600611630175105016540 0ustar bb-slavebb-slave/* * rand.c * * Copyright (C) AB Strakt * See LICENSE file for details. * * PRNG management routines, thin wrappers. * See the file RATIONALE for a short explanation of why this module was written. * */ #include /* * In order to get the RAND_screen definition from the rand.h * WIN32 or WINDOWS needs to be defined, otherwise we get a * warning. */ #ifdef MS_WINDOWS # ifndef WIN32 # define WIN32 # endif #endif #include #include "../util.h" PyObject *rand_Error; static char rand_doc[] = "\n\ PRNG management routines, thin wrappers.\n\ See the file RATIONALE for a short explanation of why this module was written.\n\ "; static char rand_add_doc[] = "\n\ Add data with a given entropy to the PRNG\n\ \n\ @param buffer: Buffer with random data\n\ @param entropy: The entropy (in bytes) measurement of the buffer\n\ @return: None\n\ "; static PyObject * rand_add(PyObject *spam, PyObject *args) { char *buf; int size; double entropy; if (!PyArg_ParseTuple(args, BYTESTRING_FMT "#d:add", &buf, &size, &entropy)) return NULL; RAND_add(buf, size, entropy); Py_INCREF(Py_None); return Py_None; } static char rand_seed_doc[] = "\n\ Alias for rand_add, with entropy equal to length\n\ \n\ @param buffer: Buffer with random data\n\ @return: None\n\ "; static PyObject * rand_seed(PyObject *spam, PyObject *args) { char *buf; int size; if (!PyArg_ParseTuple(args, BYTESTRING_FMT "#:seed", &buf, &size)) return NULL; RAND_seed(buf, size); Py_INCREF(Py_None); return Py_None; } static char rand_status_doc[] = "\n\ Retrieve the status of the PRNG\n\ \n\ @return: True if the PRNG is seeded enough, false otherwise\n\ "; static PyObject * rand_status(PyObject *spam, PyObject *args) { if (!PyArg_ParseTuple(args, ":status")) return NULL; return PyLong_FromLong((long)RAND_status()); } #ifdef MS_WINDOWS static char rand_screen_doc[] = "\n\ Add the current contents of the screen to the PRNG state. Availability:\n\ Windows.\n\ \n\ @return: None\n\ "; static PyObject * rand_screen(PyObject *spam, PyObject *args) { if (!PyArg_ParseTuple(args, ":screen")) return NULL; RAND_screen(); Py_INCREF(Py_None); return Py_None; } #endif static char rand_egd_doc[] = "\n\ Query an entropy gathering daemon (EGD) for random data and add it to the\n\ PRNG. I haven't found any problems when the socket is missing, the function\n\ just returns 0.\n\ \n\ @param path: The path to the EGD socket\n\ @param bytes: (optional) The number of bytes to read, default is 255\n\ @returns: The number of bytes read (NB: a value of 0 isn't necessarily an\n\ error, check rand.status())\n\ "; static PyObject * rand_egd(PyObject *spam, PyObject *args) { char *path; int bytes = 255; if (!PyArg_ParseTuple(args, "s|i:egd", &path, &bytes)) return NULL; return PyLong_FromLong((long)RAND_egd_bytes(path, bytes)); } static char rand_cleanup_doc[] = "\n\ Erase the memory used by the PRNG.\n\ \n\ @return: None\n\ "; static PyObject * rand_cleanup(PyObject *spam, PyObject *args) { if (!PyArg_ParseTuple(args, ":cleanup")) return NULL; RAND_cleanup(); Py_INCREF(Py_None); return Py_None; } static char rand_load_file_doc[] = "\n\ Seed the PRNG with data from a file\n\ \n\ @param filename: The file to read data from\n\ @param maxbytes: (optional) The number of bytes to read, default is\n\ to read the entire file\n\ @return: The number of bytes read\n\ "; static PyObject * rand_load_file(PyObject *spam, PyObject *args) { char *filename; int maxbytes = -1; if (!PyArg_ParseTuple(args, "s|i:load_file", &filename, &maxbytes)) return NULL; return PyLong_FromLong((long)RAND_load_file(filename, maxbytes)); } static char rand_write_file_doc[] = "\n\ Save PRNG state to a file\n\ \n\ @param filename: The file to write data to\n\ @return: The number of bytes written\n\ "; static PyObject * rand_write_file(PyObject *spam, PyObject *args) { char *filename; if (!PyArg_ParseTuple(args, "s:write_file", &filename)) return NULL; return PyLong_FromLong((long)RAND_write_file(filename)); } static char rand_bytes_doc[] = "\n\ Get some randomm bytes as a string.\n\ \n\ @param num_bytes: The number of bytes to fetch\n\ @return: A string of random bytes\n\ "; #if PY_VERSION_HEX < 0x02050000 #define Py_ssize_t int #define PY_SSIZE_FMT "i" #else #define PY_SSIZE_FMT "n" #endif static PyObject * rand_bytes(PyObject *spam, PyObject *args, PyObject *keywds) { Py_ssize_t num_bytes; static char *kwlist[] = {"num_bytes", NULL}; char *buf; unsigned int rc; PyObject *obj = NULL; if (!PyArg_ParseTupleAndKeywords( args, keywds, PY_SSIZE_FMT ":bytes", kwlist, &num_bytes)) { return NULL; } if(num_bytes < 0) { PyErr_SetString(PyExc_ValueError, "num_bytes must not be negative"); return NULL; } buf = malloc(num_bytes); if (buf == NULL) /* out of memory */ return NULL; rc = RAND_bytes((unsigned char *) buf, num_bytes); if(rc != 1) { /* if unsuccessful */ exception_from_error_queue(rand_Error); goto done; } obj = PyBytes_FromStringAndSize(buf, (unsigned) num_bytes); done: free(buf); return obj; } /* Methods in the OpenSSL.rand module */ static PyMethodDef rand_methods[] = { { "add", (PyCFunction)rand_add, METH_VARARGS, rand_add_doc }, { "seed", (PyCFunction)rand_seed, METH_VARARGS, rand_seed_doc }, { "status", (PyCFunction)rand_status, METH_VARARGS, rand_status_doc }, #ifdef MS_WINDOWS { "screen", (PyCFunction)rand_screen, METH_VARARGS, rand_screen_doc }, #endif { "egd", (PyCFunction)rand_egd, METH_VARARGS, rand_egd_doc }, { "cleanup", (PyCFunction)rand_cleanup, METH_VARARGS, rand_cleanup_doc }, { "load_file", (PyCFunction)rand_load_file, METH_VARARGS, rand_load_file_doc }, { "write_file",(PyCFunction)rand_write_file, METH_VARARGS, rand_write_file_doc }, { "bytes", (PyCFunction)rand_bytes, METH_VARARGS|METH_KEYWORDS, rand_bytes_doc }, { NULL, NULL } }; #ifdef PY3 static struct PyModuleDef randmodule = { PyModuleDef_HEAD_INIT, "rand", rand_doc, -1, rand_methods }; #endif /* * Initialize the rand sub module * * Arguments: None * Returns: None */ PyOpenSSL_MODINIT(rand) { PyObject *module; #ifdef PY3 module = PyModule_Create(&randmodule); #else module = Py_InitModule3("rand", rand_methods, rand_doc); #endif if (module == NULL) { PyOpenSSL_MODRETURN(NULL); } rand_Error = PyErr_NewException("OpenSSL.rand.Error", NULL, NULL); if (rand_Error == NULL) { goto error; } /* PyModule_AddObject steals a reference. */ Py_INCREF(rand_Error); if (PyModule_AddObject(module, "Error", rand_Error) != 0) { goto error; } ERR_load_RAND_strings(); PyOpenSSL_MODRETURN(module); error: PyOpenSSL_MODRETURN(NULL); ; } pyOpenSSL-0.13/OpenSSL/ssl/0000755000214500021450000000000011630175113015321 5ustar bb-slavebb-slavepyOpenSSL-0.13/OpenSSL/ssl/connection.c0000755000214500021450000012452111630175105017635 0ustar bb-slavebb-slave/* * connection.c * * Copyright (C) AB Strakt * Copyright (C) Jean-Paul Calderone * See LICENSE for details. * * SSL Connection objects and methods. * See the file RATIONALE for a short explanation of why this module was written. * * Reviewed 2001-07-23 */ #include #ifndef MS_WINDOWS # include # include # if !(defined(__BEOS__) || defined(__CYGWIN__)) # include # endif #else # include # include #endif #define SSL_MODULE #include #include #include "ssl.h" /** * If we are on UNIX, fine, just use PyErr_SetFromErrno. If we are on Windows, * apply some black winsock voodoo. This is basically just copied from Python's * socketmodule.c * * Arguments: None * Returns: None */ static void syscall_from_errno(void) { #ifdef MS_WINDOWS int errnum = WSAGetLastError(); if (errnum) { static struct { int num; const char *msg; } *msgp, msgs[] = { { WSAEINTR, "Interrupted system call" }, { WSAEBADF, "Bad file descriptor" }, { WSAEACCES, "Permission denied" }, { WSAEFAULT, "Bad address" }, { WSAEINVAL, "Invalid argument" }, { WSAEMFILE, "Too many open files" }, { WSAEWOULDBLOCK, "The socket operation could not complete " "without blocking" }, { WSAEINPROGRESS, "Operation now in progress" }, { WSAEALREADY, "Operation already in progress" }, { WSAENOTSOCK, "Socket operation on non-socket" }, { WSAEDESTADDRREQ, "Destination address required" }, { WSAEMSGSIZE, "Message too long" }, { WSAEPROTOTYPE, "Protocol wrong type for socket" }, { WSAENOPROTOOPT, "Protocol not available" }, { WSAEPROTONOSUPPORT, "Protocol not supported" }, { WSAESOCKTNOSUPPORT, "Socket type not supported" }, { WSAEOPNOTSUPP, "Operation not supported" }, { WSAEPFNOSUPPORT, "Protocol family not supported" }, { WSAEAFNOSUPPORT, "Address family not supported" }, { WSAEADDRINUSE, "Address already in use" }, { WSAEADDRNOTAVAIL, "Can't assign requested address" }, { WSAENETDOWN, "Network is down" }, { WSAENETUNREACH, "Network is unreachable" }, { WSAENETRESET, "Network dropped connection on reset" }, { WSAECONNABORTED, "Software caused connection abort" }, { WSAECONNRESET, "Connection reset by peer" }, { WSAENOBUFS, "No buffer space available" }, { WSAEISCONN, "Socket is already connected" }, { WSAENOTCONN, "Socket is not connected" }, { WSAESHUTDOWN, "Can't send after socket shutdown" }, { WSAETOOMANYREFS, "Too many references: can't splice" }, { WSAETIMEDOUT, "Operation timed out" }, { WSAECONNREFUSED, "Connection refused" }, { WSAELOOP, "Too many levels of symbolic links" }, { WSAENAMETOOLONG, "File name too long" }, { WSAEHOSTDOWN, "Host is down" }, { WSAEHOSTUNREACH, "No route to host" }, { WSAENOTEMPTY, "Directory not empty" }, { WSAEPROCLIM, "Too many processes" }, { WSAEUSERS, "Too many users" }, { WSAEDQUOT, "Disc quota exceeded" }, { WSAESTALE, "Stale NFS file handle" }, { WSAEREMOTE, "Too many levels of remote in path" }, { WSASYSNOTREADY, "Network subsystem is unvailable" }, { WSAVERNOTSUPPORTED, "WinSock version is not supported" }, { WSANOTINITIALISED, "Successful WSAStartup() not yet performed" }, { WSAEDISCON, "Graceful shutdown in progress" }, /* Resolver errors */ { WSAHOST_NOT_FOUND, "No such host is known" }, { WSATRY_AGAIN, "Host not found, or server failed" }, { WSANO_RECOVERY, "Unexpected server error encountered" }, { WSANO_DATA, "Valid name without requested data" }, { WSANO_ADDRESS, "No address, look for MX record" }, { 0, NULL } }; PyObject *v; const char *msg = "winsock error"; for (msgp = msgs; msgp->msg; msgp++) { if (errnum == msgp->num) { msg = msgp->msg; break; } } v = Py_BuildValue("(is)", errnum, msg); if (v != NULL) { PyErr_SetObject(ssl_SysCallError, v); Py_DECREF(v); } return; } #else PyErr_SetFromErrno(ssl_SysCallError); #endif } /* * Handle errors raised by BIO functions. * * Arguments: bio - The BIO object * ret - The return value of the BIO_ function. * Returns: None, the calling function should return NULL; */ static void handle_bio_errors(BIO* bio, int ret) { if (BIO_should_retry(bio)) { if (BIO_should_read(bio)) { PyErr_SetNone(ssl_WantReadError); } else if (BIO_should_write(bio)) { PyErr_SetNone(ssl_WantWriteError); } else if (BIO_should_io_special(bio)) { /* * It's somewhat unclear what this means. From the OpenSSL source, * it seems like it should not be triggered by the memory BIO, so * for the time being, this case shouldn't come up. The SSL BIO * (which I think should be named the socket BIO) may trigger this * case if its socket is not yet connected or it is busy doing * something related to x509. */ PyErr_SetString(PyExc_ValueError, "BIO_should_io_special"); } else { /* * I hope this is dead code. The BIO documentation suggests that * one of the above three checks should always be true. */ PyErr_SetString(PyExc_ValueError, "unknown bio failure"); } } else { /* * If we aren't to retry, it's really an error, so fall back to the * normal error reporting code. However, the BIO interface does not * specify a uniform error reporting mechanism. We can only hope that * the code which triggered the error also kindly pushed something onto * the error stack. */ exception_from_error_queue(ssl_Error); } } /* * Handle errors raised by SSL I/O functions. NOTE: Not SSL_shutdown ;) * * Arguments: ssl - The SSL object * err - The return code from SSL_get_error * ret - The return code from the SSL I/O function * Returns: None, the calling function should return NULL */ static void handle_ssl_errors(SSL *ssl, int err, int ret) { switch (err) { /* * Strange as it may seem, ZeroReturn is not an error per se. It means * that the SSL Connection has been closed correctly (note, not the * transport layer!), i.e. closure alerts have been exchanged. This is * an exception since * + There's an SSL "error" code for it * + You have to deal with it in any case, close the transport layer * etc */ case SSL_ERROR_ZERO_RETURN: PyErr_SetNone(ssl_ZeroReturnError); break; /* * The WantXYZ exceptions don't mean that there's an error, just that * nothing could be read/written just now, maybe because the transport * layer would block on the operation, or that there's not enough data * available to fill an entire SSL record. */ case SSL_ERROR_WANT_READ: PyErr_SetNone(ssl_WantReadError); break; case SSL_ERROR_WANT_WRITE: PyErr_SetNone(ssl_WantWriteError); break; case SSL_ERROR_WANT_X509_LOOKUP: PyErr_SetNone(ssl_WantX509LookupError); break; case SSL_ERROR_SYSCALL: if (ERR_peek_error() == 0) { if (ret < 0) { syscall_from_errno(); } else { PyObject *v; v = Py_BuildValue("(is)", -1, "Unexpected EOF"); if (v != NULL) { PyErr_SetObject(ssl_SysCallError, v); Py_DECREF(v); } } break; } /* NOTE: Fall-through here, we don't want to duplicate code, right? */ case SSL_ERROR_SSL: ; default: exception_from_error_queue(ssl_Error); break; } } /* * Here be member methods of the Connection "class" */ static char ssl_Connection_get_context_doc[] = "\n\ Get session context\n\ \n\ @return: A Context object\n\ "; static PyObject * ssl_Connection_get_context(ssl_ConnectionObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":get_context")) { return NULL; } Py_INCREF(self->context); return (PyObject *)self->context; } static char ssl_Connection_set_context_doc[] = "\n\ Switch this connection to a new session context\n\ \n\ @param context: A L{Context} instance giving the new session context to use.\n\ \n\ "; static PyObject * ssl_Connection_set_context(ssl_ConnectionObj *self, PyObject *args) { ssl_ContextObj *ctx; ssl_ContextObj *old; if (!PyArg_ParseTuple(args, "O!:set_context", &ssl_Context_Type, &ctx)) { return NULL; } /* This Connection will hold on to this context now. Make sure it stays * alive. */ Py_INCREF(ctx); /* XXX The unit tests don't actually verify that this call is made. * They're satisfied if self->context gets updated. */ SSL_set_SSL_CTX(self->ssl, ctx->ctx); /* Swap the old out and the new in. */ old = self->context; self->context = ctx; /* XXX The unit tests don't verify that this reference is dropped. */ Py_DECREF(old); Py_INCREF(Py_None); return Py_None; } static char ssl_Connection_get_servername_doc[] = "\n\ Retrieve the servername extension value if provided in the client hello\n\ message, or None if there wasn't one.\n\ \n\ @return: A byte string giving the server name or C{None}.\n\ \n\ "; static PyObject * ssl_Connection_get_servername(ssl_ConnectionObj *self, PyObject *args) { int type = TLSEXT_NAMETYPE_host_name; const char *name; if (!PyArg_ParseTuple(args, ":get_servername")) { return NULL; } name = SSL_get_servername(self->ssl, type); if (name == NULL) { Py_INCREF(Py_None); return Py_None; } else { return PyBytes_FromString(name); } } static char ssl_Connection_set_tlsext_host_name_doc[] = "\n\ Set the value of the servername extension to send in the client hello.\n\ \n\ @param name: A byte string giving the name.\n\ \n\ "; static PyObject * ssl_Connection_set_tlsext_host_name(ssl_ConnectionObj *self, PyObject *args) { char *buf; if (!PyArg_ParseTuple(args, BYTESTRING_FMT ":set_tlsext_host_name", &buf)) { return NULL; } /* XXX I guess this can fail sometimes? */ SSL_set_tlsext_host_name(self->ssl, buf); Py_INCREF(Py_None); return Py_None; } static char ssl_Connection_pending_doc[] = "\n\ Get the number of bytes that can be safely read from the connection\n\ \n\ @return: The number of bytes available in the receive buffer.\n\ "; static PyObject * ssl_Connection_pending(ssl_ConnectionObj *self, PyObject *args) { int ret; if (!PyArg_ParseTuple(args, ":pending")) { return NULL; } ret = SSL_pending(self->ssl); return PyLong_FromLong((long)ret); } static char ssl_Connection_bio_write_doc[] = "\n\ When using non-socket connections this function sends\n\ \"dirty\" data that would have traveled in on the network.\n\ \n\ @param buf: The string to put into the memory BIO.\n\ @return: The number of bytes written\n\ "; static PyObject * ssl_Connection_bio_write(ssl_ConnectionObj *self, PyObject *args) { char *buf; int len, ret; if (self->into_ssl == NULL) { PyErr_SetString(PyExc_TypeError, "Connection sock was not None"); return NULL; } if (!PyArg_ParseTuple(args, "s#|i:bio_write", &buf, &len)) return NULL; ret = BIO_write(self->into_ssl, buf, len); if (PyErr_Occurred()) { flush_error_queue(); return NULL; } if (ret <= 0) { /* * There was a problem with the BIO_write of some sort. */ handle_bio_errors(self->into_ssl, ret); return NULL; } return PyLong_FromLong((long)ret); } static char ssl_Connection_send_doc[] = "\n\ Send data on the connection. NOTE: If you get one of the WantRead,\n\ WantWrite or WantX509Lookup exceptions on this, you have to call the\n\ method again with the SAME buffer.\n\ \n\ @param buf: The string to send\n\ @param flags: (optional) Included for compatibility with the socket\n\ API, the value is ignored\n\ @return: The number of bytes written\n\ "; static PyObject * ssl_Connection_send(ssl_ConnectionObj *self, PyObject *args) { int len, ret, err, flags; char *buf; #if PY_VERSION_HEX >= 0x02060000 Py_buffer pbuf; if (!PyArg_ParseTuple(args, "s*|i:send", &pbuf, &flags)) return NULL; buf = pbuf.buf; len = pbuf.len; #else if (!PyArg_ParseTuple(args, "s#|i:send", &buf, &len, &flags)) return NULL; #endif MY_BEGIN_ALLOW_THREADS(self->tstate) ret = SSL_write(self->ssl, buf, len); MY_END_ALLOW_THREADS(self->tstate) #if PY_VERSION_HEX >= 0x02060000 PyBuffer_Release(&pbuf); #endif if (PyErr_Occurred()) { flush_error_queue(); return NULL; } err = SSL_get_error(self->ssl, ret); if (err == SSL_ERROR_NONE) { return PyLong_FromLong((long)ret); } else { handle_ssl_errors(self->ssl, err, ret); return NULL; } } static char ssl_Connection_sendall_doc[] = "\n\ Send \"all\" data on the connection. This calls send() repeatedly until\n\ all data is sent. If an error occurs, it's impossible to tell how much data\n\ has been sent.\n\ \n\ @param buf: The string to send\n\ @param flags: (optional) Included for compatibility with the socket\n\ API, the value is ignored\n\ @return: The number of bytes written\n\ "; static PyObject * ssl_Connection_sendall(ssl_ConnectionObj *self, PyObject *args) { char *buf; int len, ret, err, flags; PyObject *pyret = Py_None; #if PY_VERSION_HEX >= 0x02060000 Py_buffer pbuf; if (!PyArg_ParseTuple(args, "s*|i:sendall", &pbuf, &flags)) return NULL; buf = pbuf.buf; len = pbuf.len; #else if (!PyArg_ParseTuple(args, "s#|i:sendall", &buf, &len, &flags)) return NULL; #endif do { MY_BEGIN_ALLOW_THREADS(self->tstate) ret = SSL_write(self->ssl, buf, len); MY_END_ALLOW_THREADS(self->tstate) if (PyErr_Occurred()) { flush_error_queue(); pyret = NULL; break; } err = SSL_get_error(self->ssl, ret); if (err == SSL_ERROR_NONE) { buf += ret; len -= ret; } else if (err == SSL_ERROR_SSL || err == SSL_ERROR_SYSCALL || err == SSL_ERROR_ZERO_RETURN) { handle_ssl_errors(self->ssl, err, ret); pyret = NULL; break; } } while (len > 0); #if PY_VERSION_HEX >= 0x02060000 PyBuffer_Release(&pbuf); #endif Py_XINCREF(pyret); return pyret; } static char ssl_Connection_recv_doc[] = "\n\ Receive data on the connection. NOTE: If you get one of the WantRead,\n\ WantWrite or WantX509Lookup exceptions on this, you have to call the\n\ method again with the SAME buffer.\n\ \n\ @param bufsiz: The maximum number of bytes to read\n\ @param flags: (optional) Included for compatibility with the socket\n\ API, the value is ignored\n\ @return: The string read from the Connection\n\ "; static PyObject * ssl_Connection_recv(ssl_ConnectionObj *self, PyObject *args) { int bufsiz, ret, err, flags; PyObject *buf; if (!PyArg_ParseTuple(args, "i|i:recv", &bufsiz, &flags)) return NULL; buf = PyBytes_FromStringAndSize(NULL, bufsiz); if (buf == NULL) return NULL; MY_BEGIN_ALLOW_THREADS(self->tstate) ret = SSL_read(self->ssl, PyBytes_AsString(buf), bufsiz); MY_END_ALLOW_THREADS(self->tstate) if (PyErr_Occurred()) { Py_DECREF(buf); flush_error_queue(); return NULL; } err = SSL_get_error(self->ssl, ret); if (err == SSL_ERROR_NONE) { if (ret != bufsiz && _PyBytes_Resize(&buf, ret) < 0) return NULL; return buf; } else { handle_ssl_errors(self->ssl, err, ret); Py_DECREF(buf); return NULL; } } static char ssl_Connection_bio_read_doc[] = "\n\ When using non-socket connections this function reads\n\ the \"dirty\" data that would have traveled away on the network.\n\ \n\ @param bufsiz: The maximum number of bytes to read\n\ @return: The string read.\n\ "; static PyObject * ssl_Connection_bio_read(ssl_ConnectionObj *self, PyObject *args) { int bufsiz, ret; PyObject *buf; if (self->from_ssl == NULL) { PyErr_SetString(PyExc_TypeError, "Connection sock was not None"); return NULL; } if (!PyArg_ParseTuple(args, "i:bio_read", &bufsiz)) return NULL; buf = PyBytes_FromStringAndSize(NULL, bufsiz); if (buf == NULL) return NULL; ret = BIO_read(self->from_ssl, PyBytes_AsString(buf), bufsiz); if (PyErr_Occurred()) { Py_DECREF(buf); flush_error_queue(); return NULL; } if (ret <= 0) { /* * There was a problem with the BIO_read of some sort. */ handle_bio_errors(self->from_ssl, ret); Py_DECREF(buf); return NULL; } /* * Shrink the string to match the number of bytes we actually read. */ if (ret != bufsiz && _PyBytes_Resize(&buf, ret) < 0) { Py_DECREF(buf); return NULL; } return buf; } static char ssl_Connection_renegotiate_doc[] = "\n\ Renegotiate the session\n\ \n\ @return: True if the renegotiation can be started, false otherwise\n\ "; static PyObject * ssl_Connection_renegotiate(ssl_ConnectionObj *self, PyObject *args) { int ret; if (!PyArg_ParseTuple(args, ":renegotiate")) { return NULL; } MY_BEGIN_ALLOW_THREADS(self->tstate); ret = SSL_renegotiate(self->ssl); MY_END_ALLOW_THREADS(self->tstate); if (PyErr_Occurred()) { flush_error_queue(); return NULL; } return PyLong_FromLong((long)ret); } static char ssl_Connection_do_handshake_doc[] = "\n\ Perform an SSL handshake (usually called after renegotiate() or one of\n\ set_*_state()). This can raise the same exceptions as send and recv.\n\ \n\ @return: None.\n\ "; static PyObject * ssl_Connection_do_handshake(ssl_ConnectionObj *self, PyObject *args) { int ret, err; if (!PyArg_ParseTuple(args, ":do_handshake")) return NULL; MY_BEGIN_ALLOW_THREADS(self->tstate); ret = SSL_do_handshake(self->ssl); MY_END_ALLOW_THREADS(self->tstate); if (PyErr_Occurred()) { flush_error_queue(); return NULL; } err = SSL_get_error(self->ssl, ret); if (err == SSL_ERROR_NONE) { Py_INCREF(Py_None); return Py_None; } else { handle_ssl_errors(self->ssl, err, ret); return NULL; } } #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x00907000L static char ssl_Connection_renegotiate_pending_doc[] = "\n\ Check if there's a renegotiation in progress, it will return false once\n\ a renegotiation is finished.\n\ \n\ @return: Whether there's a renegotiation in progress\n\ "; static PyObject * ssl_Connection_renegotiate_pending(ssl_ConnectionObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":renegotiate_pending")) return NULL; return PyLong_FromLong((long)SSL_renegotiate_pending(self->ssl)); } #endif static char ssl_Connection_total_renegotiations_doc[] = "\n\ Find out the total number of renegotiations.\n\ \n\ @return: The number of renegotiations.\n\ "; static PyObject * ssl_Connection_total_renegotiations(ssl_ConnectionObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":total_renegotiations")) return NULL; return PyLong_FromLong(SSL_total_renegotiations(self->ssl)); } static char ssl_Connection_set_accept_state_doc[] = "\n\ Set the connection to work in server mode. The handshake will be handled\n\ automatically by read/write.\n\ \n\ @return: None\n\ "; static PyObject * ssl_Connection_set_accept_state(ssl_ConnectionObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":set_accept_state")) return NULL; SSL_set_accept_state(self->ssl); Py_INCREF(Py_None); return Py_None; } static char ssl_Connection_set_connect_state_doc[] = "\n\ Set the connection to work in client mode. The handshake will be handled\n\ automatically by read/write.\n\ \n\ @return: None\n\ "; static PyObject * ssl_Connection_set_connect_state(ssl_ConnectionObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":set_connect_state")) return NULL; SSL_set_connect_state(self->ssl); Py_INCREF(Py_None); return Py_None; } static char ssl_Connection_connect_doc[] = "\n\ Connect to remote host and set up client-side SSL\n\ \n\ @param addr: A remote address\n\ @return: What the socket's connect method returns\n\ "; static PyObject * ssl_Connection_connect(ssl_ConnectionObj *self, PyObject *args) { PyObject *meth, *ret; if ((meth = PyObject_GetAttrString(self->socket, "connect")) == NULL) return NULL; SSL_set_connect_state(self->ssl); ret = PyEval_CallObject(meth, args); Py_DECREF(meth); if (ret == NULL) return NULL; return ret; } static char ssl_Connection_connect_ex_doc[] = "\n\ Connect to remote host and set up client-side SSL. Note that if the socket's\n\ connect_ex method doesn't return 0, SSL won't be initialized.\n\ \n\ @param addr: A remove address\n\ @return: What the socket's connect_ex method returns\n\ "; static PyObject * ssl_Connection_connect_ex(ssl_ConnectionObj *self, PyObject *args) { PyObject *meth, *ret; if ((meth = PyObject_GetAttrString(self->socket, "connect_ex")) == NULL) return NULL; SSL_set_connect_state(self->ssl); ret = PyEval_CallObject(meth, args); Py_DECREF(meth); return ret; } static char ssl_Connection_accept_doc[] = "\n\ Accept incoming connection and set up SSL on it\n\ \n\ @return: A (conn,addr) pair where conn is a Connection and addr is an\n\ address\n\ "; static PyObject * ssl_Connection_accept(ssl_ConnectionObj *self, PyObject *args) { PyObject *tuple, *socket, *address, *meth; ssl_ConnectionObj *conn; if ((meth = PyObject_GetAttrString(self->socket, "accept")) == NULL) return NULL; tuple = PyEval_CallObject(meth, args); Py_DECREF(meth); if (tuple == NULL) return NULL; socket = PyTuple_GetItem(tuple, 0); Py_INCREF(socket); address = PyTuple_GetItem(tuple, 1); Py_INCREF(address); Py_DECREF(tuple); conn = ssl_Connection_New(self->context, socket); Py_DECREF(socket); if (conn == NULL) { Py_DECREF(address); return NULL; } SSL_set_accept_state(conn->ssl); tuple = Py_BuildValue("(OO)", conn, address); Py_DECREF(conn); Py_DECREF(address); return tuple; } static char ssl_Connection_bio_shutdown_doc[] = "\n\ When using non-socket connections this function signals end of\n\ data on the input for this connection.\n\ \n\ @return: None\n\ "; static PyObject * ssl_Connection_bio_shutdown(ssl_ConnectionObj *self, PyObject *args) { if (self->from_ssl == NULL) { PyErr_SetString(PyExc_TypeError, "Connection sock was not None"); return NULL; } BIO_set_mem_eof_return(self->into_ssl, 0); Py_INCREF(Py_None); return Py_None; } static char ssl_Connection_shutdown_doc[] = "\n\ Send closure alert\n\ \n\ @return: True if the shutdown completed successfully (i.e. both sides\n\ have sent closure alerts), false otherwise (i.e. you have to\n\ wait for a ZeroReturnError on a recv() method call\n\ "; static PyObject * ssl_Connection_shutdown(ssl_ConnectionObj *self, PyObject *args) { int ret; if (!PyArg_ParseTuple(args, ":shutdown")) return NULL; MY_BEGIN_ALLOW_THREADS(self->tstate) ret = SSL_shutdown(self->ssl); MY_END_ALLOW_THREADS(self->tstate) if (PyErr_Occurred()) { flush_error_queue(); return NULL; } if (ret < 0) { exception_from_error_queue(ssl_Error); return NULL; } else if (ret > 0) { Py_INCREF(Py_True); return Py_True; } else { Py_INCREF(Py_False); return Py_False; } } static char ssl_Connection_get_cipher_list_doc[] = "\n\ Get the session cipher list\n\ \n\ @return: A list of cipher strings\n\ "; static PyObject * ssl_Connection_get_cipher_list(ssl_ConnectionObj *self, PyObject *args) { int idx = 0; const char *ret; PyObject *lst, *item; if (!PyArg_ParseTuple(args, ":get_cipher_list")) return NULL; lst = PyList_New(0); while ((ret = SSL_get_cipher_list(self->ssl, idx)) != NULL) { item = PyText_FromString(ret); PyList_Append(lst, item); Py_DECREF(item); idx++; } return lst; } static char ssl_Connection_get_client_ca_list_doc[] = "\n\ Get CAs whose certificates are suggested for client authentication.\n\ \n\ @return: If this is a server connection, a list of X509Names representing\n\ the acceptable CAs as set by L{OpenSSL.SSL.Context.set_client_ca_list} or\n\ L{OpenSSL.SSL.Context.add_client_ca}. If this is a client connection,\n\ the list of such X509Names sent by the server, or an empty list if that\n\ has not yet happened.\n\ "; static PyObject * ssl_Connection_get_client_ca_list(ssl_ConnectionObj *self, PyObject *args) { STACK_OF(X509_NAME) *CANames; PyObject *CAList; int i, n; if (!PyArg_ParseTuple(args, ":get_client_ca_list")) { return NULL; } CANames = SSL_get_client_CA_list(self->ssl); if (CANames == NULL) { return PyList_New(0); } n = sk_X509_NAME_num(CANames); CAList = PyList_New(n); if (CAList == NULL) { return NULL; } for (i = 0; i < n; i++) { X509_NAME *CAName; PyObject *CA; CAName = X509_NAME_dup(sk_X509_NAME_value(CANames, i)); if (CAName == NULL) { Py_DECREF(CAList); exception_from_error_queue(ssl_Error); return NULL; } CA = (PyObject *)new_x509name(CAName, 1); if (CA == NULL) { X509_NAME_free(CAName); Py_DECREF(CAList); return NULL; } if (PyList_SetItem(CAList, i, CA)) { Py_DECREF(CA); Py_DECREF(CAList); return NULL; } } return CAList; } static char ssl_Connection_makefile_doc[] = "\n\ The makefile() method is not implemented, since there is no dup semantics\n\ for SSL connections\n\ \n\ @raise NotImplementedError\n\ "; static PyObject * ssl_Connection_makefile(ssl_ConnectionObj *self, PyObject *args) { PyErr_SetString(PyExc_NotImplementedError, "Cannot make file object of SSL.Connection"); return NULL; } static char ssl_Connection_get_app_data_doc[] = "\n\ Get application data\n\ \n\ @return: The application data\n\ "; static PyObject * ssl_Connection_get_app_data(ssl_ConnectionObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":get_app_data")) return NULL; Py_INCREF(self->app_data); return self->app_data; } static char ssl_Connection_set_app_data_doc[] = "\n\ Set application data\n\ \n\ @param data - The application data\n\ @return: None\n\ "; static PyObject * ssl_Connection_set_app_data(ssl_ConnectionObj *self, PyObject *args) { PyObject *data; if (!PyArg_ParseTuple(args, "O:set_app_data", &data)) return NULL; Py_DECREF(self->app_data); Py_INCREF(data); self->app_data = data; Py_INCREF(Py_None); return Py_None; } static char ssl_Connection_get_shutdown_doc[] = "\n\ Get shutdown state\n\ \n\ @return: The shutdown state, a bitvector of SENT_SHUTDOWN, RECEIVED_SHUTDOWN.\n\ "; static PyObject * ssl_Connection_get_shutdown(ssl_ConnectionObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":get_shutdown")) return NULL; return PyLong_FromLong((long)SSL_get_shutdown(self->ssl)); } static char ssl_Connection_set_shutdown_doc[] = "\n\ Set shutdown state\n\ \n\ @param state - bitvector of SENT_SHUTDOWN, RECEIVED_SHUTDOWN.\n\ @return: None\n\ "; static PyObject * ssl_Connection_set_shutdown(ssl_ConnectionObj *self, PyObject *args) { int shutdown; if (!PyArg_ParseTuple(args, "i:set_shutdown", &shutdown)) return NULL; SSL_set_shutdown(self->ssl, shutdown); Py_INCREF(Py_None); return Py_None; } static char ssl_Connection_state_string_doc[] = "\n\ Get a verbose state description\n\ \n\ @return: A string representing the state\n\ "; static PyObject * ssl_Connection_state_string(ssl_ConnectionObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":state_string")) return NULL; return PyText_FromString(SSL_state_string_long(self->ssl)); } static char ssl_Connection_client_random_doc[] = "\n\ Get a copy of the client hello nonce.\n\ \n\ @return: A string representing the state\n\ "; static PyObject * ssl_Connection_client_random(ssl_ConnectionObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":client_random")) return NULL; if (self->ssl->session == NULL) { Py_INCREF(Py_None); return Py_None; } return PyBytes_FromStringAndSize( (const char *) self->ssl->s3->client_random, SSL3_RANDOM_SIZE); } static char ssl_Connection_server_random_doc[] = "\n\ Get a copy of the server hello nonce.\n\ \n\ @return: A string representing the state\n\ "; static PyObject * ssl_Connection_server_random(ssl_ConnectionObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":server_random")) return NULL; if (self->ssl->session == NULL) { Py_INCREF(Py_None); return Py_None; } return PyBytes_FromStringAndSize( (const char *) self->ssl->s3->server_random, SSL3_RANDOM_SIZE); } static char ssl_Connection_master_key_doc[] = "\n\ Get a copy of the master key.\n\ \n\ @return: A string representing the state\n\ "; static PyObject * ssl_Connection_master_key(ssl_ConnectionObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":master_key")) return NULL; if (self->ssl->session == NULL) { Py_INCREF(Py_None); return Py_None; } return PyBytes_FromStringAndSize( (const char *) self->ssl->session->master_key, self->ssl->session->master_key_length); } static char ssl_Connection_sock_shutdown_doc[] = "\n\ See shutdown(2)\n\ \n\ @return: What the socket's shutdown() method returns\n\ "; static PyObject * ssl_Connection_sock_shutdown(ssl_ConnectionObj *self, PyObject *args) { PyObject *meth, *ret; if ((meth = PyObject_GetAttrString(self->socket, "shutdown")) == NULL) return NULL; ret = PyEval_CallObject(meth, args); Py_DECREF(meth); return ret; } static char ssl_Connection_get_peer_certificate_doc[] = "\n\ Retrieve the other side's certificate (if any)\n\ \n\ @return: The peer's certificate\n\ "; static PyObject * ssl_Connection_get_peer_certificate(ssl_ConnectionObj *self, PyObject *args) { X509 *cert; if (!PyArg_ParseTuple(args, ":get_peer_certificate")) return NULL; cert = SSL_get_peer_certificate(self->ssl); if (cert != NULL) { return (PyObject *)new_x509(cert, 1); } else { Py_INCREF(Py_None); return Py_None; } } static char ssl_Connection_get_peer_cert_chain_doc[] = "\n\ Retrieve the other side's certificate (if any)\n\ \n\ @return: A list of X509 instances giving the peer's certificate chain,\n\ or None if it does not have one.\n\ "; static PyObject * ssl_Connection_get_peer_cert_chain(ssl_ConnectionObj *self, PyObject *args) { STACK_OF(X509) *sk; PyObject *chain; crypto_X509Obj *cert; Py_ssize_t i; if (!PyArg_ParseTuple(args, ":get_peer_cert_chain")) { return NULL; } sk = SSL_get_peer_cert_chain(self->ssl); if (sk != NULL) { chain = PyList_New(sk_X509_num(sk)); for (i = 0; i < sk_X509_num(sk); i++) { cert = new_x509(sk_X509_value(sk, i), 1); if (!cert) { /* XXX Untested */ Py_DECREF(chain); return NULL; } CRYPTO_add(&cert->x509->references, 1, CRYPTO_LOCK_X509); PyList_SET_ITEM(chain, i, (PyObject *)cert); } return chain; } else { Py_INCREF(Py_None); return Py_None; } } static char ssl_Connection_want_read_doc[] = "\n\ Checks if more data has to be read from the transport layer to complete an\n\ operation.\n\ \n\ @return: True iff more data has to be read\n\ "; static PyObject * ssl_Connection_want_read(ssl_ConnectionObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":want_read")) return NULL; return PyLong_FromLong((long)SSL_want_read(self->ssl)); } static char ssl_Connection_want_write_doc[] = "\n\ Checks if there is data to write to the transport layer to complete an\n\ operation.\n\ \n\ @return: True iff there is data to write\n\ "; static PyObject * ssl_Connection_want_write(ssl_ConnectionObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":want_write")) return NULL; return PyLong_FromLong((long)SSL_want_write(self->ssl)); } /* * Member methods in the Connection object * ADD_METHOD(name) expands to a correct PyMethodDef declaration * { 'name', (PyCFunction)ssl_Connection_name, METH_VARARGS } * for convenience * ADD_ALIAS(name,real) creates an "alias" of the ssl_Connection_real * function with the name 'name' */ #define ADD_METHOD(name) \ { #name, (PyCFunction)ssl_Connection_##name, METH_VARARGS, ssl_Connection_##name##_doc } #define ADD_ALIAS(name,real) \ { #name, (PyCFunction)ssl_Connection_##real, METH_VARARGS, ssl_Connection_##real##_doc } static PyMethodDef ssl_Connection_methods[] = { ADD_METHOD(get_context), ADD_METHOD(set_context), ADD_METHOD(get_servername), ADD_METHOD(set_tlsext_host_name), ADD_METHOD(pending), ADD_METHOD(send), ADD_ALIAS (write, send), ADD_METHOD(sendall), ADD_METHOD(recv), ADD_ALIAS (read, recv), ADD_METHOD(bio_read), ADD_METHOD(bio_write), ADD_METHOD(renegotiate), ADD_METHOD(do_handshake), #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x00907000L ADD_METHOD(renegotiate_pending), #endif ADD_METHOD(total_renegotiations), ADD_METHOD(connect), ADD_METHOD(connect_ex), ADD_METHOD(accept), ADD_METHOD(bio_shutdown), ADD_METHOD(shutdown), ADD_METHOD(get_cipher_list), ADD_METHOD(get_client_ca_list), ADD_METHOD(makefile), ADD_METHOD(get_app_data), ADD_METHOD(set_app_data), ADD_METHOD(get_shutdown), ADD_METHOD(set_shutdown), ADD_METHOD(state_string), ADD_METHOD(server_random), ADD_METHOD(client_random), ADD_METHOD(master_key), ADD_METHOD(sock_shutdown), ADD_METHOD(get_peer_certificate), ADD_METHOD(get_peer_cert_chain), ADD_METHOD(want_read), ADD_METHOD(want_write), ADD_METHOD(set_accept_state), ADD_METHOD(set_connect_state), { NULL, NULL } }; #undef ADD_ALIAS #undef ADD_METHOD static char ssl_Connection_doc[] = "\n\ Connection(context, socket) -> Connection instance\n\ \n\ Create a new Connection object, using the given OpenSSL.SSL.Context instance\n\ and socket.\n\ \n\ @param context: An SSL Context to use for this connection\n\ @param socket: The socket to use for transport layer\n\ "; /* * Initializer used by ssl_Connection_new and ssl_Connection_New. *Not* * tp_init. This takes an already allocated ssl_ConnectionObj, a context, and * a optionally a socket, and glues them all together. */ static ssl_ConnectionObj* ssl_Connection_init(ssl_ConnectionObj *self, ssl_ContextObj *ctx, PyObject *sock) { int fd; Py_INCREF(ctx); self->context = ctx; Py_INCREF(sock); self->socket = sock; self->ssl = NULL; self->from_ssl = NULL; self->into_ssl = NULL; Py_INCREF(Py_None); self->app_data = Py_None; self->tstate = NULL; self->ssl = SSL_new(self->context->ctx); SSL_set_app_data(self->ssl, self); if (self->socket == Py_None) { /* If it's not a socket or file, treat it like a memory buffer, * so crazy people can do things like EAP-TLS. */ self->into_ssl = BIO_new(BIO_s_mem()); self->from_ssl = BIO_new(BIO_s_mem()); if (self->into_ssl == NULL || self->from_ssl == NULL) goto error; SSL_set_bio(self->ssl, self->into_ssl, self->from_ssl); } else { fd = PyObject_AsFileDescriptor(self->socket); if (fd < 0) { Py_DECREF(self); return NULL; } else { SSL_set_fd(self->ssl, (SOCKET_T)fd); } } return self; error: BIO_free(self->into_ssl); /* NULL safe */ BIO_free(self->from_ssl); /* NULL safe */ Py_DECREF(self); return NULL; } /* * Constructor for Connection objects * * Arguments: ctx - An SSL Context to use for this connection * sock - The socket to use for transport layer * Returns: The newly created Connection object */ ssl_ConnectionObj * ssl_Connection_New(ssl_ContextObj *ctx, PyObject *sock) { ssl_ConnectionObj *self; self = PyObject_GC_New(ssl_ConnectionObj, &ssl_Connection_Type); if (self == NULL) { return NULL; } self = ssl_Connection_init(self, ctx, sock); if (self == NULL) { return NULL; } PyObject_GC_Track((PyObject *)self); return self; } static PyObject* ssl_Connection_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) { ssl_ConnectionObj *self; ssl_ContextObj *ctx; PyObject *sock; static char *kwlist[] = {"context", "socket", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O:Connection", kwlist, &ssl_Context_Type, &ctx, &sock)) { return NULL; } self = (ssl_ConnectionObj *)subtype->tp_alloc(subtype, 1); if (self == NULL) { return NULL; } return (PyObject *)ssl_Connection_init(self, ctx, sock); } /* * Find attribute * * Arguments: self - The Connection object * name - The attribute name * Returns: A Python object for the attribute, or NULL if something went * wrong */ static PyObject * ssl_Connection_getattro(ssl_ConnectionObj *self, PyObject *nameobj) { PyObject *meth; meth = PyObject_GenericGetAttr((PyObject*)self, nameobj); if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_Clear(); /* Try looking it up in the "socket" instead. */ meth = PyObject_GenericGetAttr(self->socket, nameobj); } return meth; } /* * Call the visitproc on all contained objects. * * Arguments: self - The Connection object * visit - Function to call * arg - Extra argument to visit * Returns: 0 if all goes well, otherwise the return code from the first * call that gave non-zero result. */ static int ssl_Connection_traverse(ssl_ConnectionObj *self, visitproc visit, void *arg) { int ret = 0; if (ret == 0 && self->context != NULL) ret = visit((PyObject *)self->context, arg); if (ret == 0 && self->socket != NULL) ret = visit(self->socket, arg); if (ret == 0 && self->app_data != NULL) ret = visit(self->app_data, arg); return ret; } /* * Decref all contained objects and zero the pointers. * * Arguments: self - The Connection object * Returns: Always 0. */ static int ssl_Connection_clear(ssl_ConnectionObj *self) { Py_XDECREF(self->context); self->context = NULL; Py_XDECREF(self->socket); self->socket = NULL; Py_XDECREF(self->app_data); self->app_data = NULL; self->into_ssl = NULL; /* was cleaned up by SSL_free() */ self->from_ssl = NULL; /* was cleaned up by SSL_free() */ return 0; } /* * Deallocate the memory used by the Connection object * * Arguments: self - The Connection object * Returns: None */ static void ssl_Connection_dealloc(ssl_ConnectionObj *self) { PyObject_GC_UnTrack(self); if (self->ssl != NULL) SSL_free(self->ssl); ssl_Connection_clear(self); PyObject_GC_Del(self); } PyTypeObject ssl_Connection_Type = { PyOpenSSL_HEAD_INIT(&PyType_Type, 0) "OpenSSL.SSL.Connection", sizeof(ssl_ConnectionObj), 0, (destructor)ssl_Connection_dealloc, NULL, /* print */ NULL, /* tp_getattr */ NULL, /* setattr */ NULL, /* compare */ NULL, /* repr */ NULL, /* as_number */ NULL, /* as_sequence */ NULL, /* as_mapping */ NULL, /* hash */ NULL, /* call */ NULL, /* str */ (getattrofunc)ssl_Connection_getattro, /* getattro */ NULL, /* setattro */ NULL, /* as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, ssl_Connection_doc, /* doc */ (traverseproc)ssl_Connection_traverse, (inquiry)ssl_Connection_clear, NULL, /* tp_richcompare */ 0, /* tp_weaklistoffset */ NULL, /* tp_iter */ NULL, /* tp_iternext */ ssl_Connection_methods, /* tp_methods */ NULL, /* tp_members */ NULL, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ NULL, /* tp_descr_get */ NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ NULL, /* tp_init */ NULL, /* tp_alloc */ ssl_Connection_new, /* tp_new */ }; /* * Initiailze the Connection part of the SSL sub module * * Arguments: dict - The OpenSSL.SSL module * Returns: 1 for success, 0 otherwise */ int init_ssl_connection(PyObject *module) { if (PyType_Ready(&ssl_Connection_Type) < 0) { return 0; } /* PyModule_AddObject steals a reference. */ Py_INCREF((PyObject *)&ssl_Connection_Type); if (PyModule_AddObject(module, "Connection", (PyObject *)&ssl_Connection_Type) != 0) { return 0; } /* PyModule_AddObject steals a reference. */ Py_INCREF((PyObject *)&ssl_Connection_Type); if (PyModule_AddObject(module, "ConnectionType", (PyObject *)&ssl_Connection_Type) != 0) { return 0; } return 1; } pyOpenSSL-0.13/OpenSSL/ssl/connection.h0000644000214500021450000000226511630175105017637 0ustar bb-slavebb-slave/* * connection.h * * Copyright (C) AB Strakt * See LICENSE for details. * * Export SSL Connection data structures and functions. * See the file RATIONALE for a short explanation of why this module was written. * * Reviewed 2001-07-23 * */ #ifndef PyOpenSSL_SSL_CONNECTION_H_ #define PyOpenSSL_SSL_CONNECTION_H_ #include #include /* shamelessly stolen from socketmodule.c */ #ifdef MS_WINDOWS # include typedef SOCKET SOCKET_T; # ifdef MS_WIN64 # define SIZEOF_SOCKET_T 8 # else # define SIZEOF_SOCKET_T 4 # endif #else typedef int SOCKET_T; # define SIZEOF_SOCKET_T SIZEOF_INT #endif extern int init_ssl_connection (PyObject *); extern PyTypeObject ssl_Connection_Type; #define ssl_Connection_Check(v) ((v)->ob_type == &ssl_Connection_Type) typedef struct { PyObject_HEAD SSL *ssl; ssl_ContextObj *context; PyObject *socket; PyThreadState *tstate; /* This field is no longer used. */ PyObject *app_data; BIO *into_ssl, *from_ssl; /* for connections without file descriptors */ } ssl_ConnectionObj; #endif pyOpenSSL-0.13/OpenSSL/ssl/context.c0000644000214500021450000011325011630175105017154 0ustar bb-slavebb-slave/* * context.c * * Copyright (C) AB Strakt * Copyright (C) Jean-Paul Calderone * See LICENSE for details. * * SSL Context objects and their methods. * See the file RATIONALE for a short explanation of why this module was written. * * Reviewed 2001-07-23 */ #include #if PY_VERSION_HEX >= 0x02050000 # define PYARG_PARSETUPLE_FORMAT const char # define PYOBJECT_GETATTRSTRING_TYPE const char* #else # define PYARG_PARSETUPLE_FORMAT char # define PYOBJECT_GETATTRSTRING_TYPE char* #endif #ifndef MS_WINDOWS # include # include # if !(defined(__BEOS__) || defined(__CYGWIN__)) # include # endif #else # include # include #endif #define SSL_MODULE #include "ssl.h" /* * CALLBACKS * * Callbacks work like this: We provide a "global" callback in C which * transforms the arguments into a Python argument tuple and calls the * corresponding Python callback, and then parsing the return value back into * things the C function can return. * * Three caveats: * + How do we find the Context object where the Python callbacks are stored? * + What about multithreading and execution frames? * + What about Python callbacks that raise exceptions? * * The solution to the first issue is trivial if the callback provides * "userdata" functionality. Since the only callbacks that don't provide * userdata do provide a pointer to an SSL structure, we can associate an SSL * object and a Connection one-to-one via the SSL_set/get_app_data() * functions. * * The solution to the other issue is to rewrite the Py_BEGIN_ALLOW_THREADS * macro allowing it (or rather a new macro) to specify where to save the * thread state (in our case, as a member of the Connection/Context object) so * we can retrieve it again before calling the Python callback. */ /* * Globally defined passphrase callback. This is called from OpenSSL * internally. The GIL will not be held when this function is invoked. It * must not be held when the function returns. * * Arguments: buf - Buffer to store the returned passphrase in * maxlen - Maximum length of the passphrase * verify - If true, the passphrase callback should ask for a * password twice and verify they're equal. If false, only * ask once. * arg - User data, always a Context object * Returns: The length of the password if successful, 0 otherwise */ static int global_passphrase_callback(char *buf, int maxlen, int verify, void *arg) { /* * Initialize len here because we're always going to return it, and we * might jump to the return before it gets initialized in any other way. */ int len = 0; char *str; PyObject *argv, *ret = NULL; ssl_ContextObj *ctx = (ssl_ContextObj *)arg; /* * GIL isn't held yet. First things first - acquire it, or any Python API * we invoke might segfault or blow up the sun. The reverse will be done * before returning. */ MY_END_ALLOW_THREADS(ctx->tstate); /* The Python callback is called with a (maxlen,verify,userdata) tuple */ argv = Py_BuildValue("(iiO)", maxlen, verify, ctx->passphrase_userdata); /* * XXX Didn't check argv to see if it was NULL. -exarkun */ ret = PyEval_CallObject(ctx->passphrase_callback, argv); Py_DECREF(argv); if (ret == NULL) { /* * The callback raised an exception. It will be raised by whatever * Python API triggered this callback. */ goto out; } if (!PyObject_IsTrue(ret)) { /* * Returned "", or None, or something. Treat it as no passphrase. */ Py_DECREF(ret); goto out; } if (!PyBytes_Check(ret)) { /* * XXX Returned something that wasn't a string. This is bogus. We'll * return 0 and OpenSSL will treat it as an error, resulting in an * exception from whatever Python API triggered this callback. */ Py_DECREF(ret); goto out; } len = PyBytes_Size(ret); if (len > maxlen) { /* * Returned more than we said they were allowed to return. Just * truncate it. Might be better to raise an exception, * instead. -exarkun */ len = maxlen; } str = PyBytes_AsString(ret); strncpy(buf, str, len); Py_XDECREF(ret); out: /* * This function is returning into OpenSSL. Release the GIL again. */ MY_BEGIN_ALLOW_THREADS(ctx->tstate); return len; } /* * Globally defined verify callback * * Arguments: ok - True everything is OK "so far", false otherwise * x509_ctx - Contains the certificate being checked, the current * error number and depth, and the Connection we're * dealing with * Returns: True if everything is okay, false otherwise */ static int global_verify_callback(int ok, X509_STORE_CTX *x509_ctx) { PyObject *argv, *ret; SSL *ssl; ssl_ConnectionObj *conn; crypto_X509Obj *cert; int errnum, errdepth, c_ret; // Get Connection object to check thread state ssl = (SSL *)X509_STORE_CTX_get_app_data(x509_ctx); conn = (ssl_ConnectionObj *)SSL_get_app_data(ssl); MY_END_ALLOW_THREADS(conn->tstate); cert = new_x509(X509_STORE_CTX_get_current_cert(x509_ctx), 0); errnum = X509_STORE_CTX_get_error(x509_ctx); errdepth = X509_STORE_CTX_get_error_depth(x509_ctx); argv = Py_BuildValue("(OOiii)", (PyObject *)conn, (PyObject *)cert, errnum, errdepth, ok); Py_DECREF(cert); ret = PyEval_CallObject(conn->context->verify_callback, argv); Py_DECREF(argv); if (ret != NULL && PyObject_IsTrue(ret)) { X509_STORE_CTX_set_error(x509_ctx, X509_V_OK); Py_DECREF(ret); c_ret = 1; } else { c_ret = 0; } MY_BEGIN_ALLOW_THREADS(conn->tstate); return c_ret; } /* * Globally defined info callback. This is called from OpenSSL internally. * The GIL will not be held when this function is invoked. It must not be held * when the function returns. * * Arguments: ssl - The Connection * where - The part of the SSL code that called us * _ret - The return code of the SSL function that called us * Returns: None */ static void global_info_callback(const SSL *ssl, int where, int _ret) { ssl_ConnectionObj *conn = (ssl_ConnectionObj *)SSL_get_app_data(ssl); PyObject *argv, *ret; /* * GIL isn't held yet. First things first - acquire it, or any Python API * we invoke might segfault or blow up the sun. The reverse will be done * before returning. */ MY_END_ALLOW_THREADS(conn->tstate); argv = Py_BuildValue("(Oii)", (PyObject *)conn, where, _ret); ret = PyEval_CallObject(conn->context->info_callback, argv); Py_DECREF(argv); if (ret == NULL) { /* * XXX - This should be reported somehow. -exarkun */ PyErr_Clear(); } else { Py_DECREF(ret); } /* * This function is returning into OpenSSL. Release the GIL again. */ MY_BEGIN_ALLOW_THREADS(conn->tstate); return; } /* * Globally defined TLS extension server name callback. This is called from * OpenSSL internally. The GIL will not be held when this function is invoked. * It must not be held when the function returns. * * ssl represents the connection this callback is for * * alert is a pointer to the alert value which maybe will be emitted to the * client if there is an error handling the client hello (which contains the * server name). This is an out parameter, maybe. * * arg is an arbitrary pointer specified by SSL_CTX_set_tlsext_servername_arg. * It will be NULL for all pyOpenSSL uses. */ static int global_tlsext_servername_callback(const SSL *ssl, int *alert, void *arg) { int result = 0; PyObject *argv, *ret; ssl_ConnectionObj *conn = (ssl_ConnectionObj *)SSL_get_app_data(ssl); /* * GIL isn't held yet. First things first - acquire it, or any Python API * we invoke might segfault or blow up the sun. The reverse will be done * before returning. */ MY_END_ALLOW_THREADS(conn->tstate); argv = Py_BuildValue("(O)", (PyObject *)conn); ret = PyEval_CallObject(conn->context->tlsext_servername_callback, argv); Py_DECREF(argv); Py_DECREF(ret); /* * This function is returning into OpenSSL. Release the GIL again. */ MY_BEGIN_ALLOW_THREADS(conn->tstate); return result; } /* * More recent builds of OpenSSL may have SSLv2 completely disabled. */ #ifdef OPENSSL_NO_SSL2 #define SSLv2_METHOD_TEXT "" #else #define SSLv2_METHOD_TEXT "SSLv2_METHOD, " #endif static char ssl_Context_doc[] = "\n\ Context(method) -> Context instance\n\ \n\ OpenSSL.SSL.Context instances define the parameters for setting up new SSL\n\ connections.\n\ \n\ @param method: One of " SSLv2_METHOD_TEXT "SSLv3_METHOD, SSLv23_METHOD, or\n\ TLSv1_METHOD.\n\ "; #undef SSLv2_METHOD_TEXT static char ssl_Context_load_verify_locations_doc[] = "\n\ Let SSL know where we can find trusted certificates for the certificate\n\ chain\n\ \n\ @param cafile: In which file we can find the certificates\n\ @param capath: In which directory we can find the certificates\n\ @return: None\n\ "; static PyObject * ssl_Context_load_verify_locations(ssl_ContextObj *self, PyObject *args) { char *cafile = NULL; char *capath = NULL; if (!PyArg_ParseTuple(args, "z|z:load_verify_locations", &cafile, &capath)) { return NULL; } if (!SSL_CTX_load_verify_locations(self->ctx, cafile, capath)) { exception_from_error_queue(ssl_Error); return NULL; } else { Py_INCREF(Py_None); return Py_None; } } static char ssl_Context_set_default_verify_paths_doc[] = "\n\ Use the platform-specific CA certificate locations\n\ \n\ @return: None\n\ "; static PyObject * ssl_Context_set_default_verify_paths(ssl_ContextObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":set_default_verify_paths")) { return NULL; } /* * XXX Error handling for SSL_CTX_set_default_verify_paths is untested. * -exarkun */ if (!SSL_CTX_set_default_verify_paths(self->ctx)) { exception_from_error_queue(ssl_Error); return NULL; } Py_INCREF(Py_None); return Py_None; }; static char ssl_Context_set_passwd_cb_doc[] = "\n\ Set the passphrase callback\n\ \n\ @param callback: The Python callback to use\n\ @param userdata: (optional) A Python object which will be given as\n\ argument to the callback\n\ @return: None\n\ "; static PyObject * ssl_Context_set_passwd_cb(ssl_ContextObj *self, PyObject *args) { PyObject *callback = NULL, *userdata = Py_None; if (!PyArg_ParseTuple(args, "O|O:set_passwd_cb", &callback, &userdata)) return NULL; if (!PyCallable_Check(callback)) { PyErr_SetString(PyExc_TypeError, "expected PyCallable"); return NULL; } Py_DECREF(self->passphrase_callback); Py_INCREF(callback); self->passphrase_callback = callback; SSL_CTX_set_default_passwd_cb(self->ctx, global_passphrase_callback); Py_DECREF(self->passphrase_userdata); Py_INCREF(userdata); self->passphrase_userdata = userdata; SSL_CTX_set_default_passwd_cb_userdata(self->ctx, (void *)self); Py_INCREF(Py_None); return Py_None; } static PyTypeObject * type_modified_error(const char *name) { PyErr_Format(PyExc_RuntimeError, "OpenSSL.crypto's '%s' attribute has been modified", name); return NULL; } static PyTypeObject * import_crypto_type(const char *name, size_t objsize) { PyObject *module, *type, *name_attr; PyTypeObject *res; int right_name; module = PyImport_ImportModule("OpenSSL.crypto"); if (module == NULL) { return NULL; } type = PyObject_GetAttrString(module, (PYOBJECT_GETATTRSTRING_TYPE)name); Py_DECREF(module); if (type == NULL) { return NULL; } if (!(PyType_Check(type))) { Py_DECREF(type); return type_modified_error(name); } name_attr = PyObject_GetAttrString(type, "__name__"); if (name_attr == NULL) { Py_DECREF(type); return NULL; } #ifdef PY3 { PyObject* asciiname = PyUnicode_AsASCIIString(name_attr); Py_DECREF(name_attr); name_attr = asciiname; } #endif right_name = (PyBytes_CheckExact(name_attr) && strcmp(name, PyBytes_AsString(name_attr)) == 0); Py_DECREF(name_attr); res = (PyTypeObject *)type; if (!right_name || res->tp_basicsize != objsize) { Py_DECREF(type); return type_modified_error(name); } return res; } static crypto_X509Obj * parse_certificate_argument(const char* format, PyObject* args) { static PyTypeObject *crypto_X509_type = NULL; crypto_X509Obj *cert; if (!crypto_X509_type) { crypto_X509_type = import_crypto_type("X509", sizeof(crypto_X509Obj)); if (!crypto_X509_type) { return NULL; } } if (!PyArg_ParseTuple(args, (PYARG_PARSETUPLE_FORMAT *)format, crypto_X509_type, &cert)) { return NULL; } return cert; } static char ssl_Context_add_extra_chain_cert_doc[] = "\n\ Add certificate to chain\n\ \n\ @param certobj: The X509 certificate object to add to the chain\n\ @return: None\n\ "; static PyObject * ssl_Context_add_extra_chain_cert(ssl_ContextObj *self, PyObject *args) { X509* cert_original; crypto_X509Obj *cert = parse_certificate_argument( "O!:add_extra_chain_cert", args); if (cert == NULL) { return NULL; } if (!(cert_original = X509_dup(cert->x509))) { /* exception_from_error_queue(ssl_Error); */ PyErr_SetString(PyExc_RuntimeError, "X509_dup failed"); return NULL; } if (!SSL_CTX_add_extra_chain_cert(self->ctx, cert_original)) { X509_free(cert_original); exception_from_error_queue(ssl_Error); return NULL; } else { Py_INCREF(Py_None); return Py_None; } } static char ssl_Context_use_certificate_chain_file_doc[] = "\n\ Load a certificate chain from a file\n\ \n\ @param certfile: The name of the certificate chain file\n\ @return: None\n\ "; static PyObject * ssl_Context_use_certificate_chain_file(ssl_ContextObj *self, PyObject *args) { char *certfile; if (!PyArg_ParseTuple(args, "s:use_certificate_chain_file", &certfile)) return NULL; if (!SSL_CTX_use_certificate_chain_file(self->ctx, certfile)) { exception_from_error_queue(ssl_Error); return NULL; } else { Py_INCREF(Py_None); return Py_None; } } static char ssl_Context_use_certificate_file_doc[] = "\n\ Load a certificate from a file\n\ \n\ @param certfile: The name of the certificate file\n\ @param filetype: (optional) The encoding of the file, default is PEM\n\ @return: None\n\ "; static PyObject * ssl_Context_use_certificate_file(ssl_ContextObj *self, PyObject *args) { char *certfile; int filetype = SSL_FILETYPE_PEM; if (!PyArg_ParseTuple(args, "s|i:use_certificate_file", &certfile, &filetype)) return NULL; if (!SSL_CTX_use_certificate_file(self->ctx, certfile, filetype)) { exception_from_error_queue(ssl_Error); return NULL; } else { Py_INCREF(Py_None); return Py_None; } } static char ssl_Context_use_certificate_doc[] = "\n\ Load a certificate from a X509 object\n\ \n\ @param cert: The X509 object\n\ @return: None\n\ "; static PyObject * ssl_Context_use_certificate(ssl_ContextObj *self, PyObject *args) { crypto_X509Obj *cert = parse_certificate_argument( "O!:use_certificate", args); if (cert == NULL) { return NULL; } if (!SSL_CTX_use_certificate(self->ctx, cert->x509)) { exception_from_error_queue(ssl_Error); return NULL; } else { Py_INCREF(Py_None); return Py_None; } } static char ssl_Context_use_privatekey_file_doc[] = "\n\ Load a private key from a file\n\ \n\ @param keyfile: The name of the key file\n\ @param filetype: (optional) The encoding of the file, default is PEM\n\ @return: None\n\ "; static PyObject * ssl_Context_use_privatekey_file(ssl_ContextObj *self, PyObject *args) { char *keyfile; int filetype = SSL_FILETYPE_PEM, ret; if (!PyArg_ParseTuple(args, "s|i:use_privatekey_file", &keyfile, &filetype)) return NULL; MY_BEGIN_ALLOW_THREADS(self->tstate); ret = SSL_CTX_use_PrivateKey_file(self->ctx, keyfile, filetype); MY_END_ALLOW_THREADS(self->tstate); if (PyErr_Occurred()) { flush_error_queue(); return NULL; } if (!ret) { exception_from_error_queue(ssl_Error); return NULL; } else { Py_INCREF(Py_None); return Py_None; } } static char ssl_Context_use_privatekey_doc[] = "\n\ Load a private key from a PKey object\n\ \n\ @param pkey: The PKey object\n\ @return: None\n\ "; static PyObject * ssl_Context_use_privatekey(ssl_ContextObj *self, PyObject *args) { static PyTypeObject *crypto_PKey_type = NULL; crypto_PKeyObj *pkey; if (!crypto_PKey_type) { crypto_PKey_type = import_crypto_type("PKey", sizeof(crypto_PKeyObj)); if (!crypto_PKey_type) { return NULL; } } if (!PyArg_ParseTuple(args, "O!:use_privatekey", crypto_PKey_type, &pkey)) { return NULL; } if (!SSL_CTX_use_PrivateKey(self->ctx, pkey->pkey)) { exception_from_error_queue(ssl_Error); return NULL; } else { Py_INCREF(Py_None); return Py_None; } } static char ssl_Context_check_privatekey_doc[] = "\n\ Check that the private key and certificate match up\n\ \n\ @return: None (raises an exception if something's wrong)\n\ "; static PyObject * ssl_Context_check_privatekey(ssl_ContextObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":check_privatekey")) return NULL; if (!SSL_CTX_check_private_key(self->ctx)) { exception_from_error_queue(ssl_Error); return NULL; } else { Py_INCREF(Py_None); return Py_None; } } static char ssl_Context_load_client_ca_doc[] = "\n\ Load the trusted certificates that will be sent to the client (basically\n \ telling the client \"These are the guys I trust\"). Does not actually\n\ imply any of the certificates are trusted; that must be configured\n\ separately.\n\ \n\ @param cafile: The name of the certificates file\n\ @return: None\n\ "; static PyObject * ssl_Context_load_client_ca(ssl_ContextObj *self, PyObject *args) { char *cafile; if (!PyArg_ParseTuple(args, "s:load_client_ca", &cafile)) return NULL; SSL_CTX_set_client_CA_list(self->ctx, SSL_load_client_CA_file(cafile)); Py_INCREF(Py_None); return Py_None; } static char ssl_Context_set_session_id_doc[] = "\n\ Set the session identifier, this is needed if you want to do session\n\ resumption (which, ironically, isn't implemented yet)\n\ \n\ @param buf: A Python object that can be safely converted to a string\n\ @returns: None\n\ "; static PyObject * ssl_Context_set_session_id(ssl_ContextObj *self, PyObject *args) { unsigned char *buf; unsigned int len; if (!PyArg_ParseTuple(args, "s#:set_session_id", &buf, &len)) return NULL; if (!SSL_CTX_set_session_id_context(self->ctx, buf, len)) { exception_from_error_queue(ssl_Error); return NULL; } else { Py_INCREF(Py_None); return Py_None; } } static char ssl_Context_set_verify_doc[] = "\n\ Set the verify mode and verify callback\n\ \n\ @param mode: The verify mode, this is either VERIFY_NONE or\n\ VERIFY_PEER combined with possible other flags\n\ @param callback: The Python callback to use\n\ @return: None\n\ \n\ See SSL_CTX_set_verify(3SSL) for further details.\n\ "; static PyObject * ssl_Context_set_verify(ssl_ContextObj *self, PyObject *args) { int mode; PyObject *callback = NULL; if (!PyArg_ParseTuple(args, "iO:set_verify", &mode, &callback)) return NULL; if (!PyCallable_Check(callback)) { PyErr_SetString(PyExc_TypeError, "expected PyCallable"); return NULL; } Py_DECREF(self->verify_callback); Py_INCREF(callback); self->verify_callback = callback; SSL_CTX_set_verify(self->ctx, mode, global_verify_callback); Py_INCREF(Py_None); return Py_None; } static char ssl_Context_set_verify_depth_doc[] = "\n\ Set the verify depth\n\ \n\ @param depth: An integer specifying the verify depth\n\ @return: None\n\ "; static PyObject * ssl_Context_set_verify_depth(ssl_ContextObj *self, PyObject *args) { int depth; if (!PyArg_ParseTuple(args, "i:set_verify_depth", &depth)) return NULL; SSL_CTX_set_verify_depth(self->ctx, depth); Py_INCREF(Py_None); return Py_None; } static char ssl_Context_get_verify_mode_doc[] = "\n\ Get the verify mode\n\ \n\ @return: The verify mode\n\ "; static PyObject * ssl_Context_get_verify_mode(ssl_ContextObj *self, PyObject *args) { int mode; if (!PyArg_ParseTuple(args, ":get_verify_mode")) return NULL; mode = SSL_CTX_get_verify_mode(self->ctx); return PyLong_FromLong((long)mode); } static char ssl_Context_get_verify_depth_doc[] = "\n\ Get the verify depth\n\ \n\ @return: The verify depth\n\ "; static PyObject * ssl_Context_get_verify_depth(ssl_ContextObj *self, PyObject *args) { int depth; if (!PyArg_ParseTuple(args, ":get_verify_depth")) return NULL; depth = SSL_CTX_get_verify_depth(self->ctx); return PyLong_FromLong((long)depth); } static char ssl_Context_load_tmp_dh_doc[] = "\n\ Load parameters for Ephemeral Diffie-Hellman\n\ \n\ @param dhfile: The file to load EDH parameters from\n\ @return: None\n\ "; static PyObject * ssl_Context_load_tmp_dh(ssl_ContextObj *self, PyObject *args) { char *dhfile; BIO *bio; DH *dh; if (!PyArg_ParseTuple(args, "s:load_tmp_dh", &dhfile)) return NULL; bio = BIO_new_file(dhfile, "r"); if (bio == NULL) { exception_from_error_queue(ssl_Error); return NULL; } dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); SSL_CTX_set_tmp_dh(self->ctx, dh); DH_free(dh); BIO_free(bio); Py_INCREF(Py_None); return Py_None; } static char ssl_Context_set_cipher_list_doc[] = "\n\ Change the cipher list\n\ \n\ @param cipher_list: A cipher list, see ciphers(1)\n\ @return: None\n\ "; static PyObject * ssl_Context_set_cipher_list(ssl_ContextObj *self, PyObject *args) { char *cipher_list; if (!PyArg_ParseTuple(args, "s:set_cipher_list", &cipher_list)) return NULL; if (!SSL_CTX_set_cipher_list(self->ctx, cipher_list)) { exception_from_error_queue(ssl_Error); return NULL; } else { Py_INCREF(Py_None); return Py_None; } } static char ssl_Context_set_client_ca_list_doc[] = "\n\ Set the list of preferred client certificate signers for this server context.\n\ \n\ This list of certificate authorities will be sent to the client when the\n\ server requests a client certificate.\n\ \n\ @param certificate_authorities: a sequence of X509Names.\n\ @return: None\n\ "; static PyObject * ssl_Context_set_client_ca_list(ssl_ContextObj *self, PyObject *args) { static PyTypeObject *X509NameType; PyObject *sequence, *tuple, *item; crypto_X509NameObj *name; X509_NAME *sslname; STACK_OF(X509_NAME) *CANames; Py_ssize_t length; int i; if (X509NameType == NULL) { X509NameType = import_crypto_type("X509Name", sizeof(crypto_X509NameObj)); if (X509NameType == NULL) { return NULL; } } if (!PyArg_ParseTuple(args, "O:set_client_ca_list", &sequence)) { return NULL; } tuple = PySequence_Tuple(sequence); if (tuple == NULL) { return NULL; } length = PyTuple_Size(tuple); if (length >= INT_MAX) { PyErr_SetString(PyExc_ValueError, "client CA list is too long"); Py_DECREF(tuple); return NULL; } CANames = sk_X509_NAME_new_null(); if (CANames == NULL) { Py_DECREF(tuple); exception_from_error_queue(ssl_Error); return NULL; } for (i = 0; i < length; i++) { item = PyTuple_GetItem(tuple, i); if (item->ob_type != X509NameType) { PyErr_Format(PyExc_TypeError, "client CAs must be X509Name objects, not %s objects", item->ob_type->tp_name); sk_X509_NAME_free(CANames); Py_DECREF(tuple); return NULL; } name = (crypto_X509NameObj *)item; sslname = X509_NAME_dup(name->x509_name); if (sslname == NULL) { sk_X509_NAME_free(CANames); Py_DECREF(tuple); exception_from_error_queue(ssl_Error); return NULL; } if (!sk_X509_NAME_push(CANames, sslname)) { X509_NAME_free(sslname); sk_X509_NAME_free(CANames); Py_DECREF(tuple); exception_from_error_queue(ssl_Error); return NULL; } } Py_DECREF(tuple); SSL_CTX_set_client_CA_list(self->ctx, CANames); Py_INCREF(Py_None); return Py_None; } static char ssl_Context_add_client_ca_doc[] = "\n\ Add the CA certificate to the list of preferred signers for this context.\n\ \n\ The list of certificate authorities will be sent to the client when the\n\ server requests a client certificate.\n\ \n\ @param certificate_authority: certificate authority's X509 certificate.\n\ @return: None\n\ "; static PyObject * ssl_Context_add_client_ca(ssl_ContextObj *self, PyObject *args) { crypto_X509Obj *cert; cert = parse_certificate_argument("O!:add_client_ca", args); if (cert == NULL) { return NULL; } if (!SSL_CTX_add_client_CA(self->ctx, cert->x509)) { exception_from_error_queue(ssl_Error); return NULL; } Py_INCREF(Py_None); return Py_None; } static char ssl_Context_set_timeout_doc[] = "\n\ Set session timeout\n\ \n\ @param timeout: The timeout in seconds\n\ @return: The previous session timeout\n\ "; static PyObject * ssl_Context_set_timeout(ssl_ContextObj *self, PyObject *args) { long t, ret; if (!PyArg_ParseTuple(args, "l:set_timeout", &t)) return NULL; ret = SSL_CTX_set_timeout(self->ctx, t); return PyLong_FromLong(ret); } static char ssl_Context_get_timeout_doc[] = "\n\ Get the session timeout\n\ \n\ @return: The session timeout\n\ "; static PyObject * ssl_Context_get_timeout(ssl_ContextObj *self, PyObject *args) { long ret; if (!PyArg_ParseTuple(args, ":get_timeout")) return NULL; ret = SSL_CTX_get_timeout(self->ctx); return PyLong_FromLong(ret); } static char ssl_Context_set_info_callback_doc[] = "\n\ Set the info callback\n\ \n\ @param callback: The Python callback to use\n\ @return: None\n\ "; static PyObject * ssl_Context_set_info_callback(ssl_ContextObj *self, PyObject *args) { PyObject *callback; if (!PyArg_ParseTuple(args, "O:set_info_callback", &callback)) return NULL; if (!PyCallable_Check(callback)) { PyErr_SetString(PyExc_TypeError, "expected PyCallable"); return NULL; } Py_DECREF(self->info_callback); Py_INCREF(callback); self->info_callback = callback; SSL_CTX_set_info_callback(self->ctx, global_info_callback); Py_INCREF(Py_None); return Py_None; } static char ssl_Context_get_app_data_doc[] = "\n\ Get the application data (supplied via set_app_data())\n\ \n\ @return: The application data\n\ "; static PyObject * ssl_Context_get_app_data(ssl_ContextObj *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":get_app_data")) return NULL; Py_INCREF(self->app_data); return self->app_data; } static char ssl_Context_set_app_data_doc[] = "\n\ Set the application data (will be returned from get_app_data())\n\ \n\ @param data: Any Python object\n\ @return: None\n\ "; static PyObject * ssl_Context_set_app_data(ssl_ContextObj *self, PyObject *args) { PyObject *data; if (!PyArg_ParseTuple(args, "O:set_app_data", &data)) return NULL; Py_DECREF(self->app_data); Py_INCREF(data); self->app_data = data; Py_INCREF(Py_None); return Py_None; } static char ssl_Context_get_cert_store_doc[] = "\n\ Get the certificate store for the context\n\ \n\ @return: A X509Store object\n\ "; static PyObject * ssl_Context_get_cert_store(ssl_ContextObj *self, PyObject *args) { X509_STORE *store; if (!PyArg_ParseTuple(args, ":get_cert_store")) return NULL; if ((store = SSL_CTX_get_cert_store(self->ctx)) == NULL) { Py_INCREF(Py_None); return Py_None; } else { return (PyObject *)new_x509store(store, 0); } } static char ssl_Context_set_options_doc[] = "\n\ Add options. Options set before are not cleared!\n\ \n\ @param options: The options to add.\n\ @return: The new option bitmask.\n\ "; static PyObject * ssl_Context_set_options(ssl_ContextObj *self, PyObject *args) { long options; if (!PyArg_ParseTuple(args, "l:set_options", &options)) return NULL; return PyLong_FromLong(SSL_CTX_set_options(self->ctx, options)); } static char ssl_Context_set_tlsext_servername_callback_doc[] = "\n\ Specify a callback function to be called when clients specify a server name.\n\ \n\ @param callback: The callback function. It will be invoked with one\n\ argument, the Connection instance.\n\ \n\ "; static PyObject * ssl_Context_set_tlsext_servername_callback(ssl_ContextObj *self, PyObject *args) { PyObject *callback; PyObject *old; if (!PyArg_ParseTuple(args, "O:set_tlsext_servername_callback", &callback)) { return NULL; } Py_INCREF(callback); old = self->tlsext_servername_callback; self->tlsext_servername_callback = callback; Py_DECREF(old); SSL_CTX_set_tlsext_servername_callback(self->ctx, global_tlsext_servername_callback); SSL_CTX_set_tlsext_servername_arg(self->ctx, NULL); Py_INCREF(Py_None); return Py_None; } /* * Member methods in the Context object * ADD_METHOD(name) expands to a correct PyMethodDef declaration * { 'name', (PyCFunction)ssl_Context_name, METH_VARARGS } * for convenience * ADD_ALIAS(name,real) creates an "alias" of the ssl_Context_real * function with the name 'name' */ #define ADD_METHOD(name) { #name, (PyCFunction)ssl_Context_##name, METH_VARARGS, ssl_Context_##name##_doc } static PyMethodDef ssl_Context_methods[] = { ADD_METHOD(load_verify_locations), ADD_METHOD(set_passwd_cb), ADD_METHOD(set_default_verify_paths), ADD_METHOD(use_certificate_chain_file), ADD_METHOD(use_certificate_file), ADD_METHOD(use_certificate), ADD_METHOD(add_extra_chain_cert), ADD_METHOD(use_privatekey_file), ADD_METHOD(use_privatekey), ADD_METHOD(check_privatekey), ADD_METHOD(load_client_ca), ADD_METHOD(set_session_id), ADD_METHOD(set_verify), ADD_METHOD(set_verify_depth), ADD_METHOD(get_verify_mode), ADD_METHOD(get_verify_depth), ADD_METHOD(load_tmp_dh), ADD_METHOD(set_cipher_list), ADD_METHOD(set_client_ca_list), ADD_METHOD(add_client_ca), ADD_METHOD(set_timeout), ADD_METHOD(get_timeout), ADD_METHOD(set_info_callback), ADD_METHOD(get_app_data), ADD_METHOD(set_app_data), ADD_METHOD(get_cert_store), ADD_METHOD(set_options), ADD_METHOD(set_tlsext_servername_callback), { NULL, NULL } }; #undef ADD_METHOD /* * Despite the name which might suggest otherwise, this is not the tp_init for * the Context type. It's just the common initialization code shared by the * two _{Nn}ew functions below. */ static ssl_ContextObj* ssl_Context_init(ssl_ContextObj *self, int i_method) { #if (OPENSSL_VERSION_NUMBER >> 28) == 0x01 const #endif SSL_METHOD *method; switch (i_method) { case ssl_SSLv2_METHOD: #ifdef OPENSSL_NO_SSL2 PyErr_SetString(PyExc_ValueError, "SSLv2_METHOD not supported by this version of OpenSSL"); return NULL; #else method = SSLv2_method(); #endif break; case ssl_SSLv23_METHOD: method = SSLv23_method(); break; case ssl_SSLv3_METHOD: method = SSLv3_method(); break; case ssl_TLSv1_METHOD: method = TLSv1_method(); break; default: PyErr_SetString(PyExc_ValueError, "No such protocol"); return NULL; } self->ctx = SSL_CTX_new(method); Py_INCREF(Py_None); self->passphrase_callback = Py_None; Py_INCREF(Py_None); self->verify_callback = Py_None; Py_INCREF(Py_None); self->info_callback = Py_None; Py_INCREF(Py_None); self->tlsext_servername_callback = Py_None; Py_INCREF(Py_None); self->passphrase_userdata = Py_None; Py_INCREF(Py_None); self->app_data = Py_None; /* Some initialization that's required to operate smoothly in Python */ SSL_CTX_set_app_data(self->ctx, self); SSL_CTX_set_mode(self->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_AUTO_RETRY); self->tstate = NULL; return self; } /* * This one is exposed in the CObject API. I want to deprecate it. */ ssl_ContextObj* ssl_Context_New(int i_method) { ssl_ContextObj *self; self = PyObject_GC_New(ssl_ContextObj, &ssl_Context_Type); if (self == NULL) { return (ssl_ContextObj *)PyErr_NoMemory(); } self = ssl_Context_init(self, i_method); PyObject_GC_Track((PyObject *)self); return self; } /* * This one is the tp_new of the Context type. It's great. */ static PyObject* ssl_Context_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) { int i_method; ssl_ContextObj *self; static char *kwlist[] = {"method", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:Context", kwlist, &i_method)) { return NULL; } self = (ssl_ContextObj *)subtype->tp_alloc(subtype, 1); if (self == NULL) { return NULL; } return (PyObject *)ssl_Context_init(self, i_method); } /* * Call the visitproc on all contained objects. * * Arguments: self - The Context object * visit - Function to call * arg - Extra argument to visit * Returns: 0 if all goes well, otherwise the return code from the first * call that gave non-zero result. */ static int ssl_Context_traverse(ssl_ContextObj *self, visitproc visit, void *arg) { int ret = 0; if (ret == 0 && self->passphrase_callback != NULL) ret = visit((PyObject *)self->passphrase_callback, arg); if (ret == 0 && self->passphrase_userdata != NULL) ret = visit((PyObject *)self->passphrase_userdata, arg); if (ret == 0 && self->verify_callback != NULL) ret = visit((PyObject *)self->verify_callback, arg); if (ret == 0 && self->info_callback != NULL) ret = visit((PyObject *)self->info_callback, arg); if (ret == 0 && self->app_data != NULL) ret = visit(self->app_data, arg); return ret; } /* * Decref all contained objects and zero the pointers. * * Arguments: self - The Context object * Returns: Always 0. */ static int ssl_Context_clear(ssl_ContextObj *self) { Py_XDECREF(self->passphrase_callback); self->passphrase_callback = NULL; Py_XDECREF(self->passphrase_userdata); self->passphrase_userdata = NULL; Py_XDECREF(self->verify_callback); self->verify_callback = NULL; Py_XDECREF(self->info_callback); self->info_callback = NULL; Py_XDECREF(self->app_data); self->app_data = NULL; return 0; } /* * Deallocate the memory used by the Context object * * Arguments: self - The Context object * Returns: None */ static void ssl_Context_dealloc(ssl_ContextObj *self) { PyObject_GC_UnTrack((PyObject *)self); SSL_CTX_free(self->ctx); ssl_Context_clear(self); PyObject_GC_Del(self); } PyTypeObject ssl_Context_Type = { PyOpenSSL_HEAD_INIT(&PyType_Type, 0) "OpenSSL.SSL.Context", sizeof(ssl_ContextObj), 0, (destructor)ssl_Context_dealloc, /* tp_dealloc */ NULL, /* print */ NULL, /* tp_getattr */ NULL, /* setattr */ NULL, /* compare */ NULL, /* repr */ NULL, /* as_number */ NULL, /* as_sequence */ NULL, /* as_mapping */ NULL, /* hash */ NULL, /* call */ NULL, /* str */ NULL, /* getattro */ NULL, /* setattro */ NULL, /* as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, /* tp_flags */ ssl_Context_doc, /* tp_doc */ (traverseproc)ssl_Context_traverse, /* tp_traverse */ (inquiry)ssl_Context_clear, /* tp_clear */ NULL, /* tp_richcompare */ 0, /* tp_weaklistoffset */ NULL, /* tp_iter */ NULL, /* tp_iternext */ ssl_Context_methods, /* tp_methods */ NULL, /* tp_members */ NULL, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ NULL, /* tp_descr_get */ NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ NULL, /* tp_init */ NULL, /* tp_alloc */ ssl_Context_new, /* tp_new */ }; /* * Initialize the Context part of the SSL sub module * * Arguments: dict - The OpenSSL.SSL module * Returns: 1 for success, 0 otherwise */ int init_ssl_context(PyObject *module) { if (PyType_Ready(&ssl_Context_Type) < 0) { return 0; } /* PyModule_AddObject steals a reference. */ Py_INCREF((PyObject *)&ssl_Context_Type); if (PyModule_AddObject(module, "Context", (PyObject *)&ssl_Context_Type) < 0) { return 0; } /* PyModule_AddObject steals a reference. */ Py_INCREF((PyObject *)&ssl_Context_Type); if (PyModule_AddObject(module, "ContextType", (PyObject *)&ssl_Context_Type) < 0) { return 0; } return 1; } pyOpenSSL-0.13/OpenSSL/ssl/context.h0000644000214500021450000000205311630175105017157 0ustar bb-slavebb-slave/* * context.h * * Copyright (C) AB Strakt * See LICENSE for details. * * Export SSL Context object data structures and functions. * See the file RATIONALE for a short explanation of why this module was written. * * Reviewed 2001-07-23 * */ #ifndef PyOpenSSL_SSL_CONTEXT_H_ #define PyOpenSSL_SSL_CONTEXT_H_ #include #include extern int init_ssl_context (PyObject *); extern PyTypeObject ssl_Context_Type; #define ssl_Context_Check(v) ((v)->ob_type == &ssl_Context_Type) typedef struct { PyObject_HEAD SSL_CTX *ctx; PyObject *passphrase_callback, *passphrase_userdata, *verify_callback, *info_callback, *tlsext_servername_callback, *app_data; PyThreadState *tstate; } ssl_ContextObj; #define ssl_SSLv2_METHOD (1) #define ssl_SSLv3_METHOD (2) #define ssl_SSLv23_METHOD (3) #define ssl_TLSv1_METHOD (4) #endif pyOpenSSL-0.13/OpenSSL/ssl/ssl.c0000644000214500021450000002611411630175105016273 0ustar bb-slavebb-slave/* * ssl.c * * Copyright (C) AB Strakt * Copyright (C) Jean-Paul Calderone * See LICENSE for details. * * Main file of the SSL sub module. * See the file RATIONALE for a short explanation of why this module was written. * * Reviewed 2001-07-23 */ #include #ifndef MS_WINDOWS # include # include # if !(defined(__BEOS__) || defined(__CYGWIN__)) # include # endif #else # include # include #endif #define SSL_MODULE #include "ssl.h" static char ssl_doc[] = "\n\ Main file of the SSL sub module.\n\ See the file RATIONALE for a short explanation of why this module was written.\n\ "; crypto_X509Obj* (*new_x509)(X509*, int); crypto_X509NameObj* (*new_x509name)(X509_NAME*, int); crypto_X509StoreObj* (*new_x509store)(X509_STORE*, int); #ifndef PY3 void **crypto_API; #endif int _pyOpenSSL_tstate_key; /* Exceptions defined by the SSL submodule */ PyObject *ssl_Error, /* Base class */ *ssl_ZeroReturnError, /* Used with SSL_get_error */ *ssl_WantReadError, /* ... */ *ssl_WantWriteError, /* ... */ *ssl_WantX509LookupError, /* ... */ *ssl_SysCallError; /* Uses (errno,errstr) */ static char ssl_SSLeay_version_doc[] = "\n\ Return a string describing the version of OpenSSL in use.\n\ \n\ @param type: One of the SSLEAY_ constants defined in this module.\n\ "; static PyObject * ssl_SSLeay_version(PyObject *spam, PyObject *args) { int t; const char *version; if (!PyArg_ParseTuple(args, "i:SSLeay_version", &t)) { return NULL; } version = SSLeay_version(t); return PyBytes_FromStringAndSize(version, strlen(version)); } /* Methods in the OpenSSL.SSL module */ static PyMethodDef ssl_methods[] = { { "SSLeay_version", ssl_SSLeay_version, METH_VARARGS, ssl_SSLeay_version_doc }, { NULL, NULL } }; #ifdef PY3 static struct PyModuleDef sslmodule = { PyModuleDef_HEAD_INIT, "SSL", ssl_doc, -1, ssl_methods }; #endif /* * Initialize SSL sub module * * Arguments: None * Returns: None */ PyOpenSSL_MODINIT(SSL) { PyObject *module; #ifndef PY3 static void *ssl_API[ssl_API_pointers]; PyObject *ssl_api_object; import_crypto(); new_x509 = crypto_X509_New; new_x509name = crypto_X509Name_New; new_x509store = crypto_X509Store_New; #else # ifdef _WIN32 HMODULE crypto = GetModuleHandle("crypto.pyd"); if (crypto == NULL) { PyErr_SetString(PyExc_RuntimeError, "Unable to get crypto module"); PyOpenSSL_MODRETURN(NULL); } new_x509 = (crypto_X509Obj* (*)(X509*, int))GetProcAddress(crypto, "crypto_X509_New"); new_x509name = (crypto_X509NameObj* (*)(X509_NAME*, int))GetProcAddress(crypto, "crypto_X509Name_New"); new_x509store = (crypto_X509StoreObj* (*)(X509_STORE*, int))GetProcAddress(crypto, "crypto_X509Store_New"); # else new_x509 = crypto_X509_New; new_x509name = crypto_X509Name_New; new_x509store = crypto_X509Store_New; # endif #endif SSL_library_init(); ERR_load_SSL_strings(); #ifdef PY3 module = PyModule_Create(&sslmodule); #else module = Py_InitModule3("SSL", ssl_methods, ssl_doc); #endif if (module == NULL) { PyOpenSSL_MODRETURN(NULL); } #ifndef PY3 /* Initialize the C API pointer array */ ssl_API[ssl_Context_New_NUM] = (void *)ssl_Context_New; ssl_API[ssl_Connection_New_NUM] = (void *)ssl_Connection_New; ssl_api_object = PyCObject_FromVoidPtr((void *)ssl_API, NULL); if (ssl_api_object != NULL) { /* PyModule_AddObject steals a reference. */ Py_INCREF(ssl_api_object); PyModule_AddObject(module, "_C_API", ssl_api_object); } #endif /* Exceptions */ /* * ADD_EXCEPTION(dict,name,base) expands to a correct Exception declaration, * inserting OpenSSL.SSL.name into dict, derviving the exception from base. */ #define ADD_EXCEPTION(_name, _base) \ do { \ ssl_##_name = PyErr_NewException("OpenSSL.SSL."#_name, _base, NULL);\ if (ssl_##_name == NULL) \ goto error; \ /* PyModule_AddObject steals a reference. */ \ Py_INCREF(ssl_##_name); \ if (PyModule_AddObject(module, #_name, ssl_##_name) != 0) \ goto error; \ } while (0) ssl_Error = PyErr_NewException("OpenSSL.SSL.Error", NULL, NULL); if (ssl_Error == NULL) { goto error; } /* PyModule_AddObject steals a reference. */ Py_INCREF(ssl_Error); if (PyModule_AddObject(module, "Error", ssl_Error) != 0) goto error; ADD_EXCEPTION(ZeroReturnError, ssl_Error); ADD_EXCEPTION(WantReadError, ssl_Error); ADD_EXCEPTION(WantWriteError, ssl_Error); ADD_EXCEPTION(WantX509LookupError, ssl_Error); ADD_EXCEPTION(SysCallError, ssl_Error); #undef ADD_EXCEPTION /* Method constants */ PyModule_AddIntConstant(module, "SSLv2_METHOD", ssl_SSLv2_METHOD); PyModule_AddIntConstant(module, "SSLv3_METHOD", ssl_SSLv3_METHOD); PyModule_AddIntConstant(module, "SSLv23_METHOD", ssl_SSLv23_METHOD); PyModule_AddIntConstant(module, "TLSv1_METHOD", ssl_TLSv1_METHOD); /* Verify constants */ PyModule_AddIntConstant(module, "VERIFY_NONE", SSL_VERIFY_NONE); PyModule_AddIntConstant(module, "VERIFY_PEER", SSL_VERIFY_PEER); PyModule_AddIntConstant(module, "VERIFY_FAIL_IF_NO_PEER_CERT", SSL_VERIFY_FAIL_IF_NO_PEER_CERT); PyModule_AddIntConstant(module, "VERIFY_CLIENT_ONCE", SSL_VERIFY_CLIENT_ONCE); /* File type constants */ PyModule_AddIntConstant(module, "FILETYPE_PEM", SSL_FILETYPE_PEM); PyModule_AddIntConstant(module, "FILETYPE_ASN1", SSL_FILETYPE_ASN1); /* SSL option constants */ PyModule_AddIntConstant(module, "OP_SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE); PyModule_AddIntConstant(module, "OP_EPHEMERAL_RSA", SSL_OP_EPHEMERAL_RSA); PyModule_AddIntConstant(module, "OP_NO_SSLv2", SSL_OP_NO_SSLv2); PyModule_AddIntConstant(module, "OP_NO_SSLv3", SSL_OP_NO_SSLv3); PyModule_AddIntConstant(module, "OP_NO_TLSv1", SSL_OP_NO_TLSv1); /* More SSL option constants */ PyModule_AddIntConstant(module, "OP_MICROSOFT_SESS_ID_BUG", SSL_OP_MICROSOFT_SESS_ID_BUG); PyModule_AddIntConstant(module, "OP_NETSCAPE_CHALLENGE_BUG", SSL_OP_NETSCAPE_CHALLENGE_BUG); PyModule_AddIntConstant(module, "OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG); PyModule_AddIntConstant(module, "OP_SSLREF2_REUSE_CERT_TYPE_BUG", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG); PyModule_AddIntConstant(module, "OP_MICROSOFT_BIG_SSLV3_BUFFER", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER); PyModule_AddIntConstant(module, "OP_MSIE_SSLV2_RSA_PADDING", SSL_OP_MSIE_SSLV2_RSA_PADDING); PyModule_AddIntConstant(module, "OP_SSLEAY_080_CLIENT_DH_BUG", SSL_OP_SSLEAY_080_CLIENT_DH_BUG); PyModule_AddIntConstant(module, "OP_TLS_D5_BUG", SSL_OP_TLS_D5_BUG); PyModule_AddIntConstant(module, "OP_TLS_BLOCK_PADDING_BUG", SSL_OP_TLS_BLOCK_PADDING_BUG); PyModule_AddIntConstant(module, "OP_DONT_INSERT_EMPTY_FRAGMENTS", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); PyModule_AddIntConstant(module, "OP_ALL", SSL_OP_ALL); PyModule_AddIntConstant(module, "OP_CIPHER_SERVER_PREFERENCE", SSL_OP_CIPHER_SERVER_PREFERENCE); PyModule_AddIntConstant(module, "OP_TLS_ROLLBACK_BUG", SSL_OP_TLS_ROLLBACK_BUG); PyModule_AddIntConstant(module, "OP_PKCS1_CHECK_1", SSL_OP_PKCS1_CHECK_1); PyModule_AddIntConstant(module, "OP_PKCS1_CHECK_2", SSL_OP_PKCS1_CHECK_2); PyModule_AddIntConstant(module, "OP_NETSCAPE_CA_DN_BUG", SSL_OP_NETSCAPE_CA_DN_BUG); PyModule_AddIntConstant(module, "OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG); /* DTLS related options. The first two of these were introduced in * 2005, the third in 2007. To accomodate systems which are still using * older versions, make them optional. */ #ifdef SSL_OP_NO_QUERY_MTU PyModule_AddIntConstant(module, "OP_NO_QUERY_MTU", SSL_OP_NO_QUERY_MTU); #endif #ifdef SSL_OP_COOKIE_EXCHANGE PyModule_AddIntConstant(module, "OP_COOKIE_EXCHANGE", SSL_OP_COOKIE_EXCHANGE); #endif #ifdef SSL_OP_NO_TICKET PyModule_AddIntConstant(module, "OP_NO_TICKET", SSL_OP_NO_TICKET); #endif /* For SSL_set_shutdown */ PyModule_AddIntConstant(module, "SENT_SHUTDOWN", SSL_SENT_SHUTDOWN); PyModule_AddIntConstant(module, "RECEIVED_SHUTDOWN", SSL_RECEIVED_SHUTDOWN); /* For set_info_callback */ PyModule_AddIntConstant(module, "SSL_ST_CONNECT", SSL_ST_CONNECT); PyModule_AddIntConstant(module, "SSL_ST_ACCEPT", SSL_ST_ACCEPT); PyModule_AddIntConstant(module, "SSL_ST_MASK", SSL_ST_MASK); PyModule_AddIntConstant(module, "SSL_ST_INIT", SSL_ST_INIT); PyModule_AddIntConstant(module, "SSL_ST_BEFORE", SSL_ST_BEFORE); PyModule_AddIntConstant(module, "SSL_ST_OK", SSL_ST_OK); PyModule_AddIntConstant(module, "SSL_ST_RENEGOTIATE", SSL_ST_RENEGOTIATE); PyModule_AddIntConstant(module, "SSL_CB_LOOP", SSL_CB_LOOP); PyModule_AddIntConstant(module, "SSL_CB_EXIT", SSL_CB_EXIT); PyModule_AddIntConstant(module, "SSL_CB_READ", SSL_CB_READ); PyModule_AddIntConstant(module, "SSL_CB_WRITE", SSL_CB_WRITE); PyModule_AddIntConstant(module, "SSL_CB_ALERT", SSL_CB_ALERT); PyModule_AddIntConstant(module, "SSL_CB_READ_ALERT", SSL_CB_READ_ALERT); PyModule_AddIntConstant(module, "SSL_CB_WRITE_ALERT", SSL_CB_WRITE_ALERT); PyModule_AddIntConstant(module, "SSL_CB_ACCEPT_LOOP", SSL_CB_ACCEPT_LOOP); PyModule_AddIntConstant(module, "SSL_CB_ACCEPT_EXIT", SSL_CB_ACCEPT_EXIT); PyModule_AddIntConstant(module, "SSL_CB_CONNECT_LOOP", SSL_CB_CONNECT_LOOP); PyModule_AddIntConstant(module, "SSL_CB_CONNECT_EXIT", SSL_CB_CONNECT_EXIT); PyModule_AddIntConstant(module, "SSL_CB_HANDSHAKE_START", SSL_CB_HANDSHAKE_START); PyModule_AddIntConstant(module, "SSL_CB_HANDSHAKE_DONE", SSL_CB_HANDSHAKE_DONE); /* Version information indicators, used with SSLeay_version */ PyModule_AddIntConstant(module, "SSLEAY_VERSION", SSLEAY_VERSION); PyModule_AddIntConstant(module, "SSLEAY_CFLAGS", SSLEAY_CFLAGS); PyModule_AddIntConstant(module, "SSLEAY_BUILT_ON", SSLEAY_BUILT_ON); PyModule_AddIntConstant(module, "SSLEAY_PLATFORM", SSLEAY_PLATFORM); PyModule_AddIntConstant(module, "SSLEAY_DIR", SSLEAY_DIR); /* Straight up version number */ PyModule_AddIntConstant(module, "OPENSSL_VERSION_NUMBER", OPENSSL_VERSION_NUMBER); if (!init_ssl_context(module)) goto error; if (!init_ssl_connection(module)) goto error; #ifdef WITH_THREAD /* * Initialize this module's threading support structures. */ _pyOpenSSL_tstate_key = PyThread_create_key(); #endif PyOpenSSL_MODRETURN(module); error: PyOpenSSL_MODRETURN(NULL); ; } pyOpenSSL-0.13/OpenSSL/ssl/ssl.h0000644000214500021450000000443611630175105016303 0ustar bb-slavebb-slave/* * ssl.h * * Copyright (C) AB Strakt * See LICENSE for details. * * Export functions and exceptions from the SSL sub module. * See the file RATIONALE for a short explanation of why this module was written. * * Reviewed 2001-07-23 * */ #ifndef PyOpenSSL_SSL_H_ #define PyOpenSSL_SSL_H_ #include #include #include "context.h" #include "connection.h" #include "../util.h" #include "../crypto/crypto.h" extern PyObject *ssl_Error, /* Base class */ *ssl_ZeroReturnError, /* Used with SSL_get_erorr */ *ssl_WantReadError, /* ... */ *ssl_WantWriteError, /* ... */ *ssl_WantX509LookupError, /* ... */ *ssl_SysCallError; /* Uses (errno,errstr) */ #define ssl_Context_New_NUM 0 #define ssl_Context_New_RETURN ssl_ContextObj * #define ssl_Context_New_PROTO (int method) #define ssl_Connection_New_NUM 1 #define ssl_Connection_New_RETURN ssl_ConnectionObj * #define ssl_Connection_New_PROTO (ssl_ContextObj *ctx, PyObject *sock) #define ssl_API_pointers 2 #ifdef WITH_THREAD extern int _pyOpenSSL_tstate_key; #endif /* WITH_THREAD */ #ifdef SSL_MODULE extern ssl_Context_New_RETURN ssl_Context_New ssl_Context_New_PROTO; extern ssl_Connection_New_RETURN ssl_Connection_New ssl_Connection_New_PROTO; extern crypto_X509Obj* (*new_x509)(X509*, int); extern crypto_X509NameObj* (*new_x509name)(X509_NAME*, int); extern crypto_X509StoreObj* (*new_x509store)(X509_STORE*, int); #else /* SSL_MODULE */ extern void **ssl_API; #define ssl_Context_New \ (*(ssl_Context_New_RETURN (*)ssl_Context_New_PROTO) ssl_API[ssl_Context_New_NUM]) #define ssl_Connection_New \ (*(ssl_Connection_New_RETURN (*)ssl_Connection_New_PROTO) ssl_API[ssl_Connection_New_NUM]) #define import_SSL() \ { \ PyObject *module = PyImport_ImportModule("OpenSSL.SSL"); \ if (module != NULL) { \ PyObject *module_dict = PyModule_GetDict(module); \ PyObject *c_api_object = PyDict_GetItemString(module_dict, "_C_API"); \ if (PyCObject_Check(c_api_object)) { \ ssl_API = (void **)PyCObject_AsVoidPtr(c_api_object); \ } \ } \ } #endif /* SSL_MODULE */ #endif /* PyOpenSSL_SSL_H_ */ pyOpenSSL-0.13/OpenSSL/test/0000755000214500021450000000000011630175113015477 5ustar bb-slavebb-slavepyOpenSSL-0.13/OpenSSL/test/__init__.py0000644000214500021450000000016611630175105017614 0ustar bb-slavebb-slave# Copyright (C) Jean-Paul Calderone # See LICENSE for details. """ Package containing unit tests for L{OpenSSL}. """ pyOpenSSL-0.13/OpenSSL/test/test_crypto.py0000644000214500021450000030657511630175105020451 0ustar bb-slavebb-slave# Copyright (c) Jean-Paul Calderone # See LICENSE file for details. """ Unit tests for L{OpenSSL.crypto}. """ from unittest import main import os, re from subprocess import PIPE, Popen from datetime import datetime, timedelta from OpenSSL.crypto import TYPE_RSA, TYPE_DSA, Error, PKey, PKeyType from OpenSSL.crypto import X509, X509Type, X509Name, X509NameType from OpenSSL.crypto import X509Req, X509ReqType from OpenSSL.crypto import X509Extension, X509ExtensionType from OpenSSL.crypto import load_certificate, load_privatekey from OpenSSL.crypto import FILETYPE_PEM, FILETYPE_ASN1, FILETYPE_TEXT from OpenSSL.crypto import dump_certificate, load_certificate_request from OpenSSL.crypto import dump_certificate_request, dump_privatekey from OpenSSL.crypto import PKCS7Type, load_pkcs7_data from OpenSSL.crypto import PKCS12, PKCS12Type, load_pkcs12 from OpenSSL.crypto import CRL, Revoked, load_crl from OpenSSL.crypto import NetscapeSPKI, NetscapeSPKIType from OpenSSL.crypto import sign, verify from OpenSSL.test.util import TestCase, bytes, b def normalize_certificate_pem(pem): return dump_certificate(FILETYPE_PEM, load_certificate(FILETYPE_PEM, pem)) def normalize_privatekey_pem(pem): return dump_privatekey(FILETYPE_PEM, load_privatekey(FILETYPE_PEM, pem)) root_cert_pem = b("""-----BEGIN CERTIFICATE----- MIIC7TCCAlagAwIBAgIIPQzE4MbeufQwDQYJKoZIhvcNAQEFBQAwWDELMAkGA1UE BhMCVVMxCzAJBgNVBAgTAklMMRAwDgYDVQQHEwdDaGljYWdvMRAwDgYDVQQKEwdU ZXN0aW5nMRgwFgYDVQQDEw9UZXN0aW5nIFJvb3QgQ0EwIhgPMjAwOTAzMjUxMjM2 NThaGA8yMDE3MDYxMTEyMzY1OFowWDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAklM MRAwDgYDVQQHEwdDaGljYWdvMRAwDgYDVQQKEwdUZXN0aW5nMRgwFgYDVQQDEw9U ZXN0aW5nIFJvb3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPmaQumL urpE527uSEHdL1pqcDRmWzu+98Y6YHzT/J7KWEamyMCNZ6fRW1JCR782UQ8a07fy 2xXsKy4WdKaxyG8CcatwmXvpvRQ44dSANMihHELpANTdyVp6DCysED6wkQFurHlF 1dshEaJw8b/ypDhmbVIo6Ci1xvCJqivbLFnbAgMBAAGjgbswgbgwHQYDVR0OBBYE FINVdy1eIfFJDAkk51QJEo3IfgSuMIGIBgNVHSMEgYAwfoAUg1V3LV4h8UkMCSTn VAkSjch+BK6hXKRaMFgxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UE BxMHQ2hpY2FnbzEQMA4GA1UEChMHVGVzdGluZzEYMBYGA1UEAxMPVGVzdGluZyBS b290IENBggg9DMTgxt659DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GB AGGCDazMJGoWNBpc03u6+smc95dEead2KlZXBATOdFT1VesY3+nUOqZhEhTGlDMi hkgaZnzoIq/Uamidegk4hirsCT/R+6vsKAAxNTcBjUeZjlykCJWy5ojShGftXIKY w/njVbKMXrvc83qmTdGl3TAM0fxQIpqgcglFLveEBgzn -----END CERTIFICATE----- """) root_key_pem = b("""-----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQD5mkLpi7q6ROdu7khB3S9aanA0Zls7vvfGOmB80/yeylhGpsjA jWen0VtSQke/NlEPGtO38tsV7CsuFnSmschvAnGrcJl76b0UOOHUgDTIoRxC6QDU 3claegwsrBA+sJEBbqx5RdXbIRGicPG/8qQ4Zm1SKOgotcbwiaor2yxZ2wIDAQAB AoGBAPCgMpmLxzwDaUmcFbTJUvlLW1hoxNNYSu2jIZm1k/hRAcE60JYwvBkgz3UB yMEh0AtLxYe0bFk6EHah11tMUPgscbCq73snJ++8koUw+csk22G65hOs51bVb7Aa 6JBe67oLzdtvgCUFAA2qfrKzWRZzAdhUirQUZgySZk+Xq1pBAkEA/kZG0A6roTSM BVnx7LnPfsycKUsTumorpXiylZJjTi9XtmzxhrYN6wgZlDOOwOLgSQhszGpxVoMD u3gByT1b2QJBAPtL3mSKdvwRu/+40zaZLwvSJRxaj0mcE4BJOS6Oqs/hS1xRlrNk PpQ7WJ4yM6ZOLnXzm2mKyxm50Mv64109FtMCQQDOqS2KkjHaLowTGVxwC0DijMfr I9Lf8sSQk32J5VWCySWf5gGTfEnpmUa41gKTMJIbqZZLucNuDcOtzUaeWZlZAkA8 ttXigLnCqR486JDPTi9ZscoZkZ+w7y6e/hH8t6d5Vjt48JVyfjPIaJY+km58LcN3 6AWSeGAdtRFHVzR7oHjVAkB4hutvxiOeiIVQNBhM6RSI9aBPMI21DoX2JRoxvNW2 cbvAhow217X9V0dVerEOKxnNYspXRrh36h7k4mQA+sDq -----END RSA PRIVATE KEY----- """) server_cert_pem = b("""-----BEGIN CERTIFICATE----- MIICKDCCAZGgAwIBAgIJAJn/HpR21r/8MA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV BAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UEBxMHQ2hpY2FnbzEQMA4GA1UEChMH VGVzdGluZzEYMBYGA1UEAxMPVGVzdGluZyBSb290IENBMCIYDzIwMDkwMzI1MTIz NzUzWhgPMjAxNzA2MTExMjM3NTNaMBgxFjAUBgNVBAMTDWxvdmVseSBzZXJ2ZXIw gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAL6m+G653V0tpBC/OKl22VxOi2Cv lK4TYu9LHSDP9uDVTe7V5D5Tl6qzFoRRx5pfmnkqT5B+W9byp2NU3FC5hLm5zSAr b45meUhjEJ/ifkZgbNUjHdBIGP9MAQUHZa5WKdkGIJvGAvs8UzUqlr4TBWQIB24+ lJ+Ukk/CRgasrYwdAgMBAAGjNjA0MB0GA1UdDgQWBBS4kC7Ij0W1TZXZqXQFAM2e gKEG2DATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQUFAAOBgQBh30Li dJ+NlxIOx5343WqIBka3UbsOb2kxWrbkVCrvRapCMLCASO4FqiKWM+L0VDBprqIp 2mgpFQ6FHpoIENGvJhdEKpptQ5i7KaGhnDNTfdy3x1+h852G99f1iyj0RmbuFcM8 uzujnS8YXWvM7DM1Ilozk4MzPug8jzFp5uhKCQ== -----END CERTIFICATE----- """) server_key_pem = normalize_privatekey_pem(b("""-----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgQC+pvhuud1dLaQQvzipdtlcTotgr5SuE2LvSx0gz/bg1U3u1eQ+ U5eqsxaEUceaX5p5Kk+QflvW8qdjVNxQuYS5uc0gK2+OZnlIYxCf4n5GYGzVIx3Q SBj/TAEFB2WuVinZBiCbxgL7PFM1Kpa+EwVkCAduPpSflJJPwkYGrK2MHQIDAQAB AoGAbwuZ0AR6JveahBaczjfnSpiFHf+mve2UxoQdpyr6ROJ4zg/PLW5K/KXrC48G j6f3tXMrfKHcpEoZrQWUfYBRCUsGD5DCazEhD8zlxEHahIsqpwA0WWssJA2VOLEN j6DuV2pCFbw67rfTBkTSo32ahfXxEKev5KswZk0JIzH3ooECQQDgzS9AI89h0gs8 Dt+1m11Rzqo3vZML7ZIyGApUzVan+a7hbc33nbGRkAXjHaUBJO31it/H6dTO+uwX msWwNG5ZAkEA2RyFKs5xR5USTFaKLWCgpH/ydV96KPOpBND7TKQx62snDenFNNbn FwwOhpahld+vqhYk+pfuWWUpQciE+Bu7ZQJASjfT4sQv4qbbKK/scePicnDdx9th 4e1EeB9xwb+tXXXUo/6Bor/AcUNwfiQ6Zt9PZOK9sR3lMZSsP7rMi7kzuQJABie6 1sXXjFH7nNJvRG4S39cIxq8YRYTy68II/dlB2QzGpKxV/POCxbJ/zu0CU79tuYK7 NaeNCFfH3aeTrX0LyQJAMBWjWmeKM2G2sCExheeQK0ROnaBC8itCECD4Jsve4nqf r50+LF74iLXFwqysVCebPKMOpDWp/qQ1BbJQIPs7/A== -----END RSA PRIVATE KEY----- """)) client_cert_pem = b("""-----BEGIN CERTIFICATE----- MIICJjCCAY+gAwIBAgIJAKxpFI5lODkjMA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV BAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UEBxMHQ2hpY2FnbzEQMA4GA1UEChMH VGVzdGluZzEYMBYGA1UEAxMPVGVzdGluZyBSb290IENBMCIYDzIwMDkwMzI1MTIz ODA1WhgPMjAxNzA2MTExMjM4MDVaMBYxFDASBgNVBAMTC3VnbHkgY2xpZW50MIGf MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAZh/SRtNm5ntMT4qb6YzEpTroMlq2 rn+GrRHRiZ+xkCw/CGNhbtPir7/QxaUj26BSmQrHw1bGKEbPsWiW7bdXSespl+xK iku4G/KvnnmWdeJHqsiXeUZtqurMELcPQAw9xPHEuhqqUJvvEoMTsnCEqGM+7Dtb oCRajYyHfluARQIDAQABozYwNDAdBgNVHQ4EFgQUNQB+qkaOaEVecf1J3TTUtAff 0fAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQEFBQADgYEAyv/Jh7gM Q3OHvmsFEEvRI+hsW8y66zK4K5de239Y44iZrFYkt7Q5nBPMEWDj4F2hLYWL/qtI 9Zdr0U4UDCU9SmmGYh4o7R4TZ5pGFvBYvjhHbkSFYFQXZxKUi+WUxplP6I0wr2KJ PSTJCjJOn3xo2NTKRgV1gaoTf2EhL+RG8TQ= -----END CERTIFICATE----- """) client_key_pem = normalize_privatekey_pem(b("""-----BEGIN RSA PRIVATE KEY----- MIICXgIBAAKBgQDAZh/SRtNm5ntMT4qb6YzEpTroMlq2rn+GrRHRiZ+xkCw/CGNh btPir7/QxaUj26BSmQrHw1bGKEbPsWiW7bdXSespl+xKiku4G/KvnnmWdeJHqsiX eUZtqurMELcPQAw9xPHEuhqqUJvvEoMTsnCEqGM+7DtboCRajYyHfluARQIDAQAB AoGATkZ+NceY5Glqyl4mD06SdcKfV65814vg2EL7V9t8+/mi9rYL8KztSXGlQWPX zuHgtRoMl78yQ4ZJYOBVo+nsx8KZNRCEBlE19bamSbQLCeQMenWnpeYyQUZ908gF h6L9qsFVJepgA9RDgAjyDoS5CaWCdCCPCH2lDkdcqC54SVUCQQDseuduc4wi8h4t V8AahUn9fn9gYfhoNuM0gdguTA0nPLVWz4hy1yJiWYQe0H7NLNNTmCKiLQaJpAbb TC6vE8C7AkEA0Ee8CMJUc20BnGEmxwgWcVuqFWaKCo8jTH1X38FlATUsyR3krjW2 dL3yDD9NwHxsYP7nTKp/U8MV7U9IBn4y/wJBAJl7H0/BcLeRmuJk7IqJ7b635iYB D/9beFUw3MUXmQXZUfyYz39xf6CDZsu1GEdEC5haykeln3Of4M9d/4Kj+FcCQQCY si6xwT7GzMDkk/ko684AV3KPc/h6G0yGtFIrMg7J3uExpR/VdH2KgwMkZXisSMvw JJEQjOMCVsEJlRk54WWjAkEAzoZNH6UhDdBK5F38rVt/y4SEHgbSfJHIAmPS32Kq f6GGcfNpip0Uk7q7udTKuX7Q/buZi/C4YW7u3VKAquv9NA== -----END RSA PRIVATE KEY----- """)) cleartextCertificatePEM = b("""-----BEGIN CERTIFICATE----- MIIC7TCCAlagAwIBAgIIPQzE4MbeufQwDQYJKoZIhvcNAQEFBQAwWDELMAkGA1UE BhMCVVMxCzAJBgNVBAgTAklMMRAwDgYDVQQHEwdDaGljYWdvMRAwDgYDVQQKEwdU ZXN0aW5nMRgwFgYDVQQDEw9UZXN0aW5nIFJvb3QgQ0EwIhgPMjAwOTAzMjUxMjM2 NThaGA8yMDE3MDYxMTEyMzY1OFowWDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAklM MRAwDgYDVQQHEwdDaGljYWdvMRAwDgYDVQQKEwdUZXN0aW5nMRgwFgYDVQQDEw9U ZXN0aW5nIFJvb3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPmaQumL urpE527uSEHdL1pqcDRmWzu+98Y6YHzT/J7KWEamyMCNZ6fRW1JCR782UQ8a07fy 2xXsKy4WdKaxyG8CcatwmXvpvRQ44dSANMihHELpANTdyVp6DCysED6wkQFurHlF 1dshEaJw8b/ypDhmbVIo6Ci1xvCJqivbLFnbAgMBAAGjgbswgbgwHQYDVR0OBBYE FINVdy1eIfFJDAkk51QJEo3IfgSuMIGIBgNVHSMEgYAwfoAUg1V3LV4h8UkMCSTn VAkSjch+BK6hXKRaMFgxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UE BxMHQ2hpY2FnbzEQMA4GA1UEChMHVGVzdGluZzEYMBYGA1UEAxMPVGVzdGluZyBS b290IENBggg9DMTgxt659DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GB AGGCDazMJGoWNBpc03u6+smc95dEead2KlZXBATOdFT1VesY3+nUOqZhEhTGlDMi hkgaZnzoIq/Uamidegk4hirsCT/R+6vsKAAxNTcBjUeZjlykCJWy5ojShGftXIKY w/njVbKMXrvc83qmTdGl3TAM0fxQIpqgcglFLveEBgzn -----END CERTIFICATE----- """) cleartextPrivateKeyPEM = normalize_privatekey_pem(b("""\ -----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQD5mkLpi7q6ROdu7khB3S9aanA0Zls7vvfGOmB80/yeylhGpsjA jWen0VtSQke/NlEPGtO38tsV7CsuFnSmschvAnGrcJl76b0UOOHUgDTIoRxC6QDU 3claegwsrBA+sJEBbqx5RdXbIRGicPG/8qQ4Zm1SKOgotcbwiaor2yxZ2wIDAQAB AoGBAPCgMpmLxzwDaUmcFbTJUvlLW1hoxNNYSu2jIZm1k/hRAcE60JYwvBkgz3UB yMEh0AtLxYe0bFk6EHah11tMUPgscbCq73snJ++8koUw+csk22G65hOs51bVb7Aa 6JBe67oLzdtvgCUFAA2qfrKzWRZzAdhUirQUZgySZk+Xq1pBAkEA/kZG0A6roTSM BVnx7LnPfsycKUsTumorpXiylZJjTi9XtmzxhrYN6wgZlDOOwOLgSQhszGpxVoMD u3gByT1b2QJBAPtL3mSKdvwRu/+40zaZLwvSJRxaj0mcE4BJOS6Oqs/hS1xRlrNk PpQ7WJ4yM6ZOLnXzm2mKyxm50Mv64109FtMCQQDOqS2KkjHaLowTGVxwC0DijMfr I9Lf8sSQk32J5VWCySWf5gGTfEnpmUa41gKTMJIbqZZLucNuDcOtzUaeWZlZAkA8 ttXigLnCqR486JDPTi9ZscoZkZ+w7y6e/hH8t6d5Vjt48JVyfjPIaJY+km58LcN3 6AWSeGAdtRFHVzR7oHjVAkB4hutvxiOeiIVQNBhM6RSI9aBPMI21DoX2JRoxvNW2 cbvAhow217X9V0dVerEOKxnNYspXRrh36h7k4mQA+sDq -----END RSA PRIVATE KEY----- """)) cleartextCertificateRequestPEM = b("""-----BEGIN CERTIFICATE REQUEST----- MIIBnjCCAQcCAQAwXjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAklMMRAwDgYDVQQH EwdDaGljYWdvMRcwFQYDVQQKEw5NeSBDb21wYW55IEx0ZDEXMBUGA1UEAxMORnJl ZGVyaWNrIERlYW4wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANp6Y17WzKSw BsUWkXdqg6tnXy8H8hA1msCMWpc+/2KJ4mbv5NyD6UD+/SqagQqulPbF/DFea9nA E0zhmHJELcM8gUTIlXv/cgDWnmK4xj8YkjVUiCdqKRAKeuzLG1pGmwwF5lGeJpXN xQn5ecR0UYSOWj6TTGXB9VyUMQzCClcBAgMBAAGgADANBgkqhkiG9w0BAQUFAAOB gQAAJGuF/R/GGbeC7FbFW+aJgr9ee0Xbl6nlhu7pTe67k+iiKT2dsl2ti68MVTnu Vrb3HUNqOkiwsJf6kCtq5oPn3QVYzTa76Dt2y3Rtzv6boRSlmlfrgS92GNma8JfR oICQk3nAudi6zl1Dix3BCv1pUp5KMtGn3MeDEi6QFGy2rA== -----END CERTIFICATE REQUEST----- """) encryptedPrivateKeyPEM = b("""-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,9573604A18579E9E SHOho56WxDkT0ht10UTeKc0F5u8cqIa01kzFAmETw0MAs8ezYtK15NPdCXUm3X/2 a17G7LSF5bkxOgZ7vpXyMzun/owrj7CzvLxyncyEFZWvtvzaAhPhvTJtTIB3kf8B 8+qRcpTGK7NgXEgYBW5bj1y4qZkD4zCL9o9NQzsKI3Ie8i0239jsDOWR38AxjXBH mGwAQ4Z6ZN5dnmM4fhMIWsmFf19sNyAML4gHenQCHhmXbjXeVq47aC2ProInJbrm +00TcisbAQ40V9aehVbcDKtS4ZbMVDwncAjpXpcncC54G76N6j7F7wL7L/FuXa3A fvSVy9n2VfF/pJ3kYSflLHH2G/DFxjF7dl0GxhKPxJjp3IJi9VtuvmN9R2jZWLQF tfC8dXgy/P9CfFQhlinqBTEwgH0oZ/d4k4NVFDSdEMaSdmBAjlHpc+Vfdty3HVnV rKXj//wslsFNm9kIwJGIgKUa/n2jsOiydrsk1mgH7SmNCb3YHgZhbbnq0qLat/HC gHDt3FHpNQ31QzzL3yrenFB2L9osIsnRsDTPFNi4RX4SpDgNroxOQmyzCCV6H+d4 o1mcnNiZSdxLZxVKccq0AfRpHqpPAFnJcQHP6xyT9MZp6fBa0XkxDnt9kNU8H3Qw 7SJWZ69VXjBUzMlQViLuaWMgTnL+ZVyFZf9hTF7U/ef4HMLMAVNdiaGG+G+AjCV/ MbzjS007Oe4qqBnCWaFPSnJX6uLApeTbqAxAeyCql56ULW5x6vDMNC3dwjvS/CEh 11n8RkgFIQA0AhuKSIg3CbuartRsJnWOLwgLTzsrKYL4yRog1RJrtw== -----END RSA PRIVATE KEY----- """) encryptedPrivateKeyPEMPassphrase = b("foobar") # Some PKCS#7 stuff. Generated with the openssl command line: # # openssl crl2pkcs7 -inform pem -outform pem -certfile s.pem -nocrl # # with a certificate and key (but the key should be irrelevant) in s.pem pkcs7Data = b("""\ -----BEGIN PKCS7----- MIIDNwYJKoZIhvcNAQcCoIIDKDCCAyQCAQExADALBgkqhkiG9w0BBwGgggMKMIID BjCCAm+gAwIBAgIBATANBgkqhkiG9w0BAQQFADB7MQswCQYDVQQGEwJTRzERMA8G A1UEChMITTJDcnlwdG8xFDASBgNVBAsTC00yQ3J5cHRvIENBMSQwIgYDVQQDExtN MkNyeXB0byBDZXJ0aWZpY2F0ZSBNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5ncHNA cG9zdDEuY29tMB4XDTAwMDkxMDA5NTEzMFoXDTAyMDkxMDA5NTEzMFowUzELMAkG A1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwlsb2NhbGhvc3Qx HTAbBgkqhkiG9w0BCQEWDm5ncHNAcG9zdDEuY29tMFwwDQYJKoZIhvcNAQEBBQAD SwAwSAJBAKy+e3dulvXzV7zoTZWc5TzgApr8DmeQHTYC8ydfzH7EECe4R1Xh5kwI zOuuFfn178FBiS84gngaNcrFi0Z5fAkCAwEAAaOCAQQwggEAMAkGA1UdEwQCMAAw LAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0G A1UdDgQWBBTPhIKSvnsmYsBVNWjj0m3M2z0qVTCBpQYDVR0jBIGdMIGagBT7hyNp 65w6kxXlxb8pUU/+7Sg4AaF/pH0wezELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0y Q3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMbTTJDcnlwdG8g Q2VydGlmaWNhdGUgTWFzdGVyMR0wGwYJKoZIhvcNAQkBFg5uZ3BzQHBvc3QxLmNv bYIBADANBgkqhkiG9w0BAQQFAAOBgQA7/CqT6PoHycTdhEStWNZde7M/2Yc6BoJu VwnW8YxGO8Sn6UJ4FeffZNcYZddSDKosw8LtPOeWoK3JINjAk5jiPQ2cww++7QGG /g5NDjxFZNDJP1dGiLAxPW6JXwov4v0FmdzfLOZ01jDcgQQZqEpYlgpuI5JEWUQ9 Ho4EzbYCOaEAMQA= -----END PKCS7----- """) crlData = b("""\ -----BEGIN X509 CRL----- MIIBWzCBxTANBgkqhkiG9w0BAQQFADBYMQswCQYDVQQGEwJVUzELMAkGA1UECBMC SUwxEDAOBgNVBAcTB0NoaWNhZ28xEDAOBgNVBAoTB1Rlc3RpbmcxGDAWBgNVBAMT D1Rlc3RpbmcgUm9vdCBDQRcNMDkwNzI2MDQzNDU2WhcNMTIwOTI3MDI0MTUyWjA8 MBUCAgOrGA8yMDA5MDcyNTIzMzQ1NlowIwICAQAYDzIwMDkwNzI1MjMzNDU2WjAM MAoGA1UdFQQDCgEEMA0GCSqGSIb3DQEBBAUAA4GBAEBt7xTs2htdD3d4ErrcGAw1 4dKcVnIWTutoI7xxen26Wwvh8VCsT7i/UeP+rBl9rC/kfjWjzQk3/zleaarGTpBT 0yp4HXRFFoRhhSE/hP+eteaPXRgrsNRLHe9ZDd69wmh7J1wMDb0m81RG7kqcbsid vrzEeLDRiiPl92dyyWmu -----END X509 CRL----- """) # A broken RSA private key which can be used to test the error path through # PKey.check. inconsistentPrivateKeyPEM = b("""-----BEGIN RSA PRIVATE KEY----- MIIBPAIBAAJBAKy+e3dulvXzV7zoTZWc5TzgApr8DmeQHTYC8ydfzH7EECe4R1Xh 5kwIzOuuFfn178FBiS84gngaNcrFi0Z5fAkCAwEaAQJBAIqm/bz4NA1H++Vx5Ewx OcKp3w19QSaZAwlGRtsUxrP7436QjnREM3Bm8ygU11BjkPVmtrKm6AayQfCHqJoT zIECIQDW0BoMoL0HOYM/mrTLhaykYAVqgIeJsPjvkEhTFXWBuQIhAM3deFAvWNu4 nklUQ37XsCT2c9tmNt1LAT+slG2JOTTRAiAuXDtC/m3NYVwyHfFm+zKHRzHkClk2 HjubeEgjpj32AQIhAJqMGTaZVOwevTXvvHwNeH+vRWsAYU/gbx+OQB+7VOcBAiEA oolb6NMg/R3enNPvS1O4UU1H8wpaF77L4yiSWlE0p4w= -----END RSA PRIVATE KEY----- """) class X509ExtTests(TestCase): """ Tests for L{OpenSSL.crypto.X509Extension}. """ def setUp(self): """ Create a new private key and start a certificate request (for a test method to finish in one way or another). """ # Basic setup stuff to generate a certificate self.pkey = PKey() self.pkey.generate_key(TYPE_RSA, 384) self.req = X509Req() self.req.set_pubkey(self.pkey) # Authority good you have. self.req.get_subject().commonName = "Yoda root CA" self.x509 = X509() self.subject = self.x509.get_subject() self.subject.commonName = self.req.get_subject().commonName self.x509.set_issuer(self.subject) self.x509.set_pubkey(self.pkey) now = b(datetime.now().strftime("%Y%m%d%H%M%SZ")) expire = b((datetime.now() + timedelta(days=100)).strftime("%Y%m%d%H%M%SZ")) self.x509.set_notBefore(now) self.x509.set_notAfter(expire) def test_str(self): """ The string representation of L{X509Extension} instances as returned by C{str} includes stuff. """ # This isn't necessarily the best string representation. Perhaps it # will be changed/improved in the future. self.assertEquals( str(X509Extension(b('basicConstraints'), True, b('CA:false'))), 'CA:FALSE') def test_type(self): """ L{X509Extension} and L{X509ExtensionType} refer to the same type object and can be used to create instances of that type. """ self.assertIdentical(X509Extension, X509ExtensionType) self.assertConsistentType( X509Extension, 'X509Extension', b('basicConstraints'), True, b('CA:true')) def test_construction(self): """ L{X509Extension} accepts an extension type name, a critical flag, and an extension value and returns an L{X509ExtensionType} instance. """ basic = X509Extension(b('basicConstraints'), True, b('CA:true')) self.assertTrue( isinstance(basic, X509ExtensionType), "%r is of type %r, should be %r" % ( basic, type(basic), X509ExtensionType)) comment = X509Extension( b('nsComment'), False, b('pyOpenSSL unit test')) self.assertTrue( isinstance(comment, X509ExtensionType), "%r is of type %r, should be %r" % ( comment, type(comment), X509ExtensionType)) def test_invalid_extension(self): """ L{X509Extension} raises something if it is passed a bad extension name or value. """ self.assertRaises( Error, X509Extension, b('thisIsMadeUp'), False, b('hi')) self.assertRaises( Error, X509Extension, b('basicConstraints'), False, b('blah blah')) # Exercise a weird one (an extension which uses the r2i method). This # exercises the codepath that requires a non-NULL ctx to be passed to # X509V3_EXT_nconf. It can't work now because we provide no # configuration database. It might be made to work in the future. self.assertRaises( Error, X509Extension, b('proxyCertInfo'), True, b('language:id-ppl-anyLanguage,pathlen:1,policy:text:AB')) def test_get_critical(self): """ L{X509ExtensionType.get_critical} returns the value of the extension's critical flag. """ ext = X509Extension(b('basicConstraints'), True, b('CA:true')) self.assertTrue(ext.get_critical()) ext = X509Extension(b('basicConstraints'), False, b('CA:true')) self.assertFalse(ext.get_critical()) def test_get_short_name(self): """ L{X509ExtensionType.get_short_name} returns a string giving the short type name of the extension. """ ext = X509Extension(b('basicConstraints'), True, b('CA:true')) self.assertEqual(ext.get_short_name(), b('basicConstraints')) ext = X509Extension(b('nsComment'), True, b('foo bar')) self.assertEqual(ext.get_short_name(), b('nsComment')) def test_get_data(self): """ L{X509Extension.get_data} returns a string giving the data of the extension. """ ext = X509Extension(b('basicConstraints'), True, b('CA:true')) # Expect to get back the DER encoded form of CA:true. self.assertEqual(ext.get_data(), b('0\x03\x01\x01\xff')) def test_get_data_wrong_args(self): """ L{X509Extension.get_data} raises L{TypeError} if passed any arguments. """ ext = X509Extension(b('basicConstraints'), True, b('CA:true')) self.assertRaises(TypeError, ext.get_data, None) self.assertRaises(TypeError, ext.get_data, "foo") self.assertRaises(TypeError, ext.get_data, 7) def test_unused_subject(self): """ The C{subject} parameter to L{X509Extension} may be provided for an extension which does not use it and is ignored in this case. """ ext1 = X509Extension( b('basicConstraints'), False, b('CA:TRUE'), subject=self.x509) self.x509.add_extensions([ext1]) self.x509.sign(self.pkey, 'sha1') # This is a little lame. Can we think of a better way? text = dump_certificate(FILETYPE_TEXT, self.x509) self.assertTrue(b('X509v3 Basic Constraints:') in text) self.assertTrue(b('CA:TRUE') in text) def test_subject(self): """ If an extension requires a subject, the C{subject} parameter to L{X509Extension} provides its value. """ ext3 = X509Extension( b('subjectKeyIdentifier'), False, b('hash'), subject=self.x509) self.x509.add_extensions([ext3]) self.x509.sign(self.pkey, 'sha1') text = dump_certificate(FILETYPE_TEXT, self.x509) self.assertTrue(b('X509v3 Subject Key Identifier:') in text) def test_missing_subject(self): """ If an extension requires a subject and the C{subject} parameter is given no value, something happens. """ self.assertRaises( Error, X509Extension, b('subjectKeyIdentifier'), False, b('hash')) def test_invalid_subject(self): """ If the C{subject} parameter is given a value which is not an L{X509} instance, L{TypeError} is raised. """ for badObj in [True, object(), "hello", [], self]: self.assertRaises( TypeError, X509Extension, 'basicConstraints', False, 'CA:TRUE', subject=badObj) def test_unused_issuer(self): """ The C{issuer} parameter to L{X509Extension} may be provided for an extension which does not use it and is ignored in this case. """ ext1 = X509Extension( b('basicConstraints'), False, b('CA:TRUE'), issuer=self.x509) self.x509.add_extensions([ext1]) self.x509.sign(self.pkey, 'sha1') text = dump_certificate(FILETYPE_TEXT, self.x509) self.assertTrue(b('X509v3 Basic Constraints:') in text) self.assertTrue(b('CA:TRUE') in text) def test_issuer(self): """ If an extension requires a issuer, the C{issuer} parameter to L{X509Extension} provides its value. """ ext2 = X509Extension( b('authorityKeyIdentifier'), False, b('issuer:always'), issuer=self.x509) self.x509.add_extensions([ext2]) self.x509.sign(self.pkey, 'sha1') text = dump_certificate(FILETYPE_TEXT, self.x509) self.assertTrue(b('X509v3 Authority Key Identifier:') in text) self.assertTrue(b('DirName:/CN=Yoda root CA') in text) def test_missing_issuer(self): """ If an extension requires an issue and the C{issuer} parameter is given no value, something happens. """ self.assertRaises( Error, X509Extension, b('authorityKeyIdentifier'), False, b('keyid:always,issuer:always')) def test_invalid_issuer(self): """ If the C{issuer} parameter is given a value which is not an L{X509} instance, L{TypeError} is raised. """ for badObj in [True, object(), "hello", [], self]: self.assertRaises( TypeError, X509Extension, 'authorityKeyIdentifier', False, 'keyid:always,issuer:always', issuer=badObj) class PKeyTests(TestCase): """ Unit tests for L{OpenSSL.crypto.PKey}. """ def test_type(self): """ L{PKey} and L{PKeyType} refer to the same type object and can be used to create instances of that type. """ self.assertIdentical(PKey, PKeyType) self.assertConsistentType(PKey, 'PKey') def test_construction(self): """ L{PKey} takes no arguments and returns a new L{PKey} instance. """ self.assertRaises(TypeError, PKey, None) key = PKey() self.assertTrue( isinstance(key, PKeyType), "%r is of type %r, should be %r" % (key, type(key), PKeyType)) def test_pregeneration(self): """ L{PKeyType.bits} and L{PKeyType.type} return C{0} before the key is generated. L{PKeyType.check} raises L{TypeError} before the key is generated. """ key = PKey() self.assertEqual(key.type(), 0) self.assertEqual(key.bits(), 0) self.assertRaises(TypeError, key.check) def test_failedGeneration(self): """ L{PKeyType.generate_key} takes two arguments, the first giving the key type as one of L{TYPE_RSA} or L{TYPE_DSA} and the second giving the number of bits to generate. If an invalid type is specified or generation fails, L{Error} is raised. If an invalid number of bits is specified, L{ValueError} or L{Error} is raised. """ key = PKey() self.assertRaises(TypeError, key.generate_key) self.assertRaises(TypeError, key.generate_key, 1, 2, 3) self.assertRaises(TypeError, key.generate_key, "foo", "bar") self.assertRaises(Error, key.generate_key, -1, 0) self.assertRaises(ValueError, key.generate_key, TYPE_RSA, -1) self.assertRaises(ValueError, key.generate_key, TYPE_RSA, 0) # XXX RSA generation for small values of bits is fairly buggy in a wide # range of OpenSSL versions. I need to figure out what the safe lower # bound for a reasonable number of OpenSSL versions is and explicitly # check for that in the wrapper. The failure behavior is typically an # infinite loop inside OpenSSL. # self.assertRaises(Error, key.generate_key, TYPE_RSA, 2) # XXX DSA generation seems happy with any number of bits. The DSS # says bits must be between 512 and 1024 inclusive. OpenSSL's DSA # generator doesn't seem to care about the upper limit at all. For # the lower limit, it uses 512 if anything smaller is specified. # So, it doesn't seem possible to make generate_key fail for # TYPE_DSA with a bits argument which is at least an int. # self.assertRaises(Error, key.generate_key, TYPE_DSA, -7) def test_rsaGeneration(self): """ L{PKeyType.generate_key} generates an RSA key when passed L{TYPE_RSA} as a type and a reasonable number of bits. """ bits = 128 key = PKey() key.generate_key(TYPE_RSA, bits) self.assertEqual(key.type(), TYPE_RSA) self.assertEqual(key.bits(), bits) self.assertTrue(key.check()) def test_dsaGeneration(self): """ L{PKeyType.generate_key} generates a DSA key when passed L{TYPE_DSA} as a type and a reasonable number of bits. """ # 512 is a magic number. The DSS (Digital Signature Standard) # allows a minimum of 512 bits for DSA. DSA_generate_parameters # will silently promote any value below 512 to 512. bits = 512 key = PKey() key.generate_key(TYPE_DSA, bits) self.assertEqual(key.type(), TYPE_DSA) self.assertEqual(key.bits(), bits) self.assertRaises(TypeError, key.check) def test_regeneration(self): """ L{PKeyType.generate_key} can be called multiple times on the same key to generate new keys. """ key = PKey() for type, bits in [(TYPE_RSA, 512), (TYPE_DSA, 576)]: key.generate_key(type, bits) self.assertEqual(key.type(), type) self.assertEqual(key.bits(), bits) def test_inconsistentKey(self): """ L{PKeyType.check} returns C{False} if the key is not consistent. """ key = load_privatekey(FILETYPE_PEM, inconsistentPrivateKeyPEM) self.assertRaises(Error, key.check) def test_check_wrong_args(self): """ L{PKeyType.check} raises L{TypeError} if called with any arguments. """ self.assertRaises(TypeError, PKey().check, None) self.assertRaises(TypeError, PKey().check, object()) self.assertRaises(TypeError, PKey().check, 1) class X509NameTests(TestCase): """ Unit tests for L{OpenSSL.crypto.X509Name}. """ def _x509name(self, **attrs): # XXX There's no other way to get a new X509Name yet. name = X509().get_subject() attrs = list(attrs.items()) # Make the order stable - order matters! def key(attr): return attr[1] attrs.sort(key=key) for k, v in attrs: setattr(name, k, v) return name def test_type(self): """ The type of X509Name objects is L{X509NameType}. """ self.assertIdentical(X509Name, X509NameType) self.assertEqual(X509NameType.__name__, 'X509Name') self.assertTrue(isinstance(X509NameType, type)) name = self._x509name() self.assertTrue( isinstance(name, X509NameType), "%r is of type %r, should be %r" % ( name, type(name), X509NameType)) def test_onlyStringAttributes(self): """ Attempting to set a non-L{str} attribute name on an L{X509NameType} instance causes L{TypeError} to be raised. """ name = self._x509name() # Beyond these cases, you may also think that unicode should be # rejected. Sorry, you're wrong. unicode is automatically converted to # str outside of the control of X509Name, so there's no way to reject # it. self.assertRaises(TypeError, setattr, name, None, "hello") self.assertRaises(TypeError, setattr, name, 30, "hello") class evil(str): pass self.assertRaises(TypeError, setattr, name, evil(), "hello") def test_setInvalidAttribute(self): """ Attempting to set any attribute name on an L{X509NameType} instance for which no corresponding NID is defined causes L{AttributeError} to be raised. """ name = self._x509name() self.assertRaises(AttributeError, setattr, name, "no such thing", None) def test_attributes(self): """ L{X509NameType} instances have attributes for each standard (?) X509Name field. """ name = self._x509name() name.commonName = "foo" self.assertEqual(name.commonName, "foo") self.assertEqual(name.CN, "foo") name.CN = "baz" self.assertEqual(name.commonName, "baz") self.assertEqual(name.CN, "baz") name.commonName = "bar" self.assertEqual(name.commonName, "bar") self.assertEqual(name.CN, "bar") name.CN = "quux" self.assertEqual(name.commonName, "quux") self.assertEqual(name.CN, "quux") def test_copy(self): """ L{X509Name} creates a new L{X509NameType} instance with all the same attributes as an existing L{X509NameType} instance when called with one. """ name = self._x509name(commonName="foo", emailAddress="bar@example.com") copy = X509Name(name) self.assertEqual(copy.commonName, "foo") self.assertEqual(copy.emailAddress, "bar@example.com") # Mutate the copy and ensure the original is unmodified. copy.commonName = "baz" self.assertEqual(name.commonName, "foo") # Mutate the original and ensure the copy is unmodified. name.emailAddress = "quux@example.com" self.assertEqual(copy.emailAddress, "bar@example.com") def test_repr(self): """ L{repr} passed an L{X509NameType} instance should return a string containing a description of the type and the NIDs which have been set on it. """ name = self._x509name(commonName="foo", emailAddress="bar") self.assertEqual( repr(name), "") def test_comparison(self): """ L{X509NameType} instances should compare based on their NIDs. """ def _equality(a, b, assertTrue, assertFalse): assertTrue(a == b, "(%r == %r) --> False" % (a, b)) assertFalse(a != b) assertTrue(b == a) assertFalse(b != a) def assertEqual(a, b): _equality(a, b, self.assertTrue, self.assertFalse) # Instances compare equal to themselves. name = self._x509name() assertEqual(name, name) # Empty instances should compare equal to each other. assertEqual(self._x509name(), self._x509name()) # Instances with equal NIDs should compare equal to each other. assertEqual(self._x509name(commonName="foo"), self._x509name(commonName="foo")) # Instance with equal NIDs set using different aliases should compare # equal to each other. assertEqual(self._x509name(commonName="foo"), self._x509name(CN="foo")) # Instances with more than one NID with the same values should compare # equal to each other. assertEqual(self._x509name(CN="foo", organizationalUnitName="bar"), self._x509name(commonName="foo", OU="bar")) def assertNotEqual(a, b): _equality(a, b, self.assertFalse, self.assertTrue) # Instances with different values for the same NID should not compare # equal to each other. assertNotEqual(self._x509name(CN="foo"), self._x509name(CN="bar")) # Instances with different NIDs should not compare equal to each other. assertNotEqual(self._x509name(CN="foo"), self._x509name(OU="foo")) def _inequality(a, b, assertTrue, assertFalse): assertTrue(a < b) assertTrue(a <= b) assertTrue(b > a) assertTrue(b >= a) assertFalse(a > b) assertFalse(a >= b) assertFalse(b < a) assertFalse(b <= a) def assertLessThan(a, b): _inequality(a, b, self.assertTrue, self.assertFalse) # An X509Name with a NID with a value which sorts less than the value # of the same NID on another X509Name compares less than the other # X509Name. assertLessThan(self._x509name(CN="abc"), self._x509name(CN="def")) def assertGreaterThan(a, b): _inequality(a, b, self.assertFalse, self.assertTrue) # An X509Name with a NID with a value which sorts greater than the # value of the same NID on another X509Name compares greater than the # other X509Name. assertGreaterThan(self._x509name(CN="def"), self._x509name(CN="abc")) def test_hash(self): """ L{X509Name.hash} returns an integer hash based on the value of the name. """ a = self._x509name(CN="foo") b = self._x509name(CN="foo") self.assertEqual(a.hash(), b.hash()) a.CN = "bar" self.assertNotEqual(a.hash(), b.hash()) def test_der(self): """ L{X509Name.der} returns the DER encoded form of the name. """ a = self._x509name(CN="foo", C="US") self.assertEqual( a.der(), b('0\x1b1\x0b0\t\x06\x03U\x04\x06\x13\x02US' '1\x0c0\n\x06\x03U\x04\x03\x13\x03foo')) def test_get_components(self): """ L{X509Name.get_components} returns a C{list} of two-tuples of C{str} giving the NIDs and associated values which make up the name. """ a = self._x509name() self.assertEqual(a.get_components(), []) a.CN = "foo" self.assertEqual(a.get_components(), [(b("CN"), b("foo"))]) a.organizationalUnitName = "bar" self.assertEqual( a.get_components(), [(b("CN"), b("foo")), (b("OU"), b("bar"))]) class _PKeyInteractionTestsMixin: """ Tests which involve another thing and a PKey. """ def signable(self): """ Return something with a C{set_pubkey}, C{set_pubkey}, and C{sign} method. """ raise NotImplementedError() def test_signWithUngenerated(self): """ L{X509Req.sign} raises L{ValueError} when pass a L{PKey} with no parts. """ request = self.signable() key = PKey() self.assertRaises(ValueError, request.sign, key, 'MD5') def test_signWithPublicKey(self): """ L{X509Req.sign} raises L{ValueError} when pass a L{PKey} with no private part as the signing key. """ request = self.signable() key = PKey() key.generate_key(TYPE_RSA, 512) request.set_pubkey(key) pub = request.get_pubkey() self.assertRaises(ValueError, request.sign, pub, 'MD5') def test_signWithUnknownDigest(self): """ L{X509Req.sign} raises L{ValueError} when passed a digest name which is not known. """ request = self.signable() key = PKey() key.generate_key(TYPE_RSA, 512) self.assertRaises(ValueError, request.sign, key, "monkeys") def test_sign(self): """ L{X509Req.sign} succeeds when passed a private key object and a valid digest function. C{X509Req.verify} can be used to check the signature. """ request = self.signable() key = PKey() key.generate_key(TYPE_RSA, 512) request.set_pubkey(key) request.sign(key, 'MD5') # If the type has a verify method, cover that too. if getattr(request, 'verify', None) is not None: pub = request.get_pubkey() self.assertTrue(request.verify(pub)) # Make another key that won't verify. key = PKey() key.generate_key(TYPE_RSA, 512) self.assertRaises(Error, request.verify, key) class X509ReqTests(TestCase, _PKeyInteractionTestsMixin): """ Tests for L{OpenSSL.crypto.X509Req}. """ def signable(self): """ Create and return a new L{X509Req}. """ return X509Req() def test_type(self): """ L{X509Req} and L{X509ReqType} refer to the same type object and can be used to create instances of that type. """ self.assertIdentical(X509Req, X509ReqType) self.assertConsistentType(X509Req, 'X509Req') def test_construction(self): """ L{X509Req} takes no arguments and returns an L{X509ReqType} instance. """ request = X509Req() self.assertTrue( isinstance(request, X509ReqType), "%r is of type %r, should be %r" % (request, type(request), X509ReqType)) def test_version(self): """ L{X509ReqType.set_version} sets the X.509 version of the certificate request. L{X509ReqType.get_version} returns the X.509 version of the certificate request. The initial value of the version is 0. """ request = X509Req() self.assertEqual(request.get_version(), 0) request.set_version(1) self.assertEqual(request.get_version(), 1) request.set_version(3) self.assertEqual(request.get_version(), 3) def test_version_wrong_args(self): """ L{X509ReqType.set_version} raises L{TypeError} if called with the wrong number of arguments or with a non-C{int} argument. L{X509ReqType.get_version} raises L{TypeError} if called with any arguments. """ request = X509Req() self.assertRaises(TypeError, request.set_version) self.assertRaises(TypeError, request.set_version, "foo") self.assertRaises(TypeError, request.set_version, 1, 2) self.assertRaises(TypeError, request.get_version, None) def test_get_subject(self): """ L{X509ReqType.get_subject} returns an L{X509Name} for the subject of the request and which is valid even after the request object is otherwise dead. """ request = X509Req() subject = request.get_subject() self.assertTrue( isinstance(subject, X509NameType), "%r is of type %r, should be %r" % (subject, type(subject), X509NameType)) subject.commonName = "foo" self.assertEqual(request.get_subject().commonName, "foo") del request subject.commonName = "bar" self.assertEqual(subject.commonName, "bar") def test_get_subject_wrong_args(self): """ L{X509ReqType.get_subject} raises L{TypeError} if called with any arguments. """ request = X509Req() self.assertRaises(TypeError, request.get_subject, None) def test_add_extensions(self): """ L{X509Req.add_extensions} accepts a C{list} of L{X509Extension} instances and adds them to the X509 request. """ request = X509Req() request.add_extensions([ X509Extension(b('basicConstraints'), True, b('CA:false'))]) # XXX Add get_extensions so the rest of this unit test can be written. def test_add_extensions_wrong_args(self): """ L{X509Req.add_extensions} raises L{TypeError} if called with the wrong number of arguments or with a non-C{list}. Or it raises L{ValueError} if called with a C{list} containing objects other than L{X509Extension} instances. """ request = X509Req() self.assertRaises(TypeError, request.add_extensions) self.assertRaises(TypeError, request.add_extensions, object()) self.assertRaises(ValueError, request.add_extensions, [object()]) self.assertRaises(TypeError, request.add_extensions, [], None) class X509Tests(TestCase, _PKeyInteractionTestsMixin): """ Tests for L{OpenSSL.crypto.X509}. """ pemData = cleartextCertificatePEM + cleartextPrivateKeyPEM extpem = """ -----BEGIN CERTIFICATE----- MIIC3jCCAkegAwIBAgIJAJHFjlcCgnQzMA0GCSqGSIb3DQEBBQUAMEcxCzAJBgNV BAYTAlNFMRUwEwYDVQQIEwxXZXN0ZXJib3R0b20xEjAQBgNVBAoTCUNhdGFsb2dp eDENMAsGA1UEAxMEUm9vdDAeFw0wODA0MjIxNDQ1MzhaFw0wOTA0MjIxNDQ1Mzha MFQxCzAJBgNVBAYTAlNFMQswCQYDVQQIEwJXQjEUMBIGA1UEChMLT3Blbk1ldGFk aXIxIjAgBgNVBAMTGW5vZGUxLm9tMi5vcGVubWV0YWRpci5vcmcwgZ8wDQYJKoZI hvcNAQEBBQADgY0AMIGJAoGBAPIcQMrwbk2nESF/0JKibj9i1x95XYAOwP+LarwT Op4EQbdlI9SY+uqYqlERhF19w7CS+S6oyqx0DRZSk4Y9dZ9j9/xgm2u/f136YS1u zgYFPvfUs6PqYLPSM8Bw+SjJ+7+2+TN+Tkiof9WP1cMjodQwOmdsiRbR0/J7+b1B hec1AgMBAAGjgcQwgcEwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNT TCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFIdHsBcMVVMbAO7j6NCj 03HgLnHaMB8GA1UdIwQYMBaAFL2h9Bf9Mre4vTdOiHTGAt7BRY/8MEYGA1UdEQQ/ MD2CDSouZXhhbXBsZS5vcmeCESoub20yLmV4bWFwbGUuY29thwSC7wgKgRNvbTJA b3Blbm1ldGFkaXIub3JnMA0GCSqGSIb3DQEBBQUAA4GBALd7WdXkp2KvZ7/PuWZA MPlIxyjS+Ly11+BNE0xGQRp9Wz+2lABtpgNqssvU156+HkKd02rGheb2tj7MX9hG uZzbwDAZzJPjzDQDD7d3cWsrVcfIdqVU7epHqIadnOF+X0ghJ39pAm6VVadnSXCt WpOdIpB8KksUTCzV591Nr1wd -----END CERTIFICATE----- """ def signable(self): """ Create and return a new L{X509}. """ return X509() def test_type(self): """ L{X509} and L{X509Type} refer to the same type object and can be used to create instances of that type. """ self.assertIdentical(X509, X509Type) self.assertConsistentType(X509, 'X509') def test_construction(self): """ L{X509} takes no arguments and returns an instance of L{X509Type}. """ certificate = X509() self.assertTrue( isinstance(certificate, X509Type), "%r is of type %r, should be %r" % (certificate, type(certificate), X509Type)) self.assertEqual(type(X509Type).__name__, 'type') self.assertEqual(type(certificate).__name__, 'X509') self.assertEqual(type(certificate), X509Type) self.assertEqual(type(certificate), X509) def test_get_version_wrong_args(self): """ L{X509.get_version} raises L{TypeError} if invoked with any arguments. """ cert = X509() self.assertRaises(TypeError, cert.get_version, None) def test_set_version_wrong_args(self): """ L{X509.set_version} raises L{TypeError} if invoked with the wrong number of arguments or an argument not of type C{int}. """ cert = X509() self.assertRaises(TypeError, cert.set_version) self.assertRaises(TypeError, cert.set_version, None) self.assertRaises(TypeError, cert.set_version, 1, None) def test_version(self): """ L{X509.set_version} sets the certificate version number. L{X509.get_version} retrieves it. """ cert = X509() cert.set_version(1234) self.assertEquals(cert.get_version(), 1234) def test_get_serial_number_wrong_args(self): """ L{X509.get_serial_number} raises L{TypeError} if invoked with any arguments. """ cert = X509() self.assertRaises(TypeError, cert.get_serial_number, None) def test_serial_number(self): """ The serial number of an L{X509Type} can be retrieved and modified with L{X509Type.get_serial_number} and L{X509Type.set_serial_number}. """ certificate = X509() self.assertRaises(TypeError, certificate.set_serial_number) self.assertRaises(TypeError, certificate.set_serial_number, 1, 2) self.assertRaises(TypeError, certificate.set_serial_number, "1") self.assertRaises(TypeError, certificate.set_serial_number, 5.5) self.assertEqual(certificate.get_serial_number(), 0) certificate.set_serial_number(1) self.assertEqual(certificate.get_serial_number(), 1) certificate.set_serial_number(2 ** 32 + 1) self.assertEqual(certificate.get_serial_number(), 2 ** 32 + 1) certificate.set_serial_number(2 ** 64 + 1) self.assertEqual(certificate.get_serial_number(), 2 ** 64 + 1) certificate.set_serial_number(2 ** 128 + 1) self.assertEqual(certificate.get_serial_number(), 2 ** 128 + 1) def _setBoundTest(self, which): """ L{X509Type.set_notBefore} takes a string in the format of an ASN1 GENERALIZEDTIME and sets the beginning of the certificate's validity period to it. """ certificate = X509() set = getattr(certificate, 'set_not' + which) get = getattr(certificate, 'get_not' + which) # Starts with no value. self.assertEqual(get(), None) # GMT (Or is it UTC?) -exarkun when = b("20040203040506Z") set(when) self.assertEqual(get(), when) # A plus two hours and thirty minutes offset when = b("20040203040506+0530") set(when) self.assertEqual(get(), when) # A minus one hour fifteen minutes offset when = b("20040203040506-0115") set(when) self.assertEqual(get(), when) # An invalid string results in a ValueError self.assertRaises(ValueError, set, b("foo bar")) # The wrong number of arguments results in a TypeError. self.assertRaises(TypeError, set) self.assertRaises(TypeError, set, b("20040203040506Z"), b("20040203040506Z")) self.assertRaises(TypeError, get, b("foo bar")) # XXX ASN1_TIME (not GENERALIZEDTIME) def test_set_notBefore(self): """ L{X509Type.set_notBefore} takes a string in the format of an ASN1 GENERALIZEDTIME and sets the beginning of the certificate's validity period to it. """ self._setBoundTest("Before") def test_set_notAfter(self): """ L{X509Type.set_notAfter} takes a string in the format of an ASN1 GENERALIZEDTIME and sets the end of the certificate's validity period to it. """ self._setBoundTest("After") def test_get_notBefore(self): """ L{X509Type.get_notBefore} returns a string in the format of an ASN1 GENERALIZEDTIME even for certificates which store it as UTCTIME internally. """ cert = load_certificate(FILETYPE_PEM, self.pemData) self.assertEqual(cert.get_notBefore(), b("20090325123658Z")) def test_get_notAfter(self): """ L{X509Type.get_notAfter} returns a string in the format of an ASN1 GENERALIZEDTIME even for certificates which store it as UTCTIME internally. """ cert = load_certificate(FILETYPE_PEM, self.pemData) self.assertEqual(cert.get_notAfter(), b("20170611123658Z")) def test_gmtime_adj_notBefore_wrong_args(self): """ L{X509Type.gmtime_adj_notBefore} raises L{TypeError} if called with the wrong number of arguments or a non-C{int} argument. """ cert = X509() self.assertRaises(TypeError, cert.gmtime_adj_notBefore) self.assertRaises(TypeError, cert.gmtime_adj_notBefore, None) self.assertRaises(TypeError, cert.gmtime_adj_notBefore, 123, None) def test_gmtime_adj_notBefore(self): """ L{X509Type.gmtime_adj_notBefore} changes the not-before timestamp to be the current time plus the number of seconds passed in. """ cert = load_certificate(FILETYPE_PEM, self.pemData) now = datetime.utcnow() + timedelta(seconds=100) cert.gmtime_adj_notBefore(100) self.assertEqual(cert.get_notBefore(), b(now.strftime("%Y%m%d%H%M%SZ"))) def test_gmtime_adj_notAfter_wrong_args(self): """ L{X509Type.gmtime_adj_notAfter} raises L{TypeError} if called with the wrong number of arguments or a non-C{int} argument. """ cert = X509() self.assertRaises(TypeError, cert.gmtime_adj_notAfter) self.assertRaises(TypeError, cert.gmtime_adj_notAfter, None) self.assertRaises(TypeError, cert.gmtime_adj_notAfter, 123, None) def test_gmtime_adj_notAfter(self): """ L{X509Type.gmtime_adj_notAfter} changes the not-after timestamp to be the current time plus the number of seconds passed in. """ cert = load_certificate(FILETYPE_PEM, self.pemData) now = datetime.utcnow() + timedelta(seconds=100) cert.gmtime_adj_notAfter(100) self.assertEqual(cert.get_notAfter(), b(now.strftime("%Y%m%d%H%M%SZ"))) def test_has_expired_wrong_args(self): """ L{X509Type.has_expired} raises L{TypeError} if called with any arguments. """ cert = X509() self.assertRaises(TypeError, cert.has_expired, None) def test_has_expired(self): """ L{X509Type.has_expired} returns C{True} if the certificate's not-after time is in the past. """ cert = X509() cert.gmtime_adj_notAfter(-1) self.assertTrue(cert.has_expired()) def test_has_not_expired(self): """ L{X509Type.has_expired} returns C{False} if the certificate's not-after time is in the future. """ cert = X509() cert.gmtime_adj_notAfter(2) self.assertFalse(cert.has_expired()) def test_digest(self): """ L{X509.digest} returns a string giving ":"-separated hex-encoded words of the digest of the certificate. """ cert = X509() self.assertEqual( cert.digest("md5"), b("A8:EB:07:F8:53:25:0A:F2:56:05:C5:A5:C4:C4:C7:15")) def _extcert(self, pkey, extensions): cert = X509() cert.set_pubkey(pkey) cert.get_subject().commonName = "Unit Tests" cert.get_issuer().commonName = "Unit Tests" when = b(datetime.now().strftime("%Y%m%d%H%M%SZ")) cert.set_notBefore(when) cert.set_notAfter(when) cert.add_extensions(extensions) return load_certificate( FILETYPE_PEM, dump_certificate(FILETYPE_PEM, cert)) def test_extension_count(self): """ L{X509.get_extension_count} returns the number of extensions that are present in the certificate. """ pkey = load_privatekey(FILETYPE_PEM, client_key_pem) ca = X509Extension(b('basicConstraints'), True, b('CA:FALSE')) key = X509Extension(b('keyUsage'), True, b('digitalSignature')) subjectAltName = X509Extension( b('subjectAltName'), True, b('DNS:example.com')) # Try a certificate with no extensions at all. c = self._extcert(pkey, []) self.assertEqual(c.get_extension_count(), 0) # And a certificate with one c = self._extcert(pkey, [ca]) self.assertEqual(c.get_extension_count(), 1) # And a certificate with several c = self._extcert(pkey, [ca, key, subjectAltName]) self.assertEqual(c.get_extension_count(), 3) def test_get_extension(self): """ L{X509.get_extension} takes an integer and returns an L{X509Extension} corresponding to the extension at that index. """ pkey = load_privatekey(FILETYPE_PEM, client_key_pem) ca = X509Extension(b('basicConstraints'), True, b('CA:FALSE')) key = X509Extension(b('keyUsage'), True, b('digitalSignature')) subjectAltName = X509Extension( b('subjectAltName'), False, b('DNS:example.com')) cert = self._extcert(pkey, [ca, key, subjectAltName]) ext = cert.get_extension(0) self.assertTrue(isinstance(ext, X509Extension)) self.assertTrue(ext.get_critical()) self.assertEqual(ext.get_short_name(), b('basicConstraints')) ext = cert.get_extension(1) self.assertTrue(isinstance(ext, X509Extension)) self.assertTrue(ext.get_critical()) self.assertEqual(ext.get_short_name(), b('keyUsage')) ext = cert.get_extension(2) self.assertTrue(isinstance(ext, X509Extension)) self.assertFalse(ext.get_critical()) self.assertEqual(ext.get_short_name(), b('subjectAltName')) self.assertRaises(IndexError, cert.get_extension, -1) self.assertRaises(IndexError, cert.get_extension, 4) self.assertRaises(TypeError, cert.get_extension, "hello") def test_invalid_digest_algorithm(self): """ L{X509.digest} raises L{ValueError} if called with an unrecognized hash algorithm. """ cert = X509() self.assertRaises(ValueError, cert.digest, "monkeys") def test_get_subject_wrong_args(self): """ L{X509.get_subject} raises L{TypeError} if called with any arguments. """ cert = X509() self.assertRaises(TypeError, cert.get_subject, None) def test_get_subject(self): """ L{X509.get_subject} returns an L{X509Name} instance. """ cert = load_certificate(FILETYPE_PEM, self.pemData) subj = cert.get_subject() self.assertTrue(isinstance(subj, X509Name)) self.assertEquals( subj.get_components(), [(b('C'), b('US')), (b('ST'), b('IL')), (b('L'), b('Chicago')), (b('O'), b('Testing')), (b('CN'), b('Testing Root CA'))]) def test_set_subject_wrong_args(self): """ L{X509.set_subject} raises a L{TypeError} if called with the wrong number of arguments or an argument not of type L{X509Name}. """ cert = X509() self.assertRaises(TypeError, cert.set_subject) self.assertRaises(TypeError, cert.set_subject, None) self.assertRaises(TypeError, cert.set_subject, cert.get_subject(), None) def test_set_subject(self): """ L{X509.set_subject} changes the subject of the certificate to the one passed in. """ cert = X509() name = cert.get_subject() name.C = 'AU' name.O = 'Unit Tests' cert.set_subject(name) self.assertEquals( cert.get_subject().get_components(), [(b('C'), b('AU')), (b('O'), b('Unit Tests'))]) def test_get_issuer_wrong_args(self): """ L{X509.get_issuer} raises L{TypeError} if called with any arguments. """ cert = X509() self.assertRaises(TypeError, cert.get_issuer, None) def test_get_issuer(self): """ L{X509.get_issuer} returns an L{X509Name} instance. """ cert = load_certificate(FILETYPE_PEM, self.pemData) subj = cert.get_issuer() self.assertTrue(isinstance(subj, X509Name)) comp = subj.get_components() self.assertEquals( comp, [(b('C'), b('US')), (b('ST'), b('IL')), (b('L'), b('Chicago')), (b('O'), b('Testing')), (b('CN'), b('Testing Root CA'))]) def test_set_issuer_wrong_args(self): """ L{X509.set_issuer} raises a L{TypeError} if called with the wrong number of arguments or an argument not of type L{X509Name}. """ cert = X509() self.assertRaises(TypeError, cert.set_issuer) self.assertRaises(TypeError, cert.set_issuer, None) self.assertRaises(TypeError, cert.set_issuer, cert.get_issuer(), None) def test_set_issuer(self): """ L{X509.set_issuer} changes the issuer of the certificate to the one passed in. """ cert = X509() name = cert.get_issuer() name.C = 'AU' name.O = 'Unit Tests' cert.set_issuer(name) self.assertEquals( cert.get_issuer().get_components(), [(b('C'), b('AU')), (b('O'), b('Unit Tests'))]) def test_get_pubkey_uninitialized(self): """ When called on a certificate with no public key, L{X509.get_pubkey} raises L{OpenSSL.crypto.Error}. """ cert = X509() self.assertRaises(Error, cert.get_pubkey) def test_subject_name_hash_wrong_args(self): """ L{X509.subject_name_hash} raises L{TypeError} if called with any arguments. """ cert = X509() self.assertRaises(TypeError, cert.subject_name_hash, None) def test_subject_name_hash(self): """ L{X509.subject_name_hash} returns the hash of the certificate's subject name. """ cert = load_certificate(FILETYPE_PEM, self.pemData) self.assertIn( cert.subject_name_hash(), [3350047874, # OpenSSL 0.9.8, MD5 3278919224, # OpenSSL 1.0.0, SHA1 ]) def test_get_signature_algorithm(self): """ L{X509Type.get_signature_algorithm} returns a string which means the algorithm used to sign the certificate. """ cert = load_certificate(FILETYPE_PEM, self.pemData) self.assertEqual( b("sha1WithRSAEncryption"), cert.get_signature_algorithm()) def test_get_undefined_signature_algorithm(self): """ L{X509Type.get_signature_algorithm} raises L{ValueError} if the signature algorithm is undefined or unknown. """ # This certificate has been modified to indicate a bogus OID in the # signature algorithm field so that OpenSSL does not recognize it. certPEM = """\ -----BEGIN CERTIFICATE----- MIIC/zCCAmigAwIBAgIBATAGBgJ8BQUAMHsxCzAJBgNVBAYTAlNHMREwDwYDVQQK EwhNMkNyeXB0bzEUMBIGA1UECxMLTTJDcnlwdG8gQ0ExJDAiBgNVBAMTG00yQ3J5 cHRvIENlcnRpZmljYXRlIE1hc3RlcjEdMBsGCSqGSIb3DQEJARYObmdwc0Bwb3N0 MS5jb20wHhcNMDAwOTEwMDk1MTMwWhcNMDIwOTEwMDk1MTMwWjBTMQswCQYDVQQG EwJTRzERMA8GA1UEChMITTJDcnlwdG8xEjAQBgNVBAMTCWxvY2FsaG9zdDEdMBsG CSqGSIb3DQEJARYObmdwc0Bwb3N0MS5jb20wXDANBgkqhkiG9w0BAQEFAANLADBI AkEArL57d26W9fNXvOhNlZzlPOACmvwOZ5AdNgLzJ1/MfsQQJ7hHVeHmTAjM664V +fXvwUGJLziCeBo1ysWLRnl8CQIDAQABo4IBBDCCAQAwCQYDVR0TBAIwADAsBglg hkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0O BBYEFM+EgpK+eyZiwFU1aOPSbczbPSpVMIGlBgNVHSMEgZ0wgZqAFPuHI2nrnDqT FeXFvylRT/7tKDgBoX+kfTB7MQswCQYDVQQGEwJTRzERMA8GA1UEChMITTJDcnlw dG8xFDASBgNVBAsTC00yQ3J5cHRvIENBMSQwIgYDVQQDExtNMkNyeXB0byBDZXJ0 aWZpY2F0ZSBNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5ncHNAcG9zdDEuY29tggEA MA0GCSqGSIb3DQEBBAUAA4GBADv8KpPo+gfJxN2ERK1Y1l17sz/ZhzoGgm5XCdbx jEY7xKfpQngV599k1xhl11IMqizDwu0855agrckg2MCTmOI9DZzDD77tAYb+Dk0O PEVk0Mk/V0aIsDE9bolfCi/i/QWZ3N8s5nTWMNyBBBmoSliWCm4jkkRZRD0ejgTN tgI5 -----END CERTIFICATE----- """ cert = load_certificate(FILETYPE_PEM, certPEM) self.assertRaises(ValueError, cert.get_signature_algorithm) class PKCS12Tests(TestCase): """ Test for L{OpenSSL.crypto.PKCS12} and L{OpenSSL.crypto.load_pkcs12}. """ pemData = cleartextCertificatePEM + cleartextPrivateKeyPEM def test_type(self): """ L{PKCS12Type} is a type object. """ self.assertIdentical(PKCS12, PKCS12Type) self.assertConsistentType(PKCS12, 'PKCS12') def test_empty_construction(self): """ L{PKCS12} returns a new instance of L{PKCS12} with no certificate, private key, CA certificates, or friendly name. """ p12 = PKCS12() self.assertEqual(None, p12.get_certificate()) self.assertEqual(None, p12.get_privatekey()) self.assertEqual(None, p12.get_ca_certificates()) self.assertEqual(None, p12.get_friendlyname()) def test_type_errors(self): """ The L{PKCS12} setter functions (C{set_certificate}, C{set_privatekey}, C{set_ca_certificates}, and C{set_friendlyname}) raise L{TypeError} when passed objects of types other than those expected. """ p12 = PKCS12() self.assertRaises(TypeError, p12.set_certificate, 3) self.assertRaises(TypeError, p12.set_certificate, PKey()) self.assertRaises(TypeError, p12.set_certificate, X509) self.assertRaises(TypeError, p12.set_privatekey, 3) self.assertRaises(TypeError, p12.set_privatekey, 'legbone') self.assertRaises(TypeError, p12.set_privatekey, X509()) self.assertRaises(TypeError, p12.set_ca_certificates, 3) self.assertRaises(TypeError, p12.set_ca_certificates, X509()) self.assertRaises(TypeError, p12.set_ca_certificates, (3, 4)) self.assertRaises(TypeError, p12.set_ca_certificates, ( PKey(), )) self.assertRaises(TypeError, p12.set_friendlyname, 6) self.assertRaises(TypeError, p12.set_friendlyname, ('foo', 'bar')) def test_key_only(self): """ A L{PKCS12} with only a private key can be exported using L{PKCS12.export} and loaded again using L{load_pkcs12}. """ passwd = 'blah' p12 = PKCS12() pkey = load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM) p12.set_privatekey(pkey) self.assertEqual(None, p12.get_certificate()) self.assertEqual(pkey, p12.get_privatekey()) try: dumped_p12 = p12.export(passphrase=passwd, iter=2, maciter=3) except Error: # Some versions of OpenSSL will throw an exception # for this nearly useless PKCS12 we tried to generate: # [('PKCS12 routines', 'PKCS12_create', 'invalid null argument')] return p12 = load_pkcs12(dumped_p12, passwd) self.assertEqual(None, p12.get_ca_certificates()) self.assertEqual(None, p12.get_certificate()) # OpenSSL fails to bring the key back to us. So sad. Perhaps in the # future this will be improved. self.assertTrue(isinstance(p12.get_privatekey(), (PKey, type(None)))) def test_cert_only(self): """ A L{PKCS12} with only a certificate can be exported using L{PKCS12.export} and loaded again using L{load_pkcs12}. """ passwd = 'blah' p12 = PKCS12() cert = load_certificate(FILETYPE_PEM, cleartextCertificatePEM) p12.set_certificate(cert) self.assertEqual(cert, p12.get_certificate()) self.assertEqual(None, p12.get_privatekey()) try: dumped_p12 = p12.export(passphrase=passwd, iter=2, maciter=3) except Error: # Some versions of OpenSSL will throw an exception # for this nearly useless PKCS12 we tried to generate: # [('PKCS12 routines', 'PKCS12_create', 'invalid null argument')] return p12 = load_pkcs12(dumped_p12, passwd) self.assertEqual(None, p12.get_privatekey()) # OpenSSL fails to bring the cert back to us. Groany mcgroan. self.assertTrue(isinstance(p12.get_certificate(), (X509, type(None)))) # Oh ho. It puts the certificate into the ca certificates list, in # fact. Totally bogus, I would think. Nevertheless, let's exploit # that to check to see if it reconstructed the certificate we expected # it to. At some point, hopefully this will change so that # p12.get_certificate() is actually what returns the loaded # certificate. self.assertEqual( cleartextCertificatePEM, dump_certificate(FILETYPE_PEM, p12.get_ca_certificates()[0])) def gen_pkcs12(self, cert_pem=None, key_pem=None, ca_pem=None, friendly_name=None): """ Generate a PKCS12 object with components from PEM. Verify that the set functions return None. """ p12 = PKCS12() if cert_pem: ret = p12.set_certificate(load_certificate(FILETYPE_PEM, cert_pem)) self.assertEqual(ret, None) if key_pem: ret = p12.set_privatekey(load_privatekey(FILETYPE_PEM, key_pem)) self.assertEqual(ret, None) if ca_pem: ret = p12.set_ca_certificates((load_certificate(FILETYPE_PEM, ca_pem),)) self.assertEqual(ret, None) if friendly_name: ret = p12.set_friendlyname(friendly_name) self.assertEqual(ret, None) return p12 def check_recovery(self, p12_str, key=None, cert=None, ca=None, passwd='', extra=()): """ Use openssl program to confirm three components are recoverable from a PKCS12 string. """ if key: recovered_key = _runopenssl( p12_str, "pkcs12", '-nocerts', '-nodes', '-passin', 'pass:' + passwd, *extra) self.assertEqual(recovered_key[-len(key):], key) if cert: recovered_cert = _runopenssl( p12_str, "pkcs12", '-clcerts', '-nodes', '-passin', 'pass:' + passwd, '-nokeys', *extra) self.assertEqual(recovered_cert[-len(cert):], cert) if ca: recovered_cert = _runopenssl( p12_str, "pkcs12", '-cacerts', '-nodes', '-passin', 'pass:' + passwd, '-nokeys', *extra) self.assertEqual(recovered_cert[-len(ca):], ca) def test_load_pkcs12(self): """ A PKCS12 string generated using the openssl command line can be loaded with L{load_pkcs12} and its components extracted and examined. """ passwd = 'whatever' pem = client_key_pem + client_cert_pem p12_str = _runopenssl( pem, "pkcs12", '-export', '-clcerts', '-passout', 'pass:' + passwd) p12 = load_pkcs12(p12_str, passwd) # verify self.assertTrue(isinstance(p12, PKCS12)) cert_pem = dump_certificate(FILETYPE_PEM, p12.get_certificate()) self.assertEqual(cert_pem, client_cert_pem) key_pem = dump_privatekey(FILETYPE_PEM, p12.get_privatekey()) self.assertEqual(key_pem, client_key_pem) self.assertEqual(None, p12.get_ca_certificates()) def test_load_pkcs12_garbage(self): """ L{load_pkcs12} raises L{OpenSSL.crypto.Error} when passed a string which is not a PKCS12 dump. """ passwd = 'whatever' e = self.assertRaises(Error, load_pkcs12, 'fruit loops', passwd) self.assertEqual( e.args[0][0][0], 'asn1 encoding routines') self.assertEqual( len(e.args[0][0]), 3) def test_replace(self): """ L{PKCS12.set_certificate} replaces the certificate in a PKCS12 cluster. L{PKCS12.set_privatekey} replaces the private key. L{PKCS12.set_ca_certificates} replaces the CA certificates. """ p12 = self.gen_pkcs12(client_cert_pem, client_key_pem, root_cert_pem) p12.set_certificate(load_certificate(FILETYPE_PEM, server_cert_pem)) p12.set_privatekey(load_privatekey(FILETYPE_PEM, server_key_pem)) root_cert = load_certificate(FILETYPE_PEM, root_cert_pem) client_cert = load_certificate(FILETYPE_PEM, client_cert_pem) p12.set_ca_certificates([root_cert]) # not a tuple self.assertEqual(1, len(p12.get_ca_certificates())) self.assertEqual(root_cert, p12.get_ca_certificates()[0]) p12.set_ca_certificates([client_cert, root_cert]) self.assertEqual(2, len(p12.get_ca_certificates())) self.assertEqual(client_cert, p12.get_ca_certificates()[0]) self.assertEqual(root_cert, p12.get_ca_certificates()[1]) def test_friendly_name(self): """ The I{friendlyName} of a PKCS12 can be set and retrieved via L{PKCS12.get_friendlyname} and L{PKCS12_set_friendlyname}, and a L{PKCS12} with a friendly name set can be dumped with L{PKCS12.export}. """ passwd = 'Dogmeat[]{}!@#$%^&*()~`?/.,<>-_+=";:' p12 = self.gen_pkcs12(server_cert_pem, server_key_pem, root_cert_pem) for friendly_name in [b('Serverlicious'), None, b('###')]: p12.set_friendlyname(friendly_name) self.assertEqual(p12.get_friendlyname(), friendly_name) dumped_p12 = p12.export(passphrase=passwd, iter=2, maciter=3) reloaded_p12 = load_pkcs12(dumped_p12, passwd) self.assertEqual( p12.get_friendlyname(), reloaded_p12.get_friendlyname()) # We would use the openssl program to confirm the friendly # name, but it is not possible. The pkcs12 command # does not store the friendly name in the cert's # alias, which we could then extract. self.check_recovery( dumped_p12, key=server_key_pem, cert=server_cert_pem, ca=root_cert_pem, passwd=passwd) def test_various_empty_passphrases(self): """ Test that missing, None, and '' passphrases are identical for PKCS12 export. """ p12 = self.gen_pkcs12(client_cert_pem, client_key_pem, root_cert_pem) passwd = '' dumped_p12_empty = p12.export(iter=2, maciter=0, passphrase=passwd) dumped_p12_none = p12.export(iter=3, maciter=2, passphrase=None) dumped_p12_nopw = p12.export(iter=9, maciter=4) for dumped_p12 in [dumped_p12_empty, dumped_p12_none, dumped_p12_nopw]: self.check_recovery( dumped_p12, key=client_key_pem, cert=client_cert_pem, ca=root_cert_pem, passwd=passwd) def test_removing_ca_cert(self): """ Passing C{None} to L{PKCS12.set_ca_certificates} removes all CA certificates. """ p12 = self.gen_pkcs12(server_cert_pem, server_key_pem, root_cert_pem) p12.set_ca_certificates(None) self.assertEqual(None, p12.get_ca_certificates()) def test_export_without_mac(self): """ Exporting a PKCS12 with a C{maciter} of C{-1} excludes the MAC entirely. """ passwd = 'Lake Michigan' p12 = self.gen_pkcs12(server_cert_pem, server_key_pem, root_cert_pem) dumped_p12 = p12.export(maciter=-1, passphrase=passwd, iter=2) self.check_recovery( dumped_p12, key=server_key_pem, cert=server_cert_pem, passwd=passwd, extra=('-nomacver',)) def test_load_without_mac(self): """ Loading a PKCS12 without a MAC does something other than crash. """ passwd = 'Lake Michigan' p12 = self.gen_pkcs12(server_cert_pem, server_key_pem, root_cert_pem) dumped_p12 = p12.export(maciter=-1, passphrase=passwd, iter=2) try: recovered_p12 = load_pkcs12(dumped_p12, passwd) # The person who generated this PCKS12 should be flogged, # or better yet we should have a means to determine # whether a PCKS12 had a MAC that was verified. # Anyway, libopenssl chooses to allow it, so the # pyopenssl binding does as well. self.assertTrue(isinstance(recovered_p12, PKCS12)) except Error: # Failing here with an exception is preferred as some openssl # versions do. pass def test_zero_len_list_for_ca(self): """ A PKCS12 with an empty CA certificates list can be exported. """ passwd = 'Hobie 18' p12 = self.gen_pkcs12(server_cert_pem, server_key_pem) p12.set_ca_certificates([]) self.assertEqual((), p12.get_ca_certificates()) dumped_p12 = p12.export(passphrase=passwd, iter=3) self.check_recovery( dumped_p12, key=server_key_pem, cert=server_cert_pem, passwd=passwd) def test_export_without_args(self): """ All the arguments to L{PKCS12.export} are optional. """ p12 = self.gen_pkcs12(server_cert_pem, server_key_pem, root_cert_pem) dumped_p12 = p12.export() # no args self.check_recovery( dumped_p12, key=server_key_pem, cert=server_cert_pem, passwd='') def test_key_cert_mismatch(self): """ L{PKCS12.export} raises an exception when a key and certificate mismatch. """ p12 = self.gen_pkcs12(server_cert_pem, client_key_pem, root_cert_pem) self.assertRaises(Error, p12.export) # These quoting functions taken directly from Twisted's twisted.python.win32. _cmdLineQuoteRe = re.compile(r'(\\*)"') _cmdLineQuoteRe2 = re.compile(r'(\\+)\Z') def cmdLineQuote(s): """ Internal method for quoting a single command-line argument. @type: C{str} @param s: A single unquoted string to quote for something that is expecting cmd.exe-style quoting @rtype: C{str} @return: A cmd.exe-style quoted string @see: U{http://www.perlmonks.org/?node_id=764004} """ s = _cmdLineQuoteRe2.sub(r"\1\1", _cmdLineQuoteRe.sub(r'\1\1\\"', s)) return '"%s"' % s def quoteArguments(arguments): """ Quote an iterable of command-line arguments for passing to CreateProcess or a similar API. This allows the list passed to C{reactor.spawnProcess} to match the child process's C{sys.argv} properly. @type arguments: C{iterable} of C{str} @param arguments: An iterable of unquoted arguments to quote @rtype: C{str} @return: A space-delimited string containing quoted versions of L{arguments} """ return ' '.join(map(cmdLineQuote, arguments)) def _runopenssl(pem, *args): """ Run the command line openssl tool with the given arguments and write the given PEM to its stdin. Not safe for quotes. """ if os.name == 'posix': command = "openssl " + " ".join([ "'%s'" % (arg.replace("'", "'\\''"),) for arg in args]) else: command = "openssl " + quoteArguments(args) proc = Popen(command, shell=True, stdin=PIPE, stdout=PIPE) proc.stdin.write(pem) proc.stdin.close() return proc.stdout.read() class FunctionTests(TestCase): """ Tests for free-functions in the L{OpenSSL.crypto} module. """ def test_load_privatekey_invalid_format(self): """ L{load_privatekey} raises L{ValueError} if passed an unknown filetype. """ self.assertRaises(ValueError, load_privatekey, 100, root_key_pem) def test_load_privatekey_invalid_passphrase_type(self): """ L{load_privatekey} raises L{TypeError} if passed a passphrase that is neither a c{str} nor a callable. """ self.assertRaises( TypeError, load_privatekey, FILETYPE_PEM, encryptedPrivateKeyPEMPassphrase, object()) def test_load_privatekey_wrong_args(self): """ L{load_privatekey} raises L{TypeError} if called with the wrong number of arguments. """ self.assertRaises(TypeError, load_privatekey) def test_load_privatekey_wrongPassphrase(self): """ L{load_privatekey} raises L{OpenSSL.crypto.Error} when it is passed an encrypted PEM and an incorrect passphrase. """ self.assertRaises( Error, load_privatekey, FILETYPE_PEM, encryptedPrivateKeyPEM, b("quack")) def test_load_privatekey_passphrase(self): """ L{load_privatekey} can create a L{PKey} object from an encrypted PEM string if given the passphrase. """ key = load_privatekey( FILETYPE_PEM, encryptedPrivateKeyPEM, encryptedPrivateKeyPEMPassphrase) self.assertTrue(isinstance(key, PKeyType)) def test_load_privatekey_wrongPassphraseCallback(self): """ L{load_privatekey} raises L{OpenSSL.crypto.Error} when it is passed an encrypted PEM and a passphrase callback which returns an incorrect passphrase. """ called = [] def cb(*a): called.append(None) return "quack" self.assertRaises( Error, load_privatekey, FILETYPE_PEM, encryptedPrivateKeyPEM, cb) self.assertTrue(called) def test_load_privatekey_passphraseCallback(self): """ L{load_privatekey} can create a L{PKey} object from an encrypted PEM string if given a passphrase callback which returns the correct password. """ called = [] def cb(writing): called.append(writing) return encryptedPrivateKeyPEMPassphrase key = load_privatekey(FILETYPE_PEM, encryptedPrivateKeyPEM, cb) self.assertTrue(isinstance(key, PKeyType)) self.assertEqual(called, [False]) def test_load_privatekey_passphrase_exception(self): """ An exception raised by the passphrase callback passed to L{load_privatekey} causes L{OpenSSL.crypto.Error} to be raised. This isn't as nice as just letting the exception pass through. The behavior might be changed to that eventually. """ def broken(ignored): raise RuntimeError("This is not working.") self.assertRaises( Error, load_privatekey, FILETYPE_PEM, encryptedPrivateKeyPEM, broken) def test_dump_privatekey_wrong_args(self): """ L{dump_privatekey} raises L{TypeError} if called with the wrong number of arguments. """ self.assertRaises(TypeError, dump_privatekey) def test_dump_privatekey_unknown_cipher(self): """ L{dump_privatekey} raises L{ValueError} if called with an unrecognized cipher name. """ key = PKey() key.generate_key(TYPE_RSA, 512) self.assertRaises( ValueError, dump_privatekey, FILETYPE_PEM, key, "zippers", "passphrase") def test_dump_privatekey_invalid_passphrase_type(self): """ L{dump_privatekey} raises L{TypeError} if called with a passphrase which is neither a C{str} nor a callable. """ key = PKey() key.generate_key(TYPE_RSA, 512) self.assertRaises( TypeError, dump_privatekey, FILETYPE_PEM, key, "blowfish", object()) def test_dump_privatekey_invalid_filetype(self): """ L{dump_privatekey} raises L{ValueError} if called with an unrecognized filetype. """ key = PKey() key.generate_key(TYPE_RSA, 512) self.assertRaises(ValueError, dump_privatekey, 100, key) def test_dump_privatekey_passphrase(self): """ L{dump_privatekey} writes an encrypted PEM when given a passphrase. """ passphrase = b("foo") key = load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM) pem = dump_privatekey(FILETYPE_PEM, key, "blowfish", passphrase) self.assertTrue(isinstance(pem, bytes)) loadedKey = load_privatekey(FILETYPE_PEM, pem, passphrase) self.assertTrue(isinstance(loadedKey, PKeyType)) self.assertEqual(loadedKey.type(), key.type()) self.assertEqual(loadedKey.bits(), key.bits()) def test_dump_certificate(self): """ L{dump_certificate} writes PEM, DER, and text. """ pemData = cleartextCertificatePEM + cleartextPrivateKeyPEM cert = load_certificate(FILETYPE_PEM, pemData) dumped_pem = dump_certificate(FILETYPE_PEM, cert) self.assertEqual(dumped_pem, cleartextCertificatePEM) dumped_der = dump_certificate(FILETYPE_ASN1, cert) good_der = _runopenssl(dumped_pem, "x509", "-outform", "DER") self.assertEqual(dumped_der, good_der) cert2 = load_certificate(FILETYPE_ASN1, dumped_der) dumped_pem2 = dump_certificate(FILETYPE_PEM, cert2) self.assertEqual(dumped_pem2, cleartextCertificatePEM) dumped_text = dump_certificate(FILETYPE_TEXT, cert) good_text = _runopenssl(dumped_pem, "x509", "-noout", "-text") self.assertEqual(dumped_text, good_text) def test_dump_privatekey(self): """ L{dump_privatekey} writes a PEM, DER, and text. """ key = load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM) self.assertTrue(key.check()) dumped_pem = dump_privatekey(FILETYPE_PEM, key) self.assertEqual(dumped_pem, cleartextPrivateKeyPEM) dumped_der = dump_privatekey(FILETYPE_ASN1, key) # XXX This OpenSSL call writes "writing RSA key" to standard out. Sad. good_der = _runopenssl(dumped_pem, "rsa", "-outform", "DER") self.assertEqual(dumped_der, good_der) key2 = load_privatekey(FILETYPE_ASN1, dumped_der) dumped_pem2 = dump_privatekey(FILETYPE_PEM, key2) self.assertEqual(dumped_pem2, cleartextPrivateKeyPEM) dumped_text = dump_privatekey(FILETYPE_TEXT, key) good_text = _runopenssl(dumped_pem, "rsa", "-noout", "-text") self.assertEqual(dumped_text, good_text) def test_dump_certificate_request(self): """ L{dump_certificate_request} writes a PEM, DER, and text. """ req = load_certificate_request(FILETYPE_PEM, cleartextCertificateRequestPEM) dumped_pem = dump_certificate_request(FILETYPE_PEM, req) self.assertEqual(dumped_pem, cleartextCertificateRequestPEM) dumped_der = dump_certificate_request(FILETYPE_ASN1, req) good_der = _runopenssl(dumped_pem, "req", "-outform", "DER") self.assertEqual(dumped_der, good_der) req2 = load_certificate_request(FILETYPE_ASN1, dumped_der) dumped_pem2 = dump_certificate_request(FILETYPE_PEM, req2) self.assertEqual(dumped_pem2, cleartextCertificateRequestPEM) dumped_text = dump_certificate_request(FILETYPE_TEXT, req) good_text = _runopenssl(dumped_pem, "req", "-noout", "-text") self.assertEqual(dumped_text, good_text) self.assertRaises(ValueError, dump_certificate_request, 100, req) def test_dump_privatekey_passphraseCallback(self): """ L{dump_privatekey} writes an encrypted PEM when given a callback which returns the correct passphrase. """ passphrase = b("foo") called = [] def cb(writing): called.append(writing) return passphrase key = load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM) pem = dump_privatekey(FILETYPE_PEM, key, "blowfish", cb) self.assertTrue(isinstance(pem, bytes)) self.assertEqual(called, [True]) loadedKey = load_privatekey(FILETYPE_PEM, pem, passphrase) self.assertTrue(isinstance(loadedKey, PKeyType)) self.assertEqual(loadedKey.type(), key.type()) self.assertEqual(loadedKey.bits(), key.bits()) def test_load_pkcs7_data(self): """ L{load_pkcs7_data} accepts a PKCS#7 string and returns an instance of L{PKCS7Type}. """ pkcs7 = load_pkcs7_data(FILETYPE_PEM, pkcs7Data) self.assertTrue(isinstance(pkcs7, PKCS7Type)) class PKCS7Tests(TestCase): """ Tests for L{PKCS7Type}. """ def test_type(self): """ L{PKCS7Type} is a type object. """ self.assertTrue(isinstance(PKCS7Type, type)) self.assertEqual(PKCS7Type.__name__, 'PKCS7') # XXX This doesn't currently work. # self.assertIdentical(PKCS7, PKCS7Type) # XXX Opposite results for all these following methods def test_type_is_signed_wrong_args(self): """ L{PKCS7Type.type_is_signed} raises L{TypeError} if called with any arguments. """ pkcs7 = load_pkcs7_data(FILETYPE_PEM, pkcs7Data) self.assertRaises(TypeError, pkcs7.type_is_signed, None) def test_type_is_signed(self): """ L{PKCS7Type.type_is_signed} returns C{True} if the PKCS7 object is of the type I{signed}. """ pkcs7 = load_pkcs7_data(FILETYPE_PEM, pkcs7Data) self.assertTrue(pkcs7.type_is_signed()) def test_type_is_enveloped_wrong_args(self): """ L{PKCS7Type.type_is_enveloped} raises L{TypeError} if called with any arguments. """ pkcs7 = load_pkcs7_data(FILETYPE_PEM, pkcs7Data) self.assertRaises(TypeError, pkcs7.type_is_enveloped, None) def test_type_is_enveloped(self): """ L{PKCS7Type.type_is_enveloped} returns C{False} if the PKCS7 object is not of the type I{enveloped}. """ pkcs7 = load_pkcs7_data(FILETYPE_PEM, pkcs7Data) self.assertFalse(pkcs7.type_is_enveloped()) def test_type_is_signedAndEnveloped_wrong_args(self): """ L{PKCS7Type.type_is_signedAndEnveloped} raises L{TypeError} if called with any arguments. """ pkcs7 = load_pkcs7_data(FILETYPE_PEM, pkcs7Data) self.assertRaises(TypeError, pkcs7.type_is_signedAndEnveloped, None) def test_type_is_signedAndEnveloped(self): """ L{PKCS7Type.type_is_signedAndEnveloped} returns C{False} if the PKCS7 object is not of the type I{signed and enveloped}. """ pkcs7 = load_pkcs7_data(FILETYPE_PEM, pkcs7Data) self.assertFalse(pkcs7.type_is_signedAndEnveloped()) def test_type_is_data(self): """ L{PKCS7Type.type_is_data} returns C{False} if the PKCS7 object is not of the type data. """ pkcs7 = load_pkcs7_data(FILETYPE_PEM, pkcs7Data) self.assertFalse(pkcs7.type_is_data()) def test_type_is_data_wrong_args(self): """ L{PKCS7Type.type_is_data} raises L{TypeError} if called with any arguments. """ pkcs7 = load_pkcs7_data(FILETYPE_PEM, pkcs7Data) self.assertRaises(TypeError, pkcs7.type_is_data, None) def test_get_type_name_wrong_args(self): """ L{PKCS7Type.get_type_name} raises L{TypeError} if called with any arguments. """ pkcs7 = load_pkcs7_data(FILETYPE_PEM, pkcs7Data) self.assertRaises(TypeError, pkcs7.get_type_name, None) def test_get_type_name(self): """ L{PKCS7Type.get_type_name} returns a C{str} giving the type name. """ pkcs7 = load_pkcs7_data(FILETYPE_PEM, pkcs7Data) self.assertEquals(pkcs7.get_type_name(), b('pkcs7-signedData')) def test_attribute(self): """ If an attribute other than one of the methods tested here is accessed on an instance of L{PKCS7Type}, L{AttributeError} is raised. """ pkcs7 = load_pkcs7_data(FILETYPE_PEM, pkcs7Data) self.assertRaises(AttributeError, getattr, pkcs7, "foo") class NetscapeSPKITests(TestCase, _PKeyInteractionTestsMixin): """ Tests for L{OpenSSL.crypto.NetscapeSPKI}. """ def signable(self): """ Return a new L{NetscapeSPKI} for use with signing tests. """ return NetscapeSPKI() def test_type(self): """ L{NetscapeSPKI} and L{NetscapeSPKIType} refer to the same type object and can be used to create instances of that type. """ self.assertIdentical(NetscapeSPKI, NetscapeSPKIType) self.assertConsistentType(NetscapeSPKI, 'NetscapeSPKI') def test_construction(self): """ L{NetscapeSPKI} returns an instance of L{NetscapeSPKIType}. """ nspki = NetscapeSPKI() self.assertTrue(isinstance(nspki, NetscapeSPKIType)) def test_invalid_attribute(self): """ Accessing a non-existent attribute of a L{NetscapeSPKI} instance causes an L{AttributeError} to be raised. """ nspki = NetscapeSPKI() self.assertRaises(AttributeError, lambda: nspki.foo) def test_b64_encode(self): """ L{NetscapeSPKI.b64_encode} encodes the certificate to a base64 blob. """ nspki = NetscapeSPKI() blob = nspki.b64_encode() self.assertTrue(isinstance(blob, bytes)) class RevokedTests(TestCase): """ Tests for L{OpenSSL.crypto.Revoked} """ def test_construction(self): """ Confirm we can create L{OpenSSL.crypto.Revoked}. Check that it is empty. """ revoked = Revoked() self.assertTrue(isinstance(revoked, Revoked)) self.assertEquals(type(revoked), Revoked) self.assertEquals(revoked.get_serial(), b('00')) self.assertEquals(revoked.get_rev_date(), None) self.assertEquals(revoked.get_reason(), None) def test_construction_wrong_args(self): """ Calling L{OpenSSL.crypto.Revoked} with any arguments results in a L{TypeError} being raised. """ self.assertRaises(TypeError, Revoked, None) self.assertRaises(TypeError, Revoked, 1) self.assertRaises(TypeError, Revoked, "foo") def test_serial(self): """ Confirm we can set and get serial numbers from L{OpenSSL.crypto.Revoked}. Confirm errors are handled with grace. """ revoked = Revoked() ret = revoked.set_serial(b('10b')) self.assertEquals(ret, None) ser = revoked.get_serial() self.assertEquals(ser, b('010B')) revoked.set_serial(b('31ppp')) # a type error would be nice ser = revoked.get_serial() self.assertEquals(ser, b('31')) self.assertRaises(ValueError, revoked.set_serial, b('pqrst')) self.assertRaises(TypeError, revoked.set_serial, 100) self.assertRaises(TypeError, revoked.get_serial, 1) self.assertRaises(TypeError, revoked.get_serial, None) self.assertRaises(TypeError, revoked.get_serial, "") def test_date(self): """ Confirm we can set and get revocation dates from L{OpenSSL.crypto.Revoked}. Confirm errors are handled with grace. """ revoked = Revoked() date = revoked.get_rev_date() self.assertEquals(date, None) now = b(datetime.now().strftime("%Y%m%d%H%M%SZ")) ret = revoked.set_rev_date(now) self.assertEqual(ret, None) date = revoked.get_rev_date() self.assertEqual(date, now) def test_reason(self): """ Confirm we can set and get revocation reasons from L{OpenSSL.crypto.Revoked}. The "get" need to work as "set". Likewise, each reason of all_reasons() must work. """ revoked = Revoked() for r in revoked.all_reasons(): for x in range(2): ret = revoked.set_reason(r) self.assertEquals(ret, None) reason = revoked.get_reason() self.assertEquals( reason.lower().replace(b(' '), b('')), r.lower().replace(b(' '), b(''))) r = reason # again with the resp of get revoked.set_reason(None) self.assertEqual(revoked.get_reason(), None) def test_set_reason_wrong_arguments(self): """ Calling L{OpenSSL.crypto.Revoked.set_reason} with other than one argument, or an argument which isn't a valid reason, results in L{TypeError} or L{ValueError} being raised. """ revoked = Revoked() self.assertRaises(TypeError, revoked.set_reason, 100) self.assertRaises(ValueError, revoked.set_reason, b('blue')) def test_get_reason_wrong_arguments(self): """ Calling L{OpenSSL.crypto.Revoked.get_reason} with any arguments results in L{TypeError} being raised. """ revoked = Revoked() self.assertRaises(TypeError, revoked.get_reason, None) self.assertRaises(TypeError, revoked.get_reason, 1) self.assertRaises(TypeError, revoked.get_reason, "foo") class CRLTests(TestCase): """ Tests for L{OpenSSL.crypto.CRL} """ cert = load_certificate(FILETYPE_PEM, cleartextCertificatePEM) pkey = load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM) def test_construction(self): """ Confirm we can create L{OpenSSL.crypto.CRL}. Check that it is empty """ crl = CRL() self.assertTrue( isinstance(crl, CRL) ) self.assertEqual(crl.get_revoked(), None) def test_construction_wrong_args(self): """ Calling L{OpenSSL.crypto.CRL} with any number of arguments results in a L{TypeError} being raised. """ self.assertRaises(TypeError, CRL, 1) self.assertRaises(TypeError, CRL, "") self.assertRaises(TypeError, CRL, None) def test_export(self): """ Use python to create a simple CRL with a revocation, and export the CRL in formats of PEM, DER and text. Those outputs are verified with the openssl program. """ crl = CRL() revoked = Revoked() now = b(datetime.now().strftime("%Y%m%d%H%M%SZ")) revoked.set_rev_date(now) revoked.set_serial(b('3ab')) revoked.set_reason(b('sUpErSeDEd')) crl.add_revoked(revoked) # PEM format dumped_crl = crl.export(self.cert, self.pkey, days=20) text = _runopenssl(dumped_crl, "crl", "-noout", "-text") text.index(b('Serial Number: 03AB')) text.index(b('Superseded')) text.index(b('Issuer: /C=US/ST=IL/L=Chicago/O=Testing/CN=Testing Root CA')) # DER format dumped_crl = crl.export(self.cert, self.pkey, FILETYPE_ASN1) text = _runopenssl(dumped_crl, "crl", "-noout", "-text", "-inform", "DER") text.index(b('Serial Number: 03AB')) text.index(b('Superseded')) text.index(b('Issuer: /C=US/ST=IL/L=Chicago/O=Testing/CN=Testing Root CA')) # text format dumped_text = crl.export(self.cert, self.pkey, type=FILETYPE_TEXT) self.assertEqual(text, dumped_text) def test_add_revoked_keyword(self): """ L{OpenSSL.CRL.add_revoked} accepts its single argument as the I{revoked} keyword argument. """ crl = CRL() revoked = Revoked() crl.add_revoked(revoked=revoked) self.assertTrue(isinstance(crl.get_revoked()[0], Revoked)) def test_export_wrong_args(self): """ Calling L{OpenSSL.CRL.export} with fewer than two or more than four arguments, or with arguments other than the certificate, private key, integer file type, and integer number of days it expects, results in a L{TypeError} being raised. """ crl = CRL() self.assertRaises(TypeError, crl.export) self.assertRaises(TypeError, crl.export, self.cert) self.assertRaises(TypeError, crl.export, self.cert, self.pkey, FILETYPE_PEM, 10, "foo") self.assertRaises(TypeError, crl.export, None, self.pkey, FILETYPE_PEM, 10) self.assertRaises(TypeError, crl.export, self.cert, None, FILETYPE_PEM, 10) self.assertRaises(TypeError, crl.export, self.cert, self.pkey, None, 10) self.assertRaises(TypeError, crl.export, self.cert, FILETYPE_PEM, None) def test_export_unknown_filetype(self): """ Calling L{OpenSSL.CRL.export} with a file type other than L{FILETYPE_PEM}, L{FILETYPE_ASN1}, or L{FILETYPE_TEXT} results in a L{ValueError} being raised. """ crl = CRL() self.assertRaises(ValueError, crl.export, self.cert, self.pkey, 100, 10) def test_get_revoked(self): """ Use python to create a simple CRL with two revocations. Get back the L{Revoked} using L{OpenSSL.CRL.get_revoked} and verify them. """ crl = CRL() revoked = Revoked() now = b(datetime.now().strftime("%Y%m%d%H%M%SZ")) revoked.set_rev_date(now) revoked.set_serial(b('3ab')) crl.add_revoked(revoked) revoked.set_serial(b('100')) revoked.set_reason(b('sUpErSeDEd')) crl.add_revoked(revoked) revs = crl.get_revoked() self.assertEqual(len(revs), 2) self.assertEqual(type(revs[0]), Revoked) self.assertEqual(type(revs[1]), Revoked) self.assertEqual(revs[0].get_serial(), b('03AB')) self.assertEqual(revs[1].get_serial(), b('0100')) self.assertEqual(revs[0].get_rev_date(), now) self.assertEqual(revs[1].get_rev_date(), now) def test_get_revoked_wrong_args(self): """ Calling L{OpenSSL.CRL.get_revoked} with any arguments results in a L{TypeError} being raised. """ crl = CRL() self.assertRaises(TypeError, crl.get_revoked, None) self.assertRaises(TypeError, crl.get_revoked, 1) self.assertRaises(TypeError, crl.get_revoked, "") self.assertRaises(TypeError, crl.get_revoked, "", 1, None) def test_add_revoked_wrong_args(self): """ Calling L{OpenSSL.CRL.add_revoked} with other than one argument results in a L{TypeError} being raised. """ crl = CRL() self.assertRaises(TypeError, crl.add_revoked) self.assertRaises(TypeError, crl.add_revoked, 1, 2) self.assertRaises(TypeError, crl.add_revoked, "foo", "bar") def test_load_crl(self): """ Load a known CRL and inspect its revocations. Both PEM and DER formats are loaded. """ crl = load_crl(FILETYPE_PEM, crlData) revs = crl.get_revoked() self.assertEqual(len(revs), 2) self.assertEqual(revs[0].get_serial(), b('03AB')) self.assertEqual(revs[0].get_reason(), None) self.assertEqual(revs[1].get_serial(), b('0100')) self.assertEqual(revs[1].get_reason(), b('Superseded')) der = _runopenssl(crlData, "crl", "-outform", "DER") crl = load_crl(FILETYPE_ASN1, der) revs = crl.get_revoked() self.assertEqual(len(revs), 2) self.assertEqual(revs[0].get_serial(), b('03AB')) self.assertEqual(revs[0].get_reason(), None) self.assertEqual(revs[1].get_serial(), b('0100')) self.assertEqual(revs[1].get_reason(), b('Superseded')) def test_load_crl_wrong_args(self): """ Calling L{OpenSSL.crypto.load_crl} with other than two arguments results in a L{TypeError} being raised. """ self.assertRaises(TypeError, load_crl) self.assertRaises(TypeError, load_crl, FILETYPE_PEM) self.assertRaises(TypeError, load_crl, FILETYPE_PEM, crlData, None) def test_load_crl_bad_filetype(self): """ Calling L{OpenSSL.crypto.load_crl} with an unknown file type raises a L{ValueError}. """ self.assertRaises(ValueError, load_crl, 100, crlData) def test_load_crl_bad_data(self): """ Calling L{OpenSSL.crypto.load_crl} with file data which can't be loaded raises a L{OpenSSL.crypto.Error}. """ self.assertRaises(Error, load_crl, FILETYPE_PEM, "hello, world") class SignVerifyTests(TestCase): """ Tests for L{OpenSSL.crypto.sign} and L{OpenSSL.crypto.verify}. """ def test_sign_verify(self): """ L{sign} generates a cryptographic signature which L{verify} can check. """ content = b( "It was a bright cold day in April, and the clocks were striking " "thirteen. Winston Smith, his chin nuzzled into his breast in an " "effort to escape the vile wind, slipped quickly through the " "glass doors of Victory Mansions, though not quickly enough to " "prevent a swirl of gritty dust from entering along with him.") # sign the content with this private key priv_key = load_privatekey(FILETYPE_PEM, root_key_pem) # verify the content with this cert good_cert = load_certificate(FILETYPE_PEM, root_cert_pem) # certificate unrelated to priv_key, used to trigger an error bad_cert = load_certificate(FILETYPE_PEM, server_cert_pem) for digest in ['md5', 'sha1']: sig = sign(priv_key, content, digest) # Verify the signature of content, will throw an exception if error. verify(good_cert, sig, content, digest) # This should fail because the certificate doesn't match the # private key that was used to sign the content. self.assertRaises(Error, verify, bad_cert, sig, content, digest) # This should fail because we've "tainted" the content after # signing it. self.assertRaises( Error, verify, good_cert, sig, content + b("tainted"), digest) # test that unknown digest types fail self.assertRaises( ValueError, sign, priv_key, content, "strange-digest") self.assertRaises( ValueError, verify, good_cert, sig, content, "strange-digest") def test_sign_nulls(self): """ L{sign} produces a signature for a string with embedded nulls. """ content = b("Watch out! \0 Did you see it?") priv_key = load_privatekey(FILETYPE_PEM, root_key_pem) good_cert = load_certificate(FILETYPE_PEM, root_cert_pem) sig = sign(priv_key, content, "sha1") verify(good_cert, sig, content, "sha1") if __name__ == '__main__': main() pyOpenSSL-0.13/OpenSSL/test/test_rand.py0000644000214500021450000001325211630175105020040 0ustar bb-slavebb-slave# Copyright (c) Frederick Dean # See LICENSE for details. """ Unit tests for L{OpenSSL.rand}. """ from unittest import main import os import stat from OpenSSL.test.util import TestCase, b from OpenSSL import rand class RandTests(TestCase): def test_bytes_wrong_args(self): """ L{OpenSSL.rand.bytes} raises L{TypeError} if called with the wrong number of arguments or with a non-C{int} argument. """ self.assertRaises(TypeError, rand.bytes) self.assertRaises(TypeError, rand.bytes, None) self.assertRaises(TypeError, rand.bytes, 3, None) # XXX Test failure of the malloc() in rand_bytes. def test_bytes(self): """ Verify that we can obtain bytes from rand_bytes() and that they are different each time. Test the parameter of rand_bytes() for bad values. """ b1 = rand.bytes(50) self.assertEqual(len(b1), 50) b2 = rand.bytes(num_bytes=50) # parameter by name self.assertNotEqual(b1, b2) # Hip, Hip, Horay! FIPS complaince b3 = rand.bytes(num_bytes=0) self.assertEqual(len(b3), 0) exc = self.assertRaises(ValueError, rand.bytes, -1) self.assertEqual(str(exc), "num_bytes must not be negative") def test_add_wrong_args(self): """ When called with the wrong number of arguments, or with arguments not of type C{str} and C{int}, L{OpenSSL.rand.add} raises L{TypeError}. """ self.assertRaises(TypeError, rand.add) self.assertRaises(TypeError, rand.add, b("foo"), None) self.assertRaises(TypeError, rand.add, None, 3) self.assertRaises(TypeError, rand.add, b("foo"), 3, None) def test_add(self): """ L{OpenSSL.rand.add} adds entropy to the PRNG. """ rand.add(b('hamburger'), 3) def test_seed_wrong_args(self): """ When called with the wrong number of arguments, or with a non-C{str} argument, L{OpenSSL.rand.seed} raises L{TypeError}. """ self.assertRaises(TypeError, rand.seed) self.assertRaises(TypeError, rand.seed, None) self.assertRaises(TypeError, rand.seed, b("foo"), None) def test_seed(self): """ L{OpenSSL.rand.seed} adds entropy to the PRNG. """ rand.seed(b('milk shake')) def test_status_wrong_args(self): """ L{OpenSSL.rand.status} raises L{TypeError} when called with any arguments. """ self.assertRaises(TypeError, rand.status, None) def test_status(self): """ L{OpenSSL.rand.status} returns C{True} if the PRNG has sufficient entropy, C{False} otherwise. """ # It's hard to know what it is actually going to return. Different # OpenSSL random engines decide differently whether they have enough # entropy or not. self.assertTrue(rand.status() in (1, 2)) def test_egd_wrong_args(self): """ L{OpenSSL.rand.egd} raises L{TypeError} when called with the wrong number of arguments or with arguments not of type C{str} and C{int}. """ self.assertRaises(TypeError, rand.egd) self.assertRaises(TypeError, rand.egd, None) self.assertRaises(TypeError, rand.egd, "foo", None) self.assertRaises(TypeError, rand.egd, None, 3) self.assertRaises(TypeError, rand.egd, "foo", 3, None) def test_egd_missing(self): """ L{OpenSSL.rand.egd} returns C{0} or C{-1} if the EGD socket passed to it does not exist. """ result = rand.egd(self.mktemp()) expected = (-1, 0) self.assertTrue( result in expected, "%r not in %r" % (result, expected)) def test_cleanup_wrong_args(self): """ L{OpenSSL.rand.cleanup} raises L{TypeError} when called with any arguments. """ self.assertRaises(TypeError, rand.cleanup, None) def test_cleanup(self): """ L{OpenSSL.rand.cleanup} releases the memory used by the PRNG and returns C{None}. """ self.assertIdentical(rand.cleanup(), None) def test_load_file_wrong_args(self): """ L{OpenSSL.rand.load_file} raises L{TypeError} when called the wrong number of arguments or arguments not of type C{str} and C{int}. """ self.assertRaises(TypeError, rand.load_file) self.assertRaises(TypeError, rand.load_file, "foo", None) self.assertRaises(TypeError, rand.load_file, None, 1) self.assertRaises(TypeError, rand.load_file, "foo", 1, None) def test_write_file_wrong_args(self): """ L{OpenSSL.rand.write_file} raises L{TypeError} when called with the wrong number of arguments or a non-C{str} argument. """ self.assertRaises(TypeError, rand.write_file) self.assertRaises(TypeError, rand.write_file, None) self.assertRaises(TypeError, rand.write_file, "foo", None) def test_files(self): """ Test reading and writing of files via rand functions. """ # Write random bytes to a file tmpfile = self.mktemp() # Make sure it exists (so cleanup definitely succeeds) fObj = open(tmpfile, 'w') fObj.close() try: rand.write_file(tmpfile) # Verify length of written file size = os.stat(tmpfile)[stat.ST_SIZE] self.assertEquals(size, 1024) # Read random bytes from file rand.load_file(tmpfile) rand.load_file(tmpfile, 4) # specify a length finally: # Cleanup os.unlink(tmpfile) if __name__ == '__main__': main() pyOpenSSL-0.13/OpenSSL/test/test_ssl.py0000644000214500021450000021426611630175105017725 0ustar bb-slavebb-slave# Copyright (C) Jean-Paul Calderone # See LICENSE for details. """ Unit tests for L{OpenSSL.SSL}. """ from gc import collect from errno import ECONNREFUSED, EINPROGRESS, EWOULDBLOCK from sys import platform, version_info from socket import error, socket from os import makedirs from os.path import join from unittest import main from weakref import ref from OpenSSL.crypto import TYPE_RSA, FILETYPE_PEM from OpenSSL.crypto import PKey, X509, X509Extension from OpenSSL.crypto import dump_privatekey, load_privatekey from OpenSSL.crypto import dump_certificate, load_certificate from OpenSSL.SSL import OPENSSL_VERSION_NUMBER, SSLEAY_VERSION, SSLEAY_CFLAGS from OpenSSL.SSL import SSLEAY_PLATFORM, SSLEAY_DIR, SSLEAY_BUILT_ON from OpenSSL.SSL import SENT_SHUTDOWN, RECEIVED_SHUTDOWN from OpenSSL.SSL import SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD from OpenSSL.SSL import OP_NO_SSLv2, OP_NO_SSLv3, OP_SINGLE_DH_USE from OpenSSL.SSL import ( VERIFY_PEER, VERIFY_FAIL_IF_NO_PEER_CERT, VERIFY_CLIENT_ONCE, VERIFY_NONE) from OpenSSL.SSL import ( Error, SysCallError, WantReadError, ZeroReturnError, SSLeay_version) from OpenSSL.SSL import Context, ContextType, Connection, ConnectionType from OpenSSL.test.util import TestCase, bytes, b from OpenSSL.test.test_crypto import ( cleartextCertificatePEM, cleartextPrivateKeyPEM) from OpenSSL.test.test_crypto import ( client_cert_pem, client_key_pem, server_cert_pem, server_key_pem, root_cert_pem) try: from OpenSSL.SSL import OP_NO_QUERY_MTU except ImportError: OP_NO_QUERY_MTU = None try: from OpenSSL.SSL import OP_COOKIE_EXCHANGE except ImportError: OP_COOKIE_EXCHANGE = None try: from OpenSSL.SSL import OP_NO_TICKET except ImportError: OP_NO_TICKET = None from OpenSSL.SSL import ( SSL_ST_CONNECT, SSL_ST_ACCEPT, SSL_ST_MASK, SSL_ST_INIT, SSL_ST_BEFORE, SSL_ST_OK, SSL_ST_RENEGOTIATE, SSL_CB_LOOP, SSL_CB_EXIT, SSL_CB_READ, SSL_CB_WRITE, SSL_CB_ALERT, SSL_CB_READ_ALERT, SSL_CB_WRITE_ALERT, SSL_CB_ACCEPT_LOOP, SSL_CB_ACCEPT_EXIT, SSL_CB_CONNECT_LOOP, SSL_CB_CONNECT_EXIT, SSL_CB_HANDSHAKE_START, SSL_CB_HANDSHAKE_DONE) # openssl dhparam 128 -out dh-128.pem (note that 128 is a small number of bits # to use) dhparam = """\ -----BEGIN DH PARAMETERS----- MBYCEQCobsg29c9WZP/54oAPcwiDAgEC -----END DH PARAMETERS----- """ def verify_cb(conn, cert, errnum, depth, ok): return ok def socket_pair(): """ Establish and return a pair of network sockets connected to each other. """ # Connect a pair of sockets port = socket() port.bind(('', 0)) port.listen(1) client = socket() client.setblocking(False) client.connect_ex(("127.0.0.1", port.getsockname()[1])) client.setblocking(True) server = port.accept()[0] # Let's pass some unencrypted data to make sure our socket connection is # fine. Just one byte, so we don't have to worry about buffers getting # filled up or fragmentation. server.send(b("x")) assert client.recv(1024) == b("x") client.send(b("y")) assert server.recv(1024) == b("y") # Most of our callers want non-blocking sockets, make it easy for them. server.setblocking(False) client.setblocking(False) return (server, client) def handshake(client, server): conns = [client, server] while conns: for conn in conns: try: conn.do_handshake() except WantReadError: pass else: conns.remove(conn) def _create_certificate_chain(): """ Construct and return a chain of certificates. 1. A new self-signed certificate authority certificate (cacert) 2. A new intermediate certificate signed by cacert (icert) 3. A new server certificate signed by icert (scert) """ caext = X509Extension(b('basicConstraints'), False, b('CA:true')) # Step 1 cakey = PKey() cakey.generate_key(TYPE_RSA, 512) cacert = X509() cacert.get_subject().commonName = "Authority Certificate" cacert.set_issuer(cacert.get_subject()) cacert.set_pubkey(cakey) cacert.set_notBefore(b("20000101000000Z")) cacert.set_notAfter(b("20200101000000Z")) cacert.add_extensions([caext]) cacert.set_serial_number(0) cacert.sign(cakey, "sha1") # Step 2 ikey = PKey() ikey.generate_key(TYPE_RSA, 512) icert = X509() icert.get_subject().commonName = "Intermediate Certificate" icert.set_issuer(cacert.get_subject()) icert.set_pubkey(ikey) icert.set_notBefore(b("20000101000000Z")) icert.set_notAfter(b("20200101000000Z")) icert.add_extensions([caext]) icert.set_serial_number(0) icert.sign(cakey, "sha1") # Step 3 skey = PKey() skey.generate_key(TYPE_RSA, 512) scert = X509() scert.get_subject().commonName = "Server Certificate" scert.set_issuer(icert.get_subject()) scert.set_pubkey(skey) scert.set_notBefore(b("20000101000000Z")) scert.set_notAfter(b("20200101000000Z")) scert.add_extensions([ X509Extension(b('basicConstraints'), True, b('CA:false'))]) scert.set_serial_number(0) scert.sign(ikey, "sha1") return [(cakey, cacert), (ikey, icert), (skey, scert)] class _LoopbackMixin: """ Helper mixin which defines methods for creating a connected socket pair and for forcing two connected SSL sockets to talk to each other via memory BIOs. """ def _loopback(self): (server, client) = socket_pair() ctx = Context(TLSv1_METHOD) ctx.use_privatekey(load_privatekey(FILETYPE_PEM, server_key_pem)) ctx.use_certificate(load_certificate(FILETYPE_PEM, server_cert_pem)) server = Connection(ctx, server) server.set_accept_state() client = Connection(Context(TLSv1_METHOD), client) client.set_connect_state() handshake(client, server) server.setblocking(True) client.setblocking(True) return server, client def _interactInMemory(self, client_conn, server_conn): """ Try to read application bytes from each of the two L{Connection} objects. Copy bytes back and forth between their send/receive buffers for as long as there is anything to copy. When there is nothing more to copy, return C{None}. If one of them actually manages to deliver some application bytes, return a two-tuple of the connection from which the bytes were read and the bytes themselves. """ wrote = True while wrote: # Loop until neither side has anything to say wrote = False # Copy stuff from each side's send buffer to the other side's # receive buffer. for (read, write) in [(client_conn, server_conn), (server_conn, client_conn)]: # Give the side a chance to generate some more bytes, or # succeed. try: data = read.recv(2 ** 16) except WantReadError: # It didn't succeed, so we'll hope it generated some # output. pass else: # It did succeed, so we'll stop now and let the caller deal # with it. return (read, data) while True: # Keep copying as long as there's more stuff there. try: dirty = read.bio_read(4096) except WantReadError: # Okay, nothing more waiting to be sent. Stop # processing this send buffer. break else: # Keep track of the fact that someone generated some # output. wrote = True write.bio_write(dirty) class VersionTests(TestCase): """ Tests for version information exposed by L{OpenSSL.SSL.SSLeay_version} and L{OpenSSL.SSL.OPENSSL_VERSION_NUMBER}. """ def test_OPENSSL_VERSION_NUMBER(self): """ L{OPENSSL_VERSION_NUMBER} is an integer with status in the low byte and the patch, fix, minor, and major versions in the nibbles above that. """ self.assertTrue(isinstance(OPENSSL_VERSION_NUMBER, int)) def test_SSLeay_version(self): """ L{SSLeay_version} takes a version type indicator and returns one of a number of version strings based on that indicator. """ versions = {} for t in [SSLEAY_VERSION, SSLEAY_CFLAGS, SSLEAY_BUILT_ON, SSLEAY_PLATFORM, SSLEAY_DIR]: version = SSLeay_version(t) versions[version] = t self.assertTrue(isinstance(version, bytes)) self.assertEqual(len(versions), 5) class ContextTests(TestCase, _LoopbackMixin): """ Unit tests for L{OpenSSL.SSL.Context}. """ def test_method(self): """ L{Context} can be instantiated with one of L{SSLv2_METHOD}, L{SSLv3_METHOD}, L{SSLv23_METHOD}, or L{TLSv1_METHOD}. """ for meth in [SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD]: Context(meth) try: Context(SSLv2_METHOD) except ValueError: # Some versions of OpenSSL have SSLv2, some don't. # Difficult to say in advance. pass self.assertRaises(TypeError, Context, "") self.assertRaises(ValueError, Context, 10) def test_type(self): """ L{Context} and L{ContextType} refer to the same type object and can be used to create instances of that type. """ self.assertIdentical(Context, ContextType) self.assertConsistentType(Context, 'Context', TLSv1_METHOD) def test_use_privatekey(self): """ L{Context.use_privatekey} takes an L{OpenSSL.crypto.PKey} instance. """ key = PKey() key.generate_key(TYPE_RSA, 128) ctx = Context(TLSv1_METHOD) ctx.use_privatekey(key) self.assertRaises(TypeError, ctx.use_privatekey, "") def test_set_app_data_wrong_args(self): """ L{Context.set_app_data} raises L{TypeError} if called with other than one argument. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.set_app_data) self.assertRaises(TypeError, context.set_app_data, None, None) def test_get_app_data_wrong_args(self): """ L{Context.get_app_data} raises L{TypeError} if called with any arguments. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.get_app_data, None) def test_app_data(self): """ L{Context.set_app_data} stores an object for later retrieval using L{Context.get_app_data}. """ app_data = object() context = Context(TLSv1_METHOD) context.set_app_data(app_data) self.assertIdentical(context.get_app_data(), app_data) def test_set_options_wrong_args(self): """ L{Context.set_options} raises L{TypeError} if called with the wrong number of arguments or a non-C{int} argument. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.set_options) self.assertRaises(TypeError, context.set_options, None) self.assertRaises(TypeError, context.set_options, 1, None) def test_set_timeout_wrong_args(self): """ L{Context.set_timeout} raises L{TypeError} if called with the wrong number of arguments or a non-C{int} argument. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.set_timeout) self.assertRaises(TypeError, context.set_timeout, None) self.assertRaises(TypeError, context.set_timeout, 1, None) def test_get_timeout_wrong_args(self): """ L{Context.get_timeout} raises L{TypeError} if called with any arguments. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.get_timeout, None) def test_timeout(self): """ L{Context.set_timeout} sets the session timeout for all connections created using the context object. L{Context.get_timeout} retrieves this value. """ context = Context(TLSv1_METHOD) context.set_timeout(1234) self.assertEquals(context.get_timeout(), 1234) def test_set_verify_depth_wrong_args(self): """ L{Context.set_verify_depth} raises L{TypeError} if called with the wrong number of arguments or a non-C{int} argument. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.set_verify_depth) self.assertRaises(TypeError, context.set_verify_depth, None) self.assertRaises(TypeError, context.set_verify_depth, 1, None) def test_get_verify_depth_wrong_args(self): """ L{Context.get_verify_depth} raises L{TypeError} if called with any arguments. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.get_verify_depth, None) def test_verify_depth(self): """ L{Context.set_verify_depth} sets the number of certificates in a chain to follow before giving up. The value can be retrieved with L{Context.get_verify_depth}. """ context = Context(TLSv1_METHOD) context.set_verify_depth(11) self.assertEquals(context.get_verify_depth(), 11) def _write_encrypted_pem(self, passphrase): """ Write a new private key out to a new file, encrypted using the given passphrase. Return the path to the new file. """ key = PKey() key.generate_key(TYPE_RSA, 128) pemFile = self.mktemp() fObj = open(pemFile, 'w') pem = dump_privatekey(FILETYPE_PEM, key, "blowfish", passphrase) fObj.write(pem.decode('ascii')) fObj.close() return pemFile def test_set_passwd_cb_wrong_args(self): """ L{Context.set_passwd_cb} raises L{TypeError} if called with the wrong arguments or with a non-callable first argument. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.set_passwd_cb) self.assertRaises(TypeError, context.set_passwd_cb, None) self.assertRaises(TypeError, context.set_passwd_cb, lambda: None, None, None) def test_set_passwd_cb(self): """ L{Context.set_passwd_cb} accepts a callable which will be invoked when a private key is loaded from an encrypted PEM. """ passphrase = b("foobar") pemFile = self._write_encrypted_pem(passphrase) calledWith = [] def passphraseCallback(maxlen, verify, extra): calledWith.append((maxlen, verify, extra)) return passphrase context = Context(TLSv1_METHOD) context.set_passwd_cb(passphraseCallback) context.use_privatekey_file(pemFile) self.assertTrue(len(calledWith), 1) self.assertTrue(isinstance(calledWith[0][0], int)) self.assertTrue(isinstance(calledWith[0][1], int)) self.assertEqual(calledWith[0][2], None) def test_passwd_callback_exception(self): """ L{Context.use_privatekey_file} propagates any exception raised by the passphrase callback. """ pemFile = self._write_encrypted_pem(b("monkeys are nice")) def passphraseCallback(maxlen, verify, extra): raise RuntimeError("Sorry, I am a fail.") context = Context(TLSv1_METHOD) context.set_passwd_cb(passphraseCallback) self.assertRaises(RuntimeError, context.use_privatekey_file, pemFile) def test_passwd_callback_false(self): """ L{Context.use_privatekey_file} raises L{OpenSSL.SSL.Error} if the passphrase callback returns a false value. """ pemFile = self._write_encrypted_pem(b("monkeys are nice")) def passphraseCallback(maxlen, verify, extra): return None context = Context(TLSv1_METHOD) context.set_passwd_cb(passphraseCallback) self.assertRaises(Error, context.use_privatekey_file, pemFile) def test_passwd_callback_non_string(self): """ L{Context.use_privatekey_file} raises L{OpenSSL.SSL.Error} if the passphrase callback returns a true non-string value. """ pemFile = self._write_encrypted_pem(b("monkeys are nice")) def passphraseCallback(maxlen, verify, extra): return 10 context = Context(TLSv1_METHOD) context.set_passwd_cb(passphraseCallback) self.assertRaises(Error, context.use_privatekey_file, pemFile) def test_passwd_callback_too_long(self): """ If the passphrase returned by the passphrase callback returns a string longer than the indicated maximum length, it is truncated. """ # A priori knowledge! passphrase = b("x") * 1024 pemFile = self._write_encrypted_pem(passphrase) def passphraseCallback(maxlen, verify, extra): assert maxlen == 1024 return passphrase + b("y") context = Context(TLSv1_METHOD) context.set_passwd_cb(passphraseCallback) # This shall succeed because the truncated result is the correct # passphrase. context.use_privatekey_file(pemFile) def test_set_info_callback(self): """ L{Context.set_info_callback} accepts a callable which will be invoked when certain information about an SSL connection is available. """ (server, client) = socket_pair() clientSSL = Connection(Context(TLSv1_METHOD), client) clientSSL.set_connect_state() called = [] def info(conn, where, ret): called.append((conn, where, ret)) context = Context(TLSv1_METHOD) context.set_info_callback(info) context.use_certificate( load_certificate(FILETYPE_PEM, cleartextCertificatePEM)) context.use_privatekey( load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM)) serverSSL = Connection(context, server) serverSSL.set_accept_state() while not called: for ssl in clientSSL, serverSSL: try: ssl.do_handshake() except WantReadError: pass # Kind of lame. Just make sure it got called somehow. self.assertTrue(called) def _load_verify_locations_test(self, *args): """ Create a client context which will verify the peer certificate and call its C{load_verify_locations} method with C{*args}. Then connect it to a server and ensure that the handshake succeeds. """ (server, client) = socket_pair() clientContext = Context(TLSv1_METHOD) clientContext.load_verify_locations(*args) # Require that the server certificate verify properly or the # connection will fail. clientContext.set_verify( VERIFY_PEER, lambda conn, cert, errno, depth, preverify_ok: preverify_ok) clientSSL = Connection(clientContext, client) clientSSL.set_connect_state() serverContext = Context(TLSv1_METHOD) serverContext.use_certificate( load_certificate(FILETYPE_PEM, cleartextCertificatePEM)) serverContext.use_privatekey( load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM)) serverSSL = Connection(serverContext, server) serverSSL.set_accept_state() # Without load_verify_locations above, the handshake # will fail: # Error: [('SSL routines', 'SSL3_GET_SERVER_CERTIFICATE', # 'certificate verify failed')] handshake(clientSSL, serverSSL) cert = clientSSL.get_peer_certificate() self.assertEqual(cert.get_subject().CN, 'Testing Root CA') def test_load_verify_file(self): """ L{Context.load_verify_locations} accepts a file name and uses the certificates within for verification purposes. """ cafile = self.mktemp() fObj = open(cafile, 'w') fObj.write(cleartextCertificatePEM.decode('ascii')) fObj.close() self._load_verify_locations_test(cafile) def test_load_verify_invalid_file(self): """ L{Context.load_verify_locations} raises L{Error} when passed a non-existent cafile. """ clientContext = Context(TLSv1_METHOD) self.assertRaises( Error, clientContext.load_verify_locations, self.mktemp()) def test_load_verify_directory(self): """ L{Context.load_verify_locations} accepts a directory name and uses the certificates within for verification purposes. """ capath = self.mktemp() makedirs(capath) # Hash values computed manually with c_rehash to avoid depending on # c_rehash in the test suite. One is from OpenSSL 0.9.8, the other # from OpenSSL 1.0.0. for name in ['c7adac82.0', 'c3705638.0']: cafile = join(capath, name) fObj = open(cafile, 'w') fObj.write(cleartextCertificatePEM.decode('ascii')) fObj.close() self._load_verify_locations_test(None, capath) def test_load_verify_locations_wrong_args(self): """ L{Context.load_verify_locations} raises L{TypeError} if called with the wrong number of arguments or with non-C{str} arguments. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.load_verify_locations) self.assertRaises(TypeError, context.load_verify_locations, object()) self.assertRaises(TypeError, context.load_verify_locations, object(), object()) self.assertRaises(TypeError, context.load_verify_locations, None, None, None) if platform == "win32": "set_default_verify_paths appears not to work on Windows. " "See LP#404343 and LP#404344." else: def test_set_default_verify_paths(self): """ L{Context.set_default_verify_paths} causes the platform-specific CA certificate locations to be used for verification purposes. """ # Testing this requires a server with a certificate signed by one of # the CAs in the platform CA location. Getting one of those costs # money. Fortunately (or unfortunately, depending on your # perspective), it's easy to think of a public server on the # internet which has such a certificate. Connecting to the network # in a unit test is bad, but it's the only way I can think of to # really test this. -exarkun # Arg, verisign.com doesn't speak TLSv1 context = Context(SSLv3_METHOD) context.set_default_verify_paths() context.set_verify( VERIFY_PEER, lambda conn, cert, errno, depth, preverify_ok: preverify_ok) client = socket() client.connect(('verisign.com', 443)) clientSSL = Connection(context, client) clientSSL.set_connect_state() clientSSL.do_handshake() clientSSL.send('GET / HTTP/1.0\r\n\r\n') self.assertTrue(clientSSL.recv(1024)) def test_set_default_verify_paths_signature(self): """ L{Context.set_default_verify_paths} takes no arguments and raises L{TypeError} if given any. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.set_default_verify_paths, None) self.assertRaises(TypeError, context.set_default_verify_paths, 1) self.assertRaises(TypeError, context.set_default_verify_paths, "") def test_add_extra_chain_cert_invalid_cert(self): """ L{Context.add_extra_chain_cert} raises L{TypeError} if called with other than one argument or if called with an object which is not an instance of L{X509}. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.add_extra_chain_cert) self.assertRaises(TypeError, context.add_extra_chain_cert, object()) self.assertRaises(TypeError, context.add_extra_chain_cert, object(), object()) def _handshake_test(self, serverContext, clientContext): """ Verify that a client and server created with the given contexts can successfully handshake and communicate. """ serverSocket, clientSocket = socket_pair() server = Connection(serverContext, serverSocket) server.set_accept_state() client = Connection(clientContext, clientSocket) client.set_connect_state() # Make them talk to each other. # self._interactInMemory(client, server) for i in range(3): for s in [client, server]: try: s.do_handshake() except WantReadError: pass def test_add_extra_chain_cert(self): """ L{Context.add_extra_chain_cert} accepts an L{X509} instance to add to the certificate chain. See L{_create_certificate_chain} for the details of the certificate chain tested. The chain is tested by starting a server with scert and connecting to it with a client which trusts cacert and requires verification to succeed. """ chain = _create_certificate_chain() [(cakey, cacert), (ikey, icert), (skey, scert)] = chain # Dump the CA certificate to a file because that's the only way to load # it as a trusted CA in the client context. for cert, name in [(cacert, 'ca.pem'), (icert, 'i.pem'), (scert, 's.pem')]: fObj = open(name, 'w') fObj.write(dump_certificate(FILETYPE_PEM, cert).decode('ascii')) fObj.close() for key, name in [(cakey, 'ca.key'), (ikey, 'i.key'), (skey, 's.key')]: fObj = open(name, 'w') fObj.write(dump_privatekey(FILETYPE_PEM, key).decode('ascii')) fObj.close() # Create the server context serverContext = Context(TLSv1_METHOD) serverContext.use_privatekey(skey) serverContext.use_certificate(scert) # The client already has cacert, we only need to give them icert. serverContext.add_extra_chain_cert(icert) # Create the client clientContext = Context(TLSv1_METHOD) clientContext.set_verify( VERIFY_PEER | VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb) clientContext.load_verify_locations('ca.pem') # Try it out. self._handshake_test(serverContext, clientContext) def test_use_certificate_chain_file(self): """ L{Context.use_certificate_chain_file} reads a certificate chain from the specified file. The chain is tested by starting a server with scert and connecting to it with a client which trusts cacert and requires verification to succeed. """ chain = _create_certificate_chain() [(cakey, cacert), (ikey, icert), (skey, scert)] = chain # Write out the chain file. chainFile = self.mktemp() fObj = open(chainFile, 'w') # Most specific to least general. fObj.write(dump_certificate(FILETYPE_PEM, scert).decode('ascii')) fObj.write(dump_certificate(FILETYPE_PEM, icert).decode('ascii')) fObj.write(dump_certificate(FILETYPE_PEM, cacert).decode('ascii')) fObj.close() serverContext = Context(TLSv1_METHOD) serverContext.use_certificate_chain_file(chainFile) serverContext.use_privatekey(skey) fObj = open('ca.pem', 'w') fObj.write(dump_certificate(FILETYPE_PEM, cacert).decode('ascii')) fObj.close() clientContext = Context(TLSv1_METHOD) clientContext.set_verify( VERIFY_PEER | VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb) clientContext.load_verify_locations('ca.pem') self._handshake_test(serverContext, clientContext) # XXX load_client_ca # XXX set_session_id def test_get_verify_mode_wrong_args(self): """ L{Context.get_verify_mode} raises L{TypeError} if called with any arguments. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.get_verify_mode, None) def test_get_verify_mode(self): """ L{Context.get_verify_mode} returns the verify mode flags previously passed to L{Context.set_verify}. """ context = Context(TLSv1_METHOD) self.assertEquals(context.get_verify_mode(), 0) context.set_verify( VERIFY_PEER | VERIFY_CLIENT_ONCE, lambda *args: None) self.assertEquals( context.get_verify_mode(), VERIFY_PEER | VERIFY_CLIENT_ONCE) def test_load_tmp_dh_wrong_args(self): """ L{Context.load_tmp_dh} raises L{TypeError} if called with the wrong number of arguments or with a non-C{str} argument. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.load_tmp_dh) self.assertRaises(TypeError, context.load_tmp_dh, "foo", None) self.assertRaises(TypeError, context.load_tmp_dh, object()) def test_load_tmp_dh_missing_file(self): """ L{Context.load_tmp_dh} raises L{OpenSSL.SSL.Error} if the specified file does not exist. """ context = Context(TLSv1_METHOD) self.assertRaises(Error, context.load_tmp_dh, "hello") def test_load_tmp_dh(self): """ L{Context.load_tmp_dh} loads Diffie-Hellman parameters from the specified file. """ context = Context(TLSv1_METHOD) dhfilename = self.mktemp() dhfile = open(dhfilename, "w") dhfile.write(dhparam) dhfile.close() context.load_tmp_dh(dhfilename) # XXX What should I assert here? -exarkun def test_set_cipher_list(self): """ L{Context.set_cipher_list} accepts a C{str} naming the ciphers which connections created with the context object will be able to choose from. """ context = Context(TLSv1_METHOD) context.set_cipher_list("hello world:EXP-RC4-MD5") conn = Connection(context, None) self.assertEquals(conn.get_cipher_list(), ["EXP-RC4-MD5"]) class ServerNameCallbackTests(TestCase, _LoopbackMixin): """ Tests for L{Context.set_tlsext_servername_callback} and its interaction with L{Connection}. """ def test_wrong_args(self): """ L{Context.set_tlsext_servername_callback} raises L{TypeError} if called with other than one argument. """ context = Context(TLSv1_METHOD) self.assertRaises(TypeError, context.set_tlsext_servername_callback) self.assertRaises( TypeError, context.set_tlsext_servername_callback, 1, 2) def test_old_callback_forgotten(self): """ If L{Context.set_tlsext_servername_callback} is used to specify a new callback, the one it replaces is dereferenced. """ def callback(connection): pass def replacement(connection): pass context = Context(TLSv1_METHOD) context.set_tlsext_servername_callback(callback) tracker = ref(callback) del callback context.set_tlsext_servername_callback(replacement) collect() self.assertIdentical(None, tracker()) def test_no_servername(self): """ When a client specifies no server name, the callback passed to L{Context.set_tlsext_servername_callback} is invoked and the result of L{Connection.get_servername} is C{None}. """ args = [] def servername(conn): args.append((conn, conn.get_servername())) context = Context(TLSv1_METHOD) context.set_tlsext_servername_callback(servername) # Lose our reference to it. The Context is responsible for keeping it # alive now. del servername collect() # Necessary to actually accept the connection context.use_privatekey(load_privatekey(FILETYPE_PEM, server_key_pem)) context.use_certificate(load_certificate(FILETYPE_PEM, server_cert_pem)) # Do a little connection to trigger the logic server = Connection(context, None) server.set_accept_state() client = Connection(Context(TLSv1_METHOD), None) client.set_connect_state() self._interactInMemory(server, client) self.assertEqual([(server, None)], args) def test_servername(self): """ When a client specifies a server name in its hello message, the callback passed to L{Contexts.set_tlsext_servername_callback} is invoked and the result of L{Connection.get_servername} is that server name. """ args = [] def servername(conn): args.append((conn, conn.get_servername())) context = Context(TLSv1_METHOD) context.set_tlsext_servername_callback(servername) # Necessary to actually accept the connection context.use_privatekey(load_privatekey(FILETYPE_PEM, server_key_pem)) context.use_certificate(load_certificate(FILETYPE_PEM, server_cert_pem)) # Do a little connection to trigger the logic server = Connection(context, None) server.set_accept_state() client = Connection(Context(TLSv1_METHOD), None) client.set_connect_state() client.set_tlsext_host_name(b("foo1.example.com")) self._interactInMemory(server, client) self.assertEqual([(server, b("foo1.example.com"))], args) class ConnectionTests(TestCase, _LoopbackMixin): """ Unit tests for L{OpenSSL.SSL.Connection}. """ # XXX want_write # XXX want_read # XXX get_peer_certificate -> None # XXX sock_shutdown # XXX master_key -> TypeError # XXX server_random -> TypeError # XXX state_string # XXX connect -> TypeError # XXX connect_ex -> TypeError # XXX set_connect_state -> TypeError # XXX set_accept_state -> TypeError # XXX renegotiate_pending # XXX do_handshake -> TypeError # XXX bio_read -> TypeError # XXX recv -> TypeError # XXX send -> TypeError # XXX bio_write -> TypeError def test_type(self): """ L{Connection} and L{ConnectionType} refer to the same type object and can be used to create instances of that type. """ self.assertIdentical(Connection, ConnectionType) ctx = Context(TLSv1_METHOD) self.assertConsistentType(Connection, 'Connection', ctx, None) def test_get_context(self): """ L{Connection.get_context} returns the L{Context} instance used to construct the L{Connection} instance. """ context = Context(TLSv1_METHOD) connection = Connection(context, None) self.assertIdentical(connection.get_context(), context) def test_get_context_wrong_args(self): """ L{Connection.get_context} raises L{TypeError} if called with any arguments. """ connection = Connection(Context(TLSv1_METHOD), None) self.assertRaises(TypeError, connection.get_context, None) def test_set_context_wrong_args(self): """ L{Connection.set_context} raises L{TypeError} if called with a non-L{Context} instance argument or with any number of arguments other than 1. """ ctx = Context(TLSv1_METHOD) connection = Connection(ctx, None) self.assertRaises(TypeError, connection.set_context) self.assertRaises(TypeError, connection.set_context, object()) self.assertRaises(TypeError, connection.set_context, "hello") self.assertRaises(TypeError, connection.set_context, 1) self.assertRaises(TypeError, connection.set_context, 1, 2) self.assertRaises( TypeError, connection.set_context, Context(TLSv1_METHOD), 2) self.assertIdentical(ctx, connection.get_context()) def test_set_context(self): """ L{Connection.set_context} specifies a new L{Context} instance to be used for the connection. """ original = Context(SSLv23_METHOD) replacement = Context(TLSv1_METHOD) connection = Connection(original, None) connection.set_context(replacement) self.assertIdentical(replacement, connection.get_context()) # Lose our references to the contexts, just in case the Connection isn't # properly managing its own contributions to their reference counts. del original, replacement collect() def test_set_tlsext_host_name_wrong_args(self): """ If L{Connection.set_tlsext_host_name} is called with a non-byte string argument or a byte string with an embedded NUL or other than one argument, L{TypeError} is raised. """ conn = Connection(Context(TLSv1_METHOD), None) self.assertRaises(TypeError, conn.set_tlsext_host_name) self.assertRaises(TypeError, conn.set_tlsext_host_name, object()) self.assertRaises(TypeError, conn.set_tlsext_host_name, 123, 456) self.assertRaises( TypeError, conn.set_tlsext_host_name, b("with\0null")) if version_info >= (3,): # On Python 3.x, don't accidentally implicitly convert from text. self.assertRaises( TypeError, conn.set_tlsext_host_name, b("example.com").decode("ascii")) def test_get_servername_wrong_args(self): """ L{Connection.get_servername} raises L{TypeError} if called with any arguments. """ connection = Connection(Context(TLSv1_METHOD), None) self.assertRaises(TypeError, connection.get_servername, object()) self.assertRaises(TypeError, connection.get_servername, 1) self.assertRaises(TypeError, connection.get_servername, "hello") def test_pending(self): """ L{Connection.pending} returns the number of bytes available for immediate read. """ connection = Connection(Context(TLSv1_METHOD), None) self.assertEquals(connection.pending(), 0) def test_pending_wrong_args(self): """ L{Connection.pending} raises L{TypeError} if called with any arguments. """ connection = Connection(Context(TLSv1_METHOD), None) self.assertRaises(TypeError, connection.pending, None) def test_connect_wrong_args(self): """ L{Connection.connect} raises L{TypeError} if called with a non-address argument or with the wrong number of arguments. """ connection = Connection(Context(TLSv1_METHOD), socket()) self.assertRaises(TypeError, connection.connect, None) self.assertRaises(TypeError, connection.connect) self.assertRaises(TypeError, connection.connect, ("127.0.0.1", 1), None) def test_connect_refused(self): """ L{Connection.connect} raises L{socket.error} if the underlying socket connect method raises it. """ client = socket() context = Context(TLSv1_METHOD) clientSSL = Connection(context, client) exc = self.assertRaises(error, clientSSL.connect, ("127.0.0.1", 1)) self.assertEquals(exc.args[0], ECONNREFUSED) def test_connect(self): """ L{Connection.connect} establishes a connection to the specified address. """ port = socket() port.bind(('', 0)) port.listen(3) clientSSL = Connection(Context(TLSv1_METHOD), socket()) clientSSL.connect(('127.0.0.1', port.getsockname()[1])) # XXX An assertion? Or something? if platform == "darwin": "connect_ex sometimes causes a kernel panic on OS X 10.6.4" else: def test_connect_ex(self): """ If there is a connection error, L{Connection.connect_ex} returns the errno instead of raising an exception. """ port = socket() port.bind(('', 0)) port.listen(3) clientSSL = Connection(Context(TLSv1_METHOD), socket()) clientSSL.setblocking(False) result = clientSSL.connect_ex(port.getsockname()) expected = (EINPROGRESS, EWOULDBLOCK) self.assertTrue( result in expected, "%r not in %r" % (result, expected)) def test_accept_wrong_args(self): """ L{Connection.accept} raises L{TypeError} if called with any arguments. """ connection = Connection(Context(TLSv1_METHOD), socket()) self.assertRaises(TypeError, connection.accept, None) def test_accept(self): """ L{Connection.accept} accepts a pending connection attempt and returns a tuple of a new L{Connection} (the accepted client) and the address the connection originated from. """ ctx = Context(TLSv1_METHOD) ctx.use_privatekey(load_privatekey(FILETYPE_PEM, server_key_pem)) ctx.use_certificate(load_certificate(FILETYPE_PEM, server_cert_pem)) port = socket() portSSL = Connection(ctx, port) portSSL.bind(('', 0)) portSSL.listen(3) clientSSL = Connection(Context(TLSv1_METHOD), socket()) # Calling portSSL.getsockname() here to get the server IP address sounds # great, but frequently fails on Windows. clientSSL.connect(('127.0.0.1', portSSL.getsockname()[1])) serverSSL, address = portSSL.accept() self.assertTrue(isinstance(serverSSL, Connection)) self.assertIdentical(serverSSL.get_context(), ctx) self.assertEquals(address, clientSSL.getsockname()) def test_shutdown_wrong_args(self): """ L{Connection.shutdown} raises L{TypeError} if called with the wrong number of arguments or with arguments other than integers. """ connection = Connection(Context(TLSv1_METHOD), None) self.assertRaises(TypeError, connection.shutdown, None) self.assertRaises(TypeError, connection.get_shutdown, None) self.assertRaises(TypeError, connection.set_shutdown) self.assertRaises(TypeError, connection.set_shutdown, None) self.assertRaises(TypeError, connection.set_shutdown, 0, 1) def test_shutdown(self): """ L{Connection.shutdown} performs an SSL-level connection shutdown. """ server, client = self._loopback() self.assertFalse(server.shutdown()) self.assertEquals(server.get_shutdown(), SENT_SHUTDOWN) self.assertRaises(ZeroReturnError, client.recv, 1024) self.assertEquals(client.get_shutdown(), RECEIVED_SHUTDOWN) client.shutdown() self.assertEquals(client.get_shutdown(), SENT_SHUTDOWN|RECEIVED_SHUTDOWN) self.assertRaises(ZeroReturnError, server.recv, 1024) self.assertEquals(server.get_shutdown(), SENT_SHUTDOWN|RECEIVED_SHUTDOWN) def test_set_shutdown(self): """ L{Connection.set_shutdown} sets the state of the SSL connection shutdown process. """ connection = Connection(Context(TLSv1_METHOD), socket()) connection.set_shutdown(RECEIVED_SHUTDOWN) self.assertEquals(connection.get_shutdown(), RECEIVED_SHUTDOWN) def test_app_data_wrong_args(self): """ L{Connection.set_app_data} raises L{TypeError} if called with other than one argument. L{Connection.get_app_data} raises L{TypeError} if called with any arguments. """ conn = Connection(Context(TLSv1_METHOD), None) self.assertRaises(TypeError, conn.get_app_data, None) self.assertRaises(TypeError, conn.set_app_data) self.assertRaises(TypeError, conn.set_app_data, None, None) def test_app_data(self): """ Any object can be set as app data by passing it to L{Connection.set_app_data} and later retrieved with L{Connection.get_app_data}. """ conn = Connection(Context(TLSv1_METHOD), None) app_data = object() conn.set_app_data(app_data) self.assertIdentical(conn.get_app_data(), app_data) def test_makefile(self): """ L{Connection.makefile} is not implemented and calling that method raises L{NotImplementedError}. """ conn = Connection(Context(TLSv1_METHOD), None) self.assertRaises(NotImplementedError, conn.makefile) def test_get_peer_cert_chain_wrong_args(self): """ L{Connection.get_peer_cert_chain} raises L{TypeError} if called with any arguments. """ conn = Connection(Context(TLSv1_METHOD), None) self.assertRaises(TypeError, conn.get_peer_cert_chain, 1) self.assertRaises(TypeError, conn.get_peer_cert_chain, "foo") self.assertRaises(TypeError, conn.get_peer_cert_chain, object()) self.assertRaises(TypeError, conn.get_peer_cert_chain, []) def test_get_peer_cert_chain(self): """ L{Connection.get_peer_cert_chain} returns a list of certificates which the connected server returned for the certification verification. """ chain = _create_certificate_chain() [(cakey, cacert), (ikey, icert), (skey, scert)] = chain serverContext = Context(TLSv1_METHOD) serverContext.use_privatekey(skey) serverContext.use_certificate(scert) serverContext.add_extra_chain_cert(icert) serverContext.add_extra_chain_cert(cacert) server = Connection(serverContext, None) server.set_accept_state() # Create the client clientContext = Context(TLSv1_METHOD) clientContext.set_verify(VERIFY_NONE, verify_cb) client = Connection(clientContext, None) client.set_connect_state() self._interactInMemory(client, server) chain = client.get_peer_cert_chain() self.assertEqual(len(chain), 3) self.assertEqual( "Server Certificate", chain[0].get_subject().CN) self.assertEqual( "Intermediate Certificate", chain[1].get_subject().CN) self.assertEqual( "Authority Certificate", chain[2].get_subject().CN) def test_get_peer_cert_chain_none(self): """ L{Connection.get_peer_cert_chain} returns C{None} if the peer sends no certificate chain. """ ctx = Context(TLSv1_METHOD) ctx.use_privatekey(load_privatekey(FILETYPE_PEM, server_key_pem)) ctx.use_certificate(load_certificate(FILETYPE_PEM, server_cert_pem)) server = Connection(ctx, None) server.set_accept_state() client = Connection(Context(TLSv1_METHOD), None) client.set_connect_state() self._interactInMemory(client, server) self.assertIdentical(None, server.get_peer_cert_chain()) class ConnectionGetCipherListTests(TestCase): """ Tests for L{Connection.get_cipher_list}. """ def test_wrong_args(self): """ L{Connection.get_cipher_list} raises L{TypeError} if called with any arguments. """ connection = Connection(Context(TLSv1_METHOD), None) self.assertRaises(TypeError, connection.get_cipher_list, None) def test_result(self): """ L{Connection.get_cipher_list} returns a C{list} of C{str} giving the names of the ciphers which might be used. """ connection = Connection(Context(TLSv1_METHOD), None) ciphers = connection.get_cipher_list() self.assertTrue(isinstance(ciphers, list)) for cipher in ciphers: self.assertTrue(isinstance(cipher, str)) class ConnectionSendTests(TestCase, _LoopbackMixin): """ Tests for L{Connection.send} """ def test_wrong_args(self): """ When called with arguments other than a single string, L{Connection.send} raises L{TypeError}. """ connection = Connection(Context(TLSv1_METHOD), None) self.assertRaises(TypeError, connection.send) self.assertRaises(TypeError, connection.send, object()) self.assertRaises(TypeError, connection.send, "foo", "bar") def test_short_bytes(self): """ When passed a short byte string, L{Connection.send} transmits all of it and returns the number of bytes sent. """ server, client = self._loopback() count = server.send(b('xy')) self.assertEquals(count, 2) self.assertEquals(client.recv(2), b('xy')) try: memoryview except NameError: "cannot test sending memoryview without memoryview" else: def test_short_memoryview(self): """ When passed a memoryview onto a small number of bytes, L{Connection.send} transmits all of them and returns the number of bytes sent. """ server, client = self._loopback() count = server.send(memoryview(b('xy'))) self.assertEquals(count, 2) self.assertEquals(client.recv(2), b('xy')) class ConnectionSendallTests(TestCase, _LoopbackMixin): """ Tests for L{Connection.sendall}. """ def test_wrong_args(self): """ When called with arguments other than a single string, L{Connection.sendall} raises L{TypeError}. """ connection = Connection(Context(TLSv1_METHOD), None) self.assertRaises(TypeError, connection.sendall) self.assertRaises(TypeError, connection.sendall, object()) self.assertRaises(TypeError, connection.sendall, "foo", "bar") def test_short(self): """ L{Connection.sendall} transmits all of the bytes in the string passed to it. """ server, client = self._loopback() server.sendall(b('x')) self.assertEquals(client.recv(1), b('x')) try: memoryview except NameError: "cannot test sending memoryview without memoryview" else: def test_short_memoryview(self): """ When passed a memoryview onto a small number of bytes, L{Connection.sendall} transmits all of them. """ server, client = self._loopback() server.sendall(memoryview(b('x'))) self.assertEquals(client.recv(1), b('x')) def test_long(self): """ L{Connection.sendall} transmits all of the bytes in the string passed to it even if this requires multiple calls of an underlying write function. """ server, client = self._loopback() # Should be enough, underlying SSL_write should only do 16k at a time. # On Windows, after 32k of bytes the write will block (forever - because # no one is yet reading). message = b('x') * (1024 * 32 - 1) + b('y') server.sendall(message) accum = [] received = 0 while received < len(message): data = client.recv(1024) accum.append(data) received += len(data) self.assertEquals(message, b('').join(accum)) def test_closed(self): """ If the underlying socket is closed, L{Connection.sendall} propagates the write error from the low level write call. """ server, client = self._loopback() server.sock_shutdown(2) self.assertRaises(SysCallError, server.sendall, "hello, world") class ConnectionRenegotiateTests(TestCase, _LoopbackMixin): """ Tests for SSL renegotiation APIs. """ def test_renegotiate_wrong_args(self): """ L{Connection.renegotiate} raises L{TypeError} if called with any arguments. """ connection = Connection(Context(TLSv1_METHOD), None) self.assertRaises(TypeError, connection.renegotiate, None) def test_total_renegotiations_wrong_args(self): """ L{Connection.total_renegotiations} raises L{TypeError} if called with any arguments. """ connection = Connection(Context(TLSv1_METHOD), None) self.assertRaises(TypeError, connection.total_renegotiations, None) def test_total_renegotiations(self): """ L{Connection.total_renegotiations} returns C{0} before any renegotiations have happened. """ connection = Connection(Context(TLSv1_METHOD), None) self.assertEquals(connection.total_renegotiations(), 0) # def test_renegotiate(self): # """ # """ # server, client = self._loopback() # server.send("hello world") # self.assertEquals(client.recv(len("hello world")), "hello world") # self.assertEquals(server.total_renegotiations(), 0) # self.assertTrue(server.renegotiate()) # server.setblocking(False) # client.setblocking(False) # while server.renegotiate_pending(): # client.do_handshake() # server.do_handshake() # self.assertEquals(server.total_renegotiations(), 1) class ErrorTests(TestCase): """ Unit tests for L{OpenSSL.SSL.Error}. """ def test_type(self): """ L{Error} is an exception type. """ self.assertTrue(issubclass(Error, Exception)) self.assertEqual(Error.__name__, 'Error') class ConstantsTests(TestCase): """ Tests for the values of constants exposed in L{OpenSSL.SSL}. These are values defined by OpenSSL intended only to be used as flags to OpenSSL APIs. The only assertions it seems can be made about them is their values. """ # unittest.TestCase has no skip mechanism if OP_NO_QUERY_MTU is not None: def test_op_no_query_mtu(self): """ The value of L{OpenSSL.SSL.OP_NO_QUERY_MTU} is 0x1000, the value of I{SSL_OP_NO_QUERY_MTU} defined by I{openssl/ssl.h}. """ self.assertEqual(OP_NO_QUERY_MTU, 0x1000) else: "OP_NO_QUERY_MTU unavailable - OpenSSL version may be too old" if OP_COOKIE_EXCHANGE is not None: def test_op_cookie_exchange(self): """ The value of L{OpenSSL.SSL.OP_COOKIE_EXCHANGE} is 0x2000, the value of I{SSL_OP_COOKIE_EXCHANGE} defined by I{openssl/ssl.h}. """ self.assertEqual(OP_COOKIE_EXCHANGE, 0x2000) else: "OP_COOKIE_EXCHANGE unavailable - OpenSSL version may be too old" if OP_NO_TICKET is not None: def test_op_no_ticket(self): """ The value of L{OpenSSL.SSL.OP_NO_TICKET} is 0x4000, the value of I{SSL_OP_NO_TICKET} defined by I{openssl/ssl.h}. """ self.assertEqual(OP_NO_TICKET, 0x4000) else: "OP_NO_TICKET unavailable - OpenSSL version may be too old" class MemoryBIOTests(TestCase, _LoopbackMixin): """ Tests for L{OpenSSL.SSL.Connection} using a memory BIO. """ def _server(self, sock): """ Create a new server-side SSL L{Connection} object wrapped around C{sock}. """ # Create the server side Connection. This is mostly setup boilerplate # - use TLSv1, use a particular certificate, etc. server_ctx = Context(TLSv1_METHOD) server_ctx.set_options(OP_NO_SSLv2 | OP_NO_SSLv3 | OP_SINGLE_DH_USE ) server_ctx.set_verify(VERIFY_PEER|VERIFY_FAIL_IF_NO_PEER_CERT|VERIFY_CLIENT_ONCE, verify_cb) server_store = server_ctx.get_cert_store() server_ctx.use_privatekey(load_privatekey(FILETYPE_PEM, server_key_pem)) server_ctx.use_certificate(load_certificate(FILETYPE_PEM, server_cert_pem)) server_ctx.check_privatekey() server_store.add_cert(load_certificate(FILETYPE_PEM, root_cert_pem)) # Here the Connection is actually created. If None is passed as the 2nd # parameter, it indicates a memory BIO should be created. server_conn = Connection(server_ctx, sock) server_conn.set_accept_state() return server_conn def _client(self, sock): """ Create a new client-side SSL L{Connection} object wrapped around C{sock}. """ # Now create the client side Connection. Similar boilerplate to the # above. client_ctx = Context(TLSv1_METHOD) client_ctx.set_options(OP_NO_SSLv2 | OP_NO_SSLv3 | OP_SINGLE_DH_USE ) client_ctx.set_verify(VERIFY_PEER|VERIFY_FAIL_IF_NO_PEER_CERT|VERIFY_CLIENT_ONCE, verify_cb) client_store = client_ctx.get_cert_store() client_ctx.use_privatekey(load_privatekey(FILETYPE_PEM, client_key_pem)) client_ctx.use_certificate(load_certificate(FILETYPE_PEM, client_cert_pem)) client_ctx.check_privatekey() client_store.add_cert(load_certificate(FILETYPE_PEM, root_cert_pem)) client_conn = Connection(client_ctx, sock) client_conn.set_connect_state() return client_conn def test_memoryConnect(self): """ Two L{Connection}s which use memory BIOs can be manually connected by reading from the output of each and writing those bytes to the input of the other and in this way establish a connection and exchange application-level bytes with each other. """ server_conn = self._server(None) client_conn = self._client(None) # There should be no key or nonces yet. self.assertIdentical(server_conn.master_key(), None) self.assertIdentical(server_conn.client_random(), None) self.assertIdentical(server_conn.server_random(), None) # First, the handshake needs to happen. We'll deliver bytes back and # forth between the client and server until neither of them feels like # speaking any more. self.assertIdentical( self._interactInMemory(client_conn, server_conn), None) # Now that the handshake is done, there should be a key and nonces. self.assertNotIdentical(server_conn.master_key(), None) self.assertNotIdentical(server_conn.client_random(), None) self.assertNotIdentical(server_conn.server_random(), None) self.assertEquals(server_conn.client_random(), client_conn.client_random()) self.assertEquals(server_conn.server_random(), client_conn.server_random()) self.assertNotEquals(server_conn.client_random(), server_conn.server_random()) self.assertNotEquals(client_conn.client_random(), client_conn.server_random()) # Here are the bytes we'll try to send. important_message = b('One if by land, two if by sea.') server_conn.write(important_message) self.assertEquals( self._interactInMemory(client_conn, server_conn), (client_conn, important_message)) client_conn.write(important_message[::-1]) self.assertEquals( self._interactInMemory(client_conn, server_conn), (server_conn, important_message[::-1])) def test_socketConnect(self): """ Just like L{test_memoryConnect} but with an actual socket. This is primarily to rule out the memory BIO code as the source of any problems encountered while passing data over a L{Connection} (if this test fails, there must be a problem outside the memory BIO code, as no memory BIO is involved here). Even though this isn't a memory BIO test, it's convenient to have it here. """ server_conn, client_conn = self._loopback() important_message = b("Help me Obi Wan Kenobi, you're my only hope.") client_conn.send(important_message) msg = server_conn.recv(1024) self.assertEqual(msg, important_message) # Again in the other direction, just for fun. important_message = important_message[::-1] server_conn.send(important_message) msg = client_conn.recv(1024) self.assertEqual(msg, important_message) def test_socketOverridesMemory(self): """ Test that L{OpenSSL.SSL.bio_read} and L{OpenSSL.SSL.bio_write} don't work on L{OpenSSL.SSL.Connection}() that use sockets. """ context = Context(SSLv3_METHOD) client = socket() clientSSL = Connection(context, client) self.assertRaises( TypeError, clientSSL.bio_read, 100) self.assertRaises( TypeError, clientSSL.bio_write, "foo") self.assertRaises( TypeError, clientSSL.bio_shutdown ) def test_outgoingOverflow(self): """ If more bytes than can be written to the memory BIO are passed to L{Connection.send} at once, the number of bytes which were written is returned and that many bytes from the beginning of the input can be read from the other end of the connection. """ server = self._server(None) client = self._client(None) self._interactInMemory(client, server) size = 2 ** 15 sent = client.send("x" * size) # Sanity check. We're trying to test what happens when the entire # input can't be sent. If the entire input was sent, this test is # meaningless. self.assertTrue(sent < size) receiver, received = self._interactInMemory(client, server) self.assertIdentical(receiver, server) # We can rely on all of these bytes being received at once because # _loopback passes 2 ** 16 to recv - more than 2 ** 15. self.assertEquals(len(received), sent) def test_shutdown(self): """ L{Connection.bio_shutdown} signals the end of the data stream from which the L{Connection} reads. """ server = self._server(None) server.bio_shutdown() e = self.assertRaises(Error, server.recv, 1024) # We don't want WantReadError or ZeroReturnError or anything - it's a # handshake failure. self.assertEquals(e.__class__, Error) def _check_client_ca_list(self, func): """ Verify the return value of the C{get_client_ca_list} method for server and client connections. @param func: A function which will be called with the server context before the client and server are connected to each other. This function should specify a list of CAs for the server to send to the client and return that same list. The list will be used to verify that C{get_client_ca_list} returns the proper value at various times. """ server = self._server(None) client = self._client(None) self.assertEqual(client.get_client_ca_list(), []) self.assertEqual(server.get_client_ca_list(), []) ctx = server.get_context() expected = func(ctx) self.assertEqual(client.get_client_ca_list(), []) self.assertEqual(server.get_client_ca_list(), expected) self._interactInMemory(client, server) self.assertEqual(client.get_client_ca_list(), expected) self.assertEqual(server.get_client_ca_list(), expected) def test_set_client_ca_list_errors(self): """ L{Context.set_client_ca_list} raises a L{TypeError} if called with a non-list or a list that contains objects other than X509Names. """ ctx = Context(TLSv1_METHOD) self.assertRaises(TypeError, ctx.set_client_ca_list, "spam") self.assertRaises(TypeError, ctx.set_client_ca_list, ["spam"]) self.assertIdentical(ctx.set_client_ca_list([]), None) def test_set_empty_ca_list(self): """ If passed an empty list, L{Context.set_client_ca_list} configures the context to send no CA names to the client and, on both the server and client sides, L{Connection.get_client_ca_list} returns an empty list after the connection is set up. """ def no_ca(ctx): ctx.set_client_ca_list([]) return [] self._check_client_ca_list(no_ca) def test_set_one_ca_list(self): """ If passed a list containing a single X509Name, L{Context.set_client_ca_list} configures the context to send that CA name to the client and, on both the server and client sides, L{Connection.get_client_ca_list} returns a list containing that X509Name after the connection is set up. """ cacert = load_certificate(FILETYPE_PEM, root_cert_pem) cadesc = cacert.get_subject() def single_ca(ctx): ctx.set_client_ca_list([cadesc]) return [cadesc] self._check_client_ca_list(single_ca) def test_set_multiple_ca_list(self): """ If passed a list containing multiple X509Name objects, L{Context.set_client_ca_list} configures the context to send those CA names to the client and, on both the server and client sides, L{Connection.get_client_ca_list} returns a list containing those X509Names after the connection is set up. """ secert = load_certificate(FILETYPE_PEM, server_cert_pem) clcert = load_certificate(FILETYPE_PEM, server_cert_pem) sedesc = secert.get_subject() cldesc = clcert.get_subject() def multiple_ca(ctx): L = [sedesc, cldesc] ctx.set_client_ca_list(L) return L self._check_client_ca_list(multiple_ca) def test_reset_ca_list(self): """ If called multiple times, only the X509Names passed to the final call of L{Context.set_client_ca_list} are used to configure the CA names sent to the client. """ cacert = load_certificate(FILETYPE_PEM, root_cert_pem) secert = load_certificate(FILETYPE_PEM, server_cert_pem) clcert = load_certificate(FILETYPE_PEM, server_cert_pem) cadesc = cacert.get_subject() sedesc = secert.get_subject() cldesc = clcert.get_subject() def changed_ca(ctx): ctx.set_client_ca_list([sedesc, cldesc]) ctx.set_client_ca_list([cadesc]) return [cadesc] self._check_client_ca_list(changed_ca) def test_mutated_ca_list(self): """ If the list passed to L{Context.set_client_ca_list} is mutated afterwards, this does not affect the list of CA names sent to the client. """ cacert = load_certificate(FILETYPE_PEM, root_cert_pem) secert = load_certificate(FILETYPE_PEM, server_cert_pem) cadesc = cacert.get_subject() sedesc = secert.get_subject() def mutated_ca(ctx): L = [cadesc] ctx.set_client_ca_list([cadesc]) L.append(sedesc) return [cadesc] self._check_client_ca_list(mutated_ca) def test_add_client_ca_errors(self): """ L{Context.add_client_ca} raises L{TypeError} if called with a non-X509 object or with a number of arguments other than one. """ ctx = Context(TLSv1_METHOD) cacert = load_certificate(FILETYPE_PEM, root_cert_pem) self.assertRaises(TypeError, ctx.add_client_ca) self.assertRaises(TypeError, ctx.add_client_ca, "spam") self.assertRaises(TypeError, ctx.add_client_ca, cacert, cacert) def test_one_add_client_ca(self): """ A certificate's subject can be added as a CA to be sent to the client with L{Context.add_client_ca}. """ cacert = load_certificate(FILETYPE_PEM, root_cert_pem) cadesc = cacert.get_subject() def single_ca(ctx): ctx.add_client_ca(cacert) return [cadesc] self._check_client_ca_list(single_ca) def test_multiple_add_client_ca(self): """ Multiple CA names can be sent to the client by calling L{Context.add_client_ca} with multiple X509 objects. """ cacert = load_certificate(FILETYPE_PEM, root_cert_pem) secert = load_certificate(FILETYPE_PEM, server_cert_pem) cadesc = cacert.get_subject() sedesc = secert.get_subject() def multiple_ca(ctx): ctx.add_client_ca(cacert) ctx.add_client_ca(secert) return [cadesc, sedesc] self._check_client_ca_list(multiple_ca) def test_set_and_add_client_ca(self): """ A call to L{Context.set_client_ca_list} followed by a call to L{Context.add_client_ca} results in using the CA names from the first call and the CA name from the second call. """ cacert = load_certificate(FILETYPE_PEM, root_cert_pem) secert = load_certificate(FILETYPE_PEM, server_cert_pem) clcert = load_certificate(FILETYPE_PEM, server_cert_pem) cadesc = cacert.get_subject() sedesc = secert.get_subject() cldesc = clcert.get_subject() def mixed_set_add_ca(ctx): ctx.set_client_ca_list([cadesc, sedesc]) ctx.add_client_ca(clcert) return [cadesc, sedesc, cldesc] self._check_client_ca_list(mixed_set_add_ca) def test_set_after_add_client_ca(self): """ A call to L{Context.set_client_ca_list} after a call to L{Context.add_client_ca} replaces the CA name specified by the former call with the names specified by the latter cal. """ cacert = load_certificate(FILETYPE_PEM, root_cert_pem) secert = load_certificate(FILETYPE_PEM, server_cert_pem) clcert = load_certificate(FILETYPE_PEM, server_cert_pem) cadesc = cacert.get_subject() sedesc = secert.get_subject() def set_replaces_add_ca(ctx): ctx.add_client_ca(clcert) ctx.set_client_ca_list([cadesc]) ctx.add_client_ca(secert) return [cadesc, sedesc] self._check_client_ca_list(set_replaces_add_ca) class InfoConstantTests(TestCase): """ Tests for assorted constants exposed for use in info callbacks. """ def test_integers(self): """ All of the info constants are integers. This is a very weak test. It would be nice to have one that actually verifies that as certain info events happen, the value passed to the info callback matches up with the constant exposed by OpenSSL.SSL. """ for const in [ SSL_ST_CONNECT, SSL_ST_ACCEPT, SSL_ST_MASK, SSL_ST_INIT, SSL_ST_BEFORE, SSL_ST_OK, SSL_ST_RENEGOTIATE, SSL_CB_LOOP, SSL_CB_EXIT, SSL_CB_READ, SSL_CB_WRITE, SSL_CB_ALERT, SSL_CB_READ_ALERT, SSL_CB_WRITE_ALERT, SSL_CB_ACCEPT_LOOP, SSL_CB_ACCEPT_EXIT, SSL_CB_CONNECT_LOOP, SSL_CB_CONNECT_EXIT, SSL_CB_HANDSHAKE_START, SSL_CB_HANDSHAKE_DONE]: self.assertTrue(isinstance(const, int)) if __name__ == '__main__': main() pyOpenSSL-0.13/OpenSSL/test/util.py0000644000214500021450000001315011630175105017027 0ustar bb-slavebb-slave# Copyright (C) Jean-Paul Calderone # Copyright (C) Twisted Matrix Laboratories. # See LICENSE for details. """ Helpers for the OpenSSL test suite, largely copied from U{Twisted}. """ import shutil import os, os.path from tempfile import mktemp from unittest import TestCase import sys from OpenSSL.crypto import Error, _exception_from_error_queue if sys.version_info < (3, 0): def b(s): return s bytes = str else: def b(s): return s.encode("charmap") bytes = bytes class TestCase(TestCase): """ L{TestCase} adds useful testing functionality beyond what is available from the standard library L{unittest.TestCase}. """ def tearDown(self): """ Clean up any files or directories created using L{TestCase.mktemp}. Subclasses must invoke this method if they override it or the cleanup will not occur. """ if False and self._temporaryFiles is not None: for temp in self._temporaryFiles: if os.path.isdir(temp): shutil.rmtree(temp) elif os.path.exists(temp): os.unlink(temp) try: _exception_from_error_queue() except Error: e = sys.exc_info()[1] if e.args != ([],): self.fail("Left over errors in OpenSSL error queue: " + repr(e)) def failUnlessIn(self, containee, container, msg=None): """ Fail the test if C{containee} is not found in C{container}. @param containee: the value that should be in C{container} @param container: a sequence type, or in the case of a mapping type, will follow semantics of 'if key in dict.keys()' @param msg: if msg is None, then the failure message will be '%r not in %r' % (first, second) """ if containee not in container: raise self.failureException(msg or "%r not in %r" % (containee, container)) return containee assertIn = failUnlessIn def failUnlessIdentical(self, first, second, msg=None): """ Fail the test if C{first} is not C{second}. This is an obect-identity-equality test, not an object equality (i.e. C{__eq__}) test. @param msg: if msg is None, then the failure message will be '%r is not %r' % (first, second) """ if first is not second: raise self.failureException(msg or '%r is not %r' % (first, second)) return first assertIdentical = failUnlessIdentical def failIfIdentical(self, first, second, msg=None): """ Fail the test if C{first} is C{second}. This is an obect-identity-equality test, not an object equality (i.e. C{__eq__}) test. @param msg: if msg is None, then the failure message will be '%r is %r' % (first, second) """ if first is second: raise self.failureException(msg or '%r is %r' % (first, second)) return first assertNotIdentical = failIfIdentical def failUnlessRaises(self, exception, f, *args, **kwargs): """ Fail the test unless calling the function C{f} with the given C{args} and C{kwargs} raises C{exception}. The failure will report the traceback and call stack of the unexpected exception. @param exception: exception type that is to be expected @param f: the function to call @return: The raised exception instance, if it is of the given type. @raise self.failureException: Raised if the function call does not raise an exception or if it raises an exception of a different type. """ try: result = f(*args, **kwargs) except exception: inst = sys.exc_info()[1] return inst except: raise self.failureException('%s raised instead of %s' % (sys.exc_info()[0], exception.__name__, )) else: raise self.failureException('%s not raised (%r returned)' % (exception.__name__, result)) assertRaises = failUnlessRaises _temporaryFiles = None def mktemp(self): """ Pathetic substitute for twisted.trial.unittest.TestCase.mktemp. """ if self._temporaryFiles is None: self._temporaryFiles = [] temp = mktemp(dir=".") self._temporaryFiles.append(temp) return temp # Python 2.3 compatibility. def assertTrue(self, *a, **kw): return self.failUnless(*a, **kw) def assertFalse(self, *a, **kw): return self.failIf(*a, **kw) # Other stuff def assertConsistentType(self, theType, name, *constructionArgs): """ Perform various assertions about C{theType} to ensure that it is a well-defined type. This is useful for extension types, where it's pretty easy to do something wacky. If something about the type is unusual, an exception will be raised. @param theType: The type object about which to make assertions. @param name: A string giving the name of the type. @param constructionArgs: Positional arguments to use with C{theType} to create an instance of it. """ self.assertEqual(theType.__name__, name) self.assertTrue(isinstance(theType, type)) instance = theType(*constructionArgs) self.assertIdentical(type(instance), theType) pyOpenSSL-0.13/OpenSSL/RATIONALE0000644000214500021450000000673411630175105015774 0ustar bb-slavebb-slave RATIONALE The reason this module exists at all is that the SSL support in the socket module in the Python 2.1 distribution (which is what we used, of course I cannot speak for later versions) is severely limited. Update this list whenever needed! The communications module isn't written yet, so we don't know exactly how this'll work! This is a list of things we need from an OpenSSL module: + Context objects (in OpenSSL called SSL_CTX) that can be manipulated from Python modules. They must support a number of operations: - Loading certificates from file and memory, both the client certificate and the certificates used for the verification chain. - Loading private keys from file and memory. - Setting the verification mode (basically VERIFY_NONE and VERIFY_PEER). - Callbacks mechanism for prompting for pass phrases and verifying certificates. The callbacks have to work under a multi-threaded environment (see the comment in ssl/context.c). Of course the callbacks will have to be written in Python! + The Connection objects (in OpenSSL called SSL) have to support a few things: - Renegotiation, this is really important, especially for connections that are up and running for a long time, since renegotiation generates new encryption keys. - Server-side SSL must work! As far as I know this doesn't work in the SSL support of the socket module as of Python 2.1. - Wrapping the methods of the underlying transport object is nice, so you don't have to keep track of more than one object per connection. This could of course be done a lot better than the way it works now, so more transport layers than sockets are possible! + A well-organized error system that mimics OpenSSL's error system is desireable. Specifically there has to be a way to find out wether the operation was successful, or if it failed, why it failed, so some sort of interface to OpenSSL's error queue mechanism is needed. + Certificate objects (X509) and certificate name objects (X509_NAME) are needed, especially for verification purposes. Certificates will probably also be generated by the server which is another reason for them to exist. The same thing goes for key objects (EVP_PKEY) + Since this is an OpenSSL module, there has to be an interface to the OpenSSL PRNG, so it can be seeded in a good way. When asking about SSL on the comp.lang.python newsgroup (or on python-list@python.org) people usually pointed you to the M2Crypto package. The M2Crypto.SSL module does implement a lot of OpenSSL's functionality but unfortunately its error handling system does not seem to be finished, especially for non-blocking I/O. I think that much of the reason for this is that M2Crypto is developed using SWIG. This makes it awkward to create functions that e.g. can return both an integer and NULL since (as far as I know) you basically write C functions and SWIG makes wrapper functions that parses the Python argument list and calls your C function, and finally transforms your return value to a Python object. Finally, a good book on the topic of SSL (that I read and learned a lot from) is "SSL and TLS - Designing and Building Secure Systems" (ISBN 0201615983) by Eric Rescorla. A good mailinglist to subscribe to is the openssl-users@openssl.org list. This comment was written July 2001, discussing Python 2.1. Feel free to modify it as the SSL support in the socket module changes. pyOpenSSL-0.13/OpenSSL/__init__.py0000644000214500021450000000170511630175105016635 0ustar bb-slavebb-slave# Copyright (C) AB Strakt # See LICENSE for details. """ pyOpenSSL - A simple wrapper around the OpenSSL library """ import sys try: orig = sys.getdlopenflags() except AttributeError: from OpenSSL import crypto else: try: import DLFCN except ImportError: try: import dl except ImportError: try: import ctypes except ImportError: flags = 2 | 256 else: flags = 2 | ctypes.RTLD_GLOBAL del ctypes else: flags = dl.RTLD_NOW | dl.RTLD_GLOBAL del dl else: flags = DLFCN.RTLD_NOW | DLFCN.RTLD_GLOBAL del DLFCN sys.setdlopenflags(flags) from OpenSSL import crypto sys.setdlopenflags(orig) del orig, flags del sys from OpenSSL import rand, SSL from OpenSSL.version import __version__ __all__ = [ 'rand', 'crypto', 'SSL', 'tsafe', '__version__'] pyOpenSSL-0.13/OpenSSL/py3k.h0000644000214500021450000000267211630175105015567 0ustar bb-slavebb-slave#ifndef PyOpenSSL_PY3K_H_ #define PyOpenSSL_PY3K_H_ #if (PY_VERSION_HEX >= 0x03000000) #define PY3 #define PyOpenSSL_MODINIT(name) \ PyMODINIT_FUNC \ PyInit_##name(void) #define PyText_CheckExact PyUnicode_CheckExact #define PyText_FromString PyUnicode_FromString #define PyText_FromStringAndSize PyUnicode_FromStringAndSize #define PyOpenSSL_HEAD_INIT(type, size) PyVarObject_HEAD_INIT(NULL, size) #define PyOpenSSL_Integer_Check(o) PyLong_Check(o) #define PyOpenSSL_MODRETURN(module) { return module; } #define BYTESTRING_FMT "y" #else /* (PY_VERSION_HEX >= 0x03000000) */ #define PyOpenSSL_MODRETURN(module) { return; } #define PyOpenSSL_HEAD_INIT(type, size) PyObject_HEAD_INIT(NULL) 0, #define PyBytes_FromStringAndSize PyString_FromStringAndSize #define PyOpenSSL_Integer_Check(o) (PyInt_Check(o) || PyLong_Check(o)) #define PyBytes_Size PyString_Size #define PyBytes_Check PyString_Check #define PyBytes_CheckExact PyString_CheckExact #define PyBytes_AsString PyString_AsString #define PyBytes_FromString PyString_FromString #define PyBytes_FromStringAndSize PyString_FromStringAndSize #define _PyBytes_Resize _PyString_Resize #define PyText_CheckExact PyString_CheckExact #define PyText_FromString PyString_FromString #define PyText_FromStringAndSize PyString_FromStringAndSize #define PyOpenSSL_MODINIT(name) \ void \ init##name(void) #define BYTESTRING_FMT "s" #endif /* (PY_VERSION_HEX >= 0x03000000) */ #endif /* PyOpenSSL_PY3K_H_ */ pyOpenSSL-0.13/OpenSSL/pymemcompat.h0000644000214500021450000000612011630175105017224 0ustar bb-slavebb-slave/* The idea of this file is that you bundle it with your extension, #include it, program to Python 2.3's memory API and have your extension build with any version of Python from 1.5.2 through to 2.3 (and hopefully beyond). */ #ifndef Py_PYMEMCOMPAT_H #define Py_PYMEMCOMPAT_H #include "Python.h" /* There are three "families" of memory API: the "raw memory", "object memory" and "object" families. (This is ignoring the matter of the cycle collector, about which more is said below). Raw Memory: PyMem_Malloc, PyMem_Realloc, PyMem_Free Object Memory: PyObject_Malloc, PyObject_Realloc, PyObject_Free Object: PyObject_New, PyObject_NewVar, PyObject_Del The raw memory and object memory allocators both mimic the malloc/realloc/free interface from ANSI C, but the object memory allocator can (and, since 2.3, does by default) use a different allocation strategy biased towards lots of lots of "small" allocations. The object family is used for allocating Python objects, and the initializers take care of some basic initialization (setting the refcount to 1 and filling out the ob_type field) as well as having a somewhat different interface. Do not mix the families! E.g. do not allocate memory with PyMem_Malloc and free it with PyObject_Free. You may get away with it quite a lot of the time, but there *are* scenarios where this will break. You Have Been Warned. Also, in many versions of Python there are an insane amount of memory interfaces to choose from. Use the ones described above. */ #if PY_VERSION_HEX < 0x01060000 /* raw memory interface already present */ /* there is no object memory interface in 1.5.2 */ #define PyObject_Malloc PyMem_Malloc #define PyObject_Realloc PyMem_Realloc #define PyObject_Free PyMem_Free /* the object interface is there, but the names have changed */ #define PyObject_New PyObject_NEW #define PyObject_NewVar PyObject_NEW_VAR #define PyObject_Del PyMem_Free #endif /* If your object is a container you probably want to support the cycle collector, which was new in Python 2.0. Unfortunately, the interface to the collector that was present in Python 2.0 and 2.1 proved to be tricky to use, and so changed in 2.2 -- in a way that can't easily be papered over with macros. This file contains macros that let you program to the 2.2 GC API. Your module will compile against any Python since version 1.5.2, but the type will only participate in the GC in versions 2.2 and up. Some work is still necessary on your part to only fill out the tp_traverse and tp_clear fields when they exist and set tp_flags appropriately. It is possible to support both the 2.0 and 2.2 GC APIs, but it's not pretty and this comment block is too narrow to contain a desciption of what's required... */ #if PY_VERSION_HEX < 0x020200B1 #define PyObject_GC_New PyObject_New #define PyObject_GC_NewVar PyObject_NewVar #define PyObject_GC_Del PyObject_Del #define PyObject_GC_Track(op) #define PyObject_GC_UnTrack(op) #endif #endif /* !Py_PYMEMCOMPAT_H */ pyOpenSSL-0.13/OpenSSL/tsafe.py0000644000214500021450000000176211630175105016203 0ustar bb-slavebb-slavefrom OpenSSL import SSL _ssl = SSL del SSL import threading _RLock = threading.RLock del threading class Connection: def __init__(self, *args): self._ssl_conn = apply(_ssl.Connection, args) self._lock = _RLock() for f in ('get_context', 'pending', 'send', 'write', 'recv', 'read', 'renegotiate', 'bind', 'listen', 'connect', 'accept', 'setblocking', 'fileno', 'shutdown', 'close', 'get_cipher_list', 'getpeername', 'getsockname', 'getsockopt', 'setsockopt', 'makefile', 'get_app_data', 'set_app_data', 'state_string', 'sock_shutdown', 'get_peer_certificate', 'get_peer_cert_chain', 'want_read', 'want_write', 'set_connect_state', 'set_accept_state', 'connect_ex', 'sendall'): exec("""def %s(self, *args): self._lock.acquire() try: return self._ssl_conn.%s(*args) finally: self._lock.release()\n""" % (f, f)) pyOpenSSL-0.13/OpenSSL/util.c0000644000214500021450000000410511630175105015642 0ustar bb-slavebb-slave/* * util.c * * Copyright (C) AB Strakt * Copyright (C) Jean-Paul Calderone * See LICENSE for details. * * Utility functions. * See the file RATIONALE for a short explanation of why this module was written. * * Reviewed 2001-07-23 */ #include #include "util.h" /* * Flush OpenSSL's error queue and return a list of errors (a (library, * function, reason) string tuple) * * Arguments: None * Returns: A list of errors (new reference) */ PyObject * error_queue_to_list(void) { PyObject *errlist, *tuple; long err; errlist = PyList_New(0); while ((err = ERR_get_error()) != 0) { tuple = Py_BuildValue("(sss)", ERR_lib_error_string(err), ERR_func_error_string(err), ERR_reason_error_string(err)); PyList_Append(errlist, tuple); Py_DECREF(tuple); } return errlist; } void exception_from_error_queue(PyObject *the_Error) { PyObject *errlist = error_queue_to_list(); PyErr_SetObject(the_Error, errlist); Py_DECREF(errlist); } /* * Flush OpenSSL's error queue and ignore the result * * Arguments: None * Returns: None */ void flush_error_queue(void) { /* * Make sure to save the errors to a local. Py_DECREF might expand such * that it evaluates its argument more than once, which would lead to * very nasty things if we just invoked it with error_queue_to_list(). */ PyObject *list = error_queue_to_list(); Py_DECREF(list); } #if (PY_VERSION_HEX < 0x02600000) PyObject* PyOpenSSL_LongToHex(PyObject *o) { PyObject *hex = NULL; PyObject *format = NULL; PyObject *format_args = NULL; if ((format_args = Py_BuildValue("(O)", o)) == NULL) { goto err; } if ((format = PyString_FromString("%x")) == NULL) { goto err; } if ((hex = PyString_Format(format, format_args)) == NULL) { goto err; } return hex; err: if (format_args) { Py_DECREF(format_args); } if (format) { Py_DECREF(format); } if (hex) { Py_DECREF(hex); } return NULL; } #endif pyOpenSSL-0.13/OpenSSL/util.h0000644000214500021450000000674211630175105015660 0ustar bb-slavebb-slave/* * util.h * * Copyright (C) AB Strakt * See LICENSE for details. * * Export utility functions and macros. * See the file RATIONALE for a short explanation of why this module was written. * * Reviewed 2001-07-23 * */ #ifndef PyOpenSSL_UTIL_H_ #define PyOpenSSL_UTIL_H_ #include #include /* * pymemcompat written by Michael Hudson and lets you program to the * Python 2.3 memory API while keeping backwards compatibility. */ #include "pymemcompat.h" /* * py3k defines macros that help with Python 2.x/3.x compatibility. */ #include "py3k.h" extern PyObject *error_queue_to_list(void); extern void exception_from_error_queue(PyObject *the_Error); extern void flush_error_queue(void); /* * These are needed because there is no "official" way to specify * WHERE to save the thread state. */ #ifdef WITH_THREAD /* * Get the current Python threadstate and put it somewhere any code running * in this thread can get it, if it needs to restore the threadstate to run * some Python. */ # define MY_BEGIN_ALLOW_THREADS(ignored) \ PyThread_delete_key_value(_pyOpenSSL_tstate_key); \ PyThread_set_key_value(_pyOpenSSL_tstate_key, PyEval_SaveThread()); /* * Get the previous Python threadstate and restore it. */ # define MY_END_ALLOW_THREADS(ignored) \ PyEval_RestoreThread(PyThread_get_key_value(_pyOpenSSL_tstate_key)); #else # define MY_BEGIN_ALLOW_THREADS(st) # define MY_END_ALLOW_THREADS(st) { st = NULL; } #endif #if !defined(PY_MAJOR_VERSION) || PY_VERSION_HEX < 0x02000000 static int PyModule_AddObject(PyObject *m, char *name, PyObject *o) { PyObject *dict; if (!PyModule_Check(m) || o == NULL) return -1; dict = PyModule_GetDict(m); if (dict == NULL) return -1; if (PyDict_SetItemString(dict, name, o)) return -1; Py_DECREF(o); return 0; } static int PyModule_AddIntConstant(PyObject *m, char *name, long value) { return PyModule_AddObject(m, name, PyInt_FromLong(value)); } static int PyObject_AsFileDescriptor(PyObject *o) { int fd; PyObject *meth; if (PyInt_Check(o)) { fd = PyInt_AsLong(o); } else if (PyLong_Check(o)) { fd = PyLong_AsLong(o); } else if ((meth = PyObject_GetAttrString(o, "fileno")) != NULL) { PyObject *fno = PyEval_CallObject(meth, NULL); Py_DECREF(meth); if (fno == NULL) return -1; if (PyInt_Check(fno)) { fd = PyInt_AsLong(fno); Py_DECREF(fno); } else if (PyLong_Check(fno)) { fd = PyLong_AsLong(fno); Py_DECREF(fno); } else { PyErr_SetString(PyExc_TypeError, "fileno() returned a non-integer"); Py_DECREF(fno); return -1; } } else { PyErr_SetString(PyExc_TypeError, "argument must be an int, or have a fileno() method."); return -1; } if (fd < 0) { PyErr_Format(PyExc_ValueError, "file descriptor cannot be a negative integer (%i)", fd); return -1; } return fd; } #endif #if !defined(PY_SSIZE_T_MIN) typedef int Py_ssize_t; #define PY_SSIZE_T_MAX INT_MAX #define PY_SSIZE_T_MIN INT_MIN #endif #if (PY_VERSION_HEX < 0x02600000) extern PyObject* PyOpenSSL_LongToHex(PyObject *o); #else #define PyOpenSSL_LongToHex(o) PyNumber_ToBase(o, 16) #endif #ifndef Py_TYPE #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) #endif #endif pyOpenSSL-0.13/OpenSSL/version.py0000644000214500021450000000026011630175105016556 0ustar bb-slavebb-slave# Copyright (C) AB Strakt # Copyright (C) Jean-Paul Calderone # See LICENSE for details. """ pyOpenSSL - A simple wrapper around the OpenSSL library """ __version__ = '0.13' pyOpenSSL-0.13/doc/0000755000214500021450000000000011630175113014002 5ustar bb-slavebb-slavepyOpenSSL-0.13/doc/tools/0000755000214500021450000000000011630175113015142 5ustar bb-slavebb-slavepyOpenSSL-0.13/doc/tools/html/0000755000214500021450000000000011630175113016106 5ustar bb-slavebb-slavepyOpenSSL-0.13/doc/tools/html/icons/0000755000214500021450000000000011630175113017221 5ustar bb-slavebb-slavepyOpenSSL-0.13/doc/tools/html/icons/blank.gif0000644000214500021450000000364611630175105021011 0ustar bb-slavebb-slaveGIF87a  3f333f3333f3ffffff3f̙3f3f333f333333333f33333333f33f3ff3f3f3f3333f33̙33333f3333333f3333f3ffffff3f33ff3f3f3f3fff3ffffffffffff3ffff̙fff3fffffff3ffffff3f333f3333f3ffffff3f̙̙3̙f̙̙̙̙3f3f̙333f3̙333f3fff̙fff3f̙̙3f̙3f̙3f333f3333f3ffffff3f̙3f3f, @e˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[6ٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖ `lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lٲe˖-[lf˖-[lٲe˖- ;pyOpenSSL-0.13/doc/tools/html/icons/blank.png0000644000214500021450000000200711630175105021016 0ustar bb-slavebb-slavePNG  IHDR DPLTE 3f333f3333f3ffffff3f̙3f3f333f333333333f33333333f33f3ff3f3f3f3333f33̙33333f3333333f3333f3ffffff3f33ff3f3f3f3fff3ffffffffffff3ffff̙fff3fffffff3ffffff3f333f3333f3ffffff3f̙̙3̙f̙̙̙̙3f3f̙333f3̙333f3fff̙fff3f̙̙3f̙3f̙3f333f3333f3ffffff3f̙3f3fCAbKGDHIDATxcI0*U0`*d.CtEXtSoftware@(#)ImageMagick 4.2.8 99/08/01 cristy@mystic.es.dupont.com!*tEXtSignature0ac660e469fb3b89a555665df224a4be tEXtPage32x32+0+0S2IENDB`pyOpenSSL-0.13/doc/tools/html/icons/contents.gif0000644000214500021450000000066611630175105021556 0ustar bb-slavebb-slaveGIF89a |si_VLCv:m0c&YPFy =p3f, ` dihlp2{(zDG~Hd(IH$yh"£@D UpC)dAE;)%#=:f#%A| $~A*nB ho)\; %=^8* rw'uQ^ ;"X"`z|PB  $[ &%'>.     }B` ;:lpdʍ zxXZ*G9 ?Q(($'*ix zn74Jذ";pyOpenSSL-0.13/doc/tools/html/icons/contents.png0000644000214500021450000000121111630175105021560 0ustar bb-slavebb-slavePNG  IHDR D`PLTE|si_VLCv:m0c&YPFy =p3f?0bKGD{lIDATx͒ݒ  e1I7Mgg3xF>`|dydlO'>hGBaaV8 +V՗v/{R38wJh"Uo.i|M-I3S$e|Eo3v R,߬3.7w`Zj ?Br E:r %:pmp> .Nlr=tP@~TRE;pyOpenSSL-0.13/doc/tools/html/icons/modules.png0000644000214500021450000000112611630175105021400 0ustar bb-slavebb-slavePNG  IHDR D`PLTE|si_VLCv:m0c&YPFy =p3f?0bKGD{lIDATxr EbݦL{cs7|HEXhmt9Z̉g0 MIL+nOJ{ps^Av7{Wu}fO5a 9Ǿ}4ҠZsEMB$GXըc)zB C3/Oo,;fK>hF *eS@Q_ LzTXtSoftwarexsPMLOMLLV033R7070TH.,.tȭ,.LK-K)-+KK^3zTXtSignaturexK05K3K124H1266KJL3M54204I070.i zTXtPagex360666 GwIENDB`pyOpenSSL-0.13/doc/tools/html/icons/next.gif0000644000214500021450000000037511630175105020674 0ustar bb-slavebb-slaveGIF89a |si_VLCv:m0c&YP =p3f, ` dihlp,Gcl.P?Ih0B QDEPPs׆H*Rh#rn{,6`:bjABf> IBMFpJ>Q}FQ<3DNk 76 \%!;pyOpenSSL-0.13/doc/tools/html/icons/next.png0000644000214500021450000000077711630175105020721 0ustar bb-slavebb-slavePNG  IHDR D`PLTE|si_VLCv:m0c&YP =p3f]=bKGD=IDATx͓0Dc@ vͶ{MfrtF@ uQ@N ;:%فQ!XxmS1 ZOc*Tx< wqhA,Z~LzTXtSoftwarexsPMLOMLLV033R7070TH.,.tȭ,.LK-K)-+KK^3zTXtSignaturex3231L47374K11426NL3105L210HL3|nɾzTXtPagex360666 GwIENDB`pyOpenSSL-0.13/doc/tools/html/icons/previous.gif0000644000214500021450000000037411630175105021571 0ustar bb-slavebb-slaveGIF89a |si_VLCv:m0c&YPFy =p3f, ` dihlp,GcL.QCHAa4\DiT#hBW0t!"p5# ̈́ # ~}I"EcWtoGPWv=sh 4h`cQ ^e 76+!;pyOpenSSL-0.13/doc/tools/html/icons/previous.png0000644000214500021450000000077711630175105021617 0ustar bb-slavebb-slavePNG  IHDR D`PLTE|si_VLCv:m0c&YPFy =p3f?0bKGD{lIDATxՒA DiIZe/8vv$/ H5=S`'R3jBjyZLL Nׄl-1wA4=r`?7cj&$ph,@xx 3LzTXtSoftwarexsPMLOMLLV033R7070TH.,.tȭ,.LK-K)-+KK^3zTXtSignaturex304L0JL4M4KI4H564LL444H40421vC[̓zTXtPagex360666 GwIENDB`pyOpenSSL-0.13/doc/tools/html/about.dat0000644000214500021450000000166011630175105017716 0ustar bb-slavebb-slave

This document was generated using the LaTeX2HTML translator.

LaTeX2HTML is Copyright © 1993, 1994, 1995, 1996, 1997, Nikos Drakos, Computer Based Learning Unit, University of Leeds, and Copyright © 1997, 1998, Ross Moore, Mathematics Department, Macquarie University, Sydney.

The application of LaTeX2HTML to the Python documentation has been heavily tailored by Fred L. Drake, Jr. Original navigation icons were contributed by Christopher Petrilli.

pyOpenSSL-0.13/doc/tools/html/about.html0000644000214500021450000000573411630175105020120 0ustar bb-slavebb-slave About the Python Documentation

About the Python Documentation

The Python documentation was originally written by Guido van Rossum, but has increasingly become a community effort over the past several years. This growing collection of documents is available in several formats, including typeset versions in PDF and PostScript for printing, from the Python Web site.

A list of contributors is available.

Comments and Questions

General comments and questions regarding this document should be sent by email to python-docs@python.org. If you find specific errors in this document, please report the bug at the Python Bug Tracker at SourceForge.

Questions regarding how to use the information in this document should be sent to the Python news group, comp.lang.python, or the Python mailing list (which is gated to the newsgroup and carries the same content).

For any of these channels, please be sure not to send HTML email. Thanks.


pyOpenSSL-0.13/doc/tools/html/index.html.in0000644000214500021450000000662311630175105020520 0ustar bb-slavebb-slave Python @RELEASE@ Documentation - @DATE@

Python Documentation

Release @RELEASE@
@DATE@

   


See About the Python Documentation for information on suggesting changes.
pyOpenSSL-0.13/doc/tools/html/stdabout.dat0000644000214500021450000000340211630175105020425 0ustar bb-slavebb-slave

This document was generated using the LaTeX2HTML translator.

LaTeX2HTML is Copyright © 1993, 1994, 1995, 1996, 1997, Nikos Drakos, Computer Based Learning Unit, University of Leeds, and Copyright © 1997, 1998, Ross Moore, Mathematics Department, Macquarie University, Sydney.

The application of LaTeX2HTML to the Python documentation has been heavily tailored by Fred L. Drake, Jr. Original navigation icons were contributed by Christopher Petrilli.


Comments and Questions

General comments and questions regarding this document should be sent by email to python-docs@python.org. If you find specific errors in this document, please report the bug at the Python Bug Tracker at SourceForge.

Questions regarding how to use the information in this document should be sent to the Python news group, comp.lang.python, or the Python mailing list (which is gated to the newsgroup and carries the same content).

For any of these channels, please be sure not to send HTML email. Thanks.

pyOpenSSL-0.13/doc/tools/html/style.css0000644000214500021450000000635611630175105017773 0ustar bb-slavebb-slave/* * The first part of this is the standard CSS generated by LaTeX2HTML, * with the "empty" declarations removed. */ /* Century Schoolbook font is very similar to Computer Modern Math: cmmi */ .math { font-family: "Century Schoolbook", serif; } .math i { font-family: "Century Schoolbook", serif; font-weight: bold } .boldmath { font-family: "Century Schoolbook", serif; font-weight: bold } /* Implement both fixed-size and relative sizes: */ small.xtiny { font-size : xx-small } small.tiny { font-size : x-small } small.scriptsize { font-size : smaller } small.footnotesize { font-size : small } big.xlarge { font-size : large } big.xxlarge { font-size : x-large } big.huge { font-size : larger } big.xhuge { font-size : xx-large } /* * Document-specific styles come next; * these are added for the Python documentation. * * Note that the size specifications for the H* elements are because * Netscape on Solaris otherwise doesn't get it right; they all end up * the normal text size. */ body { color: #000000; background-color: #ffffff; } a:active { color: #ff0000; } a:visited { color: #551a8b; } a:link { color: #0000bb; } h1, h2, h3, h4, h5, h6 { font-family: avantgarde, sans-serif; font-weight: bold } h1 { font-size: 180% } h2 { font-size: 150% } h3, h4 { font-size: 120% } code, tt { font-family: monospace } var { font-family: times, serif; font-style: italic; font-weight: normal } .navigation td { background-color: #99ccff; font-weight: bold; font-family: avantgarde, sans-serif; font-size: 110% } .release-info { font-style: italic; } .titlegraphic { vertical-align: top; } .verbatim { color: #00008b } .email { font-family: avantgarde, sans-serif } .mimetype { font-family: avantgarde, sans-serif } .newsgroup { font-family: avantgarde, sans-serif } .url { font-family: avantgarde, sans-serif } .file { font-family: avantgarde, sans-serif } .tableheader { background-color: #99ccff; font-family: avantgarde, sans-serif; } .refcount-info { font-style: italic } .refcount-info .value { font-weight: bold; color: #006600 } /* * Some decoration for the "See also:" blocks, in part inspired by some of * the styling on Lars Marius Garshol's XSA pages. * (The blue in the navigation bars is #99CCFF.) */ .seealso { background-color: #fffaf0; border: thin solid black; padding: 4pt } .seealso .heading { font-size: 110% } /* * Class 'availability' is used for module availability statements at * the top of modules. */ .availability .platform { font-weight: bold } pyOpenSSL-0.13/doc/tools/info/0000755000214500021450000000000011630175113016075 5ustar bb-slavebb-slavepyOpenSSL-0.13/doc/tools/info/Makefile0000644000214500021450000000313711630175105017542 0ustar bb-slavebb-slave# Generate the Python "info" documentation. TOPDIR=.. TOOLSDIR=$(TOPDIR)/tools HTMLDIR=$(TOPDIR)/html MKINFO=$(TOOLSDIR)/mkinfo SCRIPTS=$(TOOLSDIR)/html2texi.pl $(TOOLSDIR)/checkargs.pm $(TOOLSDIR)/mkinfo \ $(TOOLSDIR)/fixinfo.el all: python-api.info python-ext.info python-lib.info \ python-ref.info python-tut.info \ python-dist.info python-inst.info python-api.info: $(HTMLDIR)/api/api.html $(SCRIPTS) $(MKINFO) $< python-ext.info: $(HTMLDIR)/ext/ext.html $(SCRIPTS) $(MKINFO) $< python-lib.info: $(HTMLDIR)/lib/lib.html $(SCRIPTS) $(MKINFO) $< # Not built by default; the conversion doesn't really handle it well. python-mac.info: $(HTMLDIR)/mac/mac.html $(SCRIPTS) $(MKINFO) $< python-ref.info: $(HTMLDIR)/ref/ref.html $(SCRIPTS) $(MKINFO) $< python-tut.info: $(HTMLDIR)/tut/tut.html $(SCRIPTS) $(MKINFO) $< python-dist.info: $(HTMLDIR)/dist/dist.html $(SCRIPTS) $(MKINFO) $< python-inst.info: $(HTMLDIR)/inst/inst.html $(SCRIPTS) $(MKINFO) $< clean: rm -f *.texi~ *.texi clobber: clean rm -f *.texi python-*.info python-*.info-[0-9]* # This makes sure we can build info files from a "clean" tree, # in case we haven't already built the HTML: $(HTMLDIR)/api/api.html: (cd $(HTMLDIR); $(MAKE) api) $(HTMLDIR)/ext/ext.html: (cd $(HTMLDIR); $(MAKE) ext) $(HTMLDIR)/lib/lib.html: (cd $(HTMLDIR); $(MAKE) lib) $(HTMLDIR)/mac/mac.html: (cd $(HTMLDIR); $(MAKE) mac) $(HTMLDIR)/ref/ref.html: (cd $(HTMLDIR); $(MAKE) ref) $(HTMLDIR)/tut/tut.html: (cd $(HTMLDIR); $(MAKE) tut) $(HTMLDIR)/dist/dist.html: (cd $(HTMLDIR); $(MAKE) dist) $(HTMLDIR)/inst/inst.html: (cd $(HTMLDIR); $(MAKE) inst) pyOpenSSL-0.13/doc/tools/info/README0000644000214500021450000000153711630175105016764 0ustar bb-slavebb-slaveThis archive contains the standard Python documentation in GNU info format. Five manuals are included: python-ref.info* Python Reference Manual python-mac.info* Python Macintosh Modules python-lib.info* Python Library Reference python-ext.info* Extending and Embedding the Python Interpreter python-api.info* Python/C API Reference python-tut.info* Python Tutorial The file python.dir is a fragment of a "dir" file that can be used to incorporate these documents into an existing GNU info installation: insert the contents of this file into the "dir" or "localdir" file at an appropriate point and copy the python-*.info* files to the same directory. Thanks go to Milan Zamazal for providing this conversion to the info format. Questions and comments on these documents should be directed to python-docs@python.org. pyOpenSSL-0.13/doc/tools/info/python.dir0000644000214500021450000000057411630175105020125 0ustar bb-slavebb-slave Python Standard Documentation * Python Library: (python-lib). Python Library Reference * Python Mac Modules: (python-mac). Python Macintosh Modules * Python Reference: (python-ref). Python Reference Manual * Python API: (python-api). Python/C API Reference Manual * Python Extending: (python-ext). Extending & Embedding Python * Python Tutorial: (python-tut). Python Tutorial pyOpenSSL-0.13/doc/tools/paper-a4/0000755000214500021450000000000011630175113016553 5ustar bb-slavebb-slavepyOpenSSL-0.13/doc/tools/paper-a4/pypaper.sty0000644000214500021450000000020711630175105020774 0ustar bb-slavebb-slave% % Change this to say a4paper instead of letterpaper if you want A4. % \newcommand{\py@paper}{a4paper} \newcommand{\py@ptsize}{10pt} pyOpenSSL-0.13/doc/tools/perl/0000755000214500021450000000000011630175113016104 5ustar bb-slavebb-slavepyOpenSSL-0.13/doc/tools/perl/SynopsisTable.pm0000644000214500021450000000427711630175105021254 0ustar bb-slavebb-slavepackage SynopsisTable; sub new{ return bless {names=>'', info=>{}, file=>''}; } sub declare{ my($self,$name,$key,$type) = @_; if ($self->{names}) { $self->{names} .= ",$name"; } else { $self->{names} .= "$name"; } $self->{info}{$name} = "$key,$type,"; } # The 'file' attribute is used to store the filename of the node in which # the table will be presented; this assumes that each table will be presented # only once, which works for the current use of this object. sub set_file{ my($self, $filename) = @_; $self->{file} = "$filename"; } sub get_file{ my $self = shift; return $self->{file}; } sub set_synopsis{ my($self,$name,$synopsis) = @_; my($key,$type,$unused) = split ',', $self->{info}{$name}, 3; $self->{info}{$name} = "$key,$type,$synopsis"; } sub get{ my($self,$name) = @_; return split /,/, $self->{info}{$name}, 3; } sub show{ my $self = shift; my $name; print "names: ", $self->{names}, "\n\n"; foreach $name (split /,/, $self->{names}) { my($key,$type,$synopsis) = $self->get($name); print "$name($key) is $type: $synopsis\n"; } } sub tohtml{ my $self = shift; my $data = "\n"; my $name; foreach $name (split /,/, $self->{names}) { my($key,$type,$synopsis) = $self->get($name); my $link = ""; $data .= (' ' . "\n" . " \n"); } $data .= "
$link$name$synopsis
\n"; $data; } package testSynopsisTable; sub test{ # this little test is mostly to debug the stuff above, since this is # my first Perl "object". my $st = SynopsisTable->new(); $st->declare("sample", "sample", "standard"); $st->set_synopsis("sample", "This is a little synopsis...."); $st->declare("copy_reg", "copyreg", "standard"); $st->set_synopsis("copy_reg", "pickle support stuff"); $st->show(); print "\n\n"; my $st2 = SynopsisTable->new(); $st2->declare("st2module", "st2module", "built-in"); $st2->set_synopsis("st2module", "silly little synopsis"); $st2->show(); } 1; # This must be the last line -- Perl is bogus! pyOpenSSL-0.13/doc/tools/perl/distutils.perl0000644000214500021450000000062611630175105021021 0ustar bb-slavebb-slave# LaTeX2HTML support for distutils.sty. package main; sub do_cmd_command { return use_wrappers(@_[0], '', ''); } sub do_cmd_option { return use_wrappers(@_[0], '', ''); } sub do_cmd_filevar { return use_wrappers(@_[0], '', ''); } sub do_cmd_XXX { return use_wrappers(@_[0], '** ', ' **'); } 1; pyOpenSSL-0.13/doc/tools/perl/howto.perl0000644000214500021450000000036211630175105020132 0ustar bb-slavebb-slave# -*- perl -*- # # This implements the Python howto class. All it really needs to do it # load the "python" style. package main; do_require_package("article"); do_require_package("alltt"); do_require_package("python"); 1; # sheesh.... pyOpenSSL-0.13/doc/tools/perl/l2hinit.perl0000644000214500021450000004601511630175105020350 0ustar bb-slavebb-slave# LaTeX2HTML support base for use with Python documentation. package main; use L2hos; $HTML_VERSION = 4.0; $MAX_LINK_DEPTH = 2; $ADDRESS = ''; $NO_FOOTNODE = 1; $NUMBERED_FOOTNOTES = 1; # Python documentation uses section numbers to support references to match # in the printed and online versions. # $SHOW_SECTION_NUMBERS = 1; $ICONSERVER = '../icons'; $IMAGE_TYPE = 'gif'; # Control where the navigation bars should show up: $TOP_NAVIGATION = 1; $BOTTOM_NAVIGATION = 1; $AUTO_NAVIGATION = 0; $BODYTEXT = ''; $CHILDLINE = "\n


\n"; $VERBOSITY = 0; # default # of columns for the indexes $INDEX_COLUMNS = 2; $MODULE_INDEX_COLUMNS = 4; # A little painful, but lets us clean up the top level directory a little, # and not be tied to the current directory (as far as I can tell). Testing # an existing definition of $mydir is needed since it cannot be computed when # run under mkhowto with recent versions of LaTeX2HTML, since this file is # not read directly by LaTeX2HTML any more. mkhowto is required to prepend # the required definition at the top of the actual input file. # if (!defined $mydir) { use Cwd; use File::Basename; ($myname, $mydir, $myext) = fileparse(__FILE__, '\..*'); chop $mydir; # remove trailing '/' $mydir = getcwd() . "$dd$mydir" unless $mydir =~ s|^/|/|; } $LATEX2HTMLSTYLES = "$mydir$envkey$LATEX2HTMLSTYLES"; push (@INC, $mydir); ($myrootname, $myrootdir, $myext) = fileparse($mydir, '\..*'); chop $myrootdir; # Hackish way to get the appropriate paper-*/ directory into $TEXINPUTS; # pass in the paper size (a4 or letter) as the environment variable PAPER # to add the right directory. If not given, the current directory is # added instead for use with HOWTO processing. # if (defined $ENV{'PAPER'}) { $mytexinputs = "$myrootdir${dd}paper-$ENV{'PAPER'}$envkey"; } else { $mytexinputs = getcwd() . $envkey; } $mytexinputs .= "$myrootdir${dd}texinputs"; # Change this variable to change the text added in "About this document..."; # this should be an absolute pathname to get it right. # $ABOUT_FILE = "$myrootdir${dd}html${dd}stdabout.dat"; sub custom_driver_hook { # # This adds the directory of the main input file to $TEXINPUTS; it # seems to be sufficiently general that it should be fine for HOWTO # processing. # my $file = @_[0]; my($jobname, $dir, $ext) = fileparse($file, '\..*'); $dir = L2hos->Make_directory_absolute($dir); $dir =~ s/$dd$//; $TEXINPUTS = "$dir$envkey$mytexinputs"; print "\nAdding $dir to \$TEXINPUTS\n"; } $CUSTOM_BUTTONS = ''; sub make_nav_sectref { my($label,$title) = @_; if ($title) { if ($title =~ /\<[aA] /) { $title =~ s/\<[aA] /
$title"; } return "$label: $title\n"; } return ''; } @my_icon_tags = (); $my_icon_tags{'next'} = 'Next Page'; $my_icon_tags{'next_page'} = 'Next Page'; $my_icon_tags{'previous'} = 'Previous Page'; $my_icon_tags{'previous_page'} = 'Previous Page'; $my_icon_tags{'up'} = 'Up One Level'; $my_icon_tags{'contents'} = 'Contents'; $my_icon_tags{'index'} = 'Index'; $my_icon_tags{'modules'} = 'Module Index'; @my_icon_names = (); $my_icon_names{'previous_page'} = 'previous'; $my_icon_names{'next_page'} = 'next'; sub get_my_icon { my $name = @_[0]; my $text = $my_icon_tags{$name}; if ($my_icon_names{$name}) { $name = $my_icon_names{$name}; } if ($text eq '') { $name = 'blank'; } my $iconserver = ($ICONSERVER eq '.') ? '' : "$ICONSERVER/"; return "\"$text\""; } sub use_my_icon { my $s = @_[0]; if ($s =~ /\/) { my $r = get_my_icon($1); $s =~ s/\/$r/; } return $s; } sub make_nav_panel { my $s; my $BLANK_ICON = get_my_icon('blank'); $NEXT = $NEXT_TITLE ? use_my_icon("$NEXT") : $BLANK_ICON; $UP = $UP_TITLE ? use_my_icon("$UP") : $BLANK_ICON; $PREVIOUS = $PREVIOUS_TITLE ? use_my_icon("$PREVIOUS") : $BLANK_ICON; $CONTENTS = use_my_icon("$CONTENTS"); $INDEX = $INDEX ? use_my_icon("$INDEX") : $BLANK_ICON; if (!$CUSTOM_BUTTONS) { $CUSTOM_BUTTONS = $BLANK_ICON; } $s = ('' . "\n" # left-hand side . "\n" . "\n" . "\n" # title box . "\n" # right-hand side . "\n" . "\n" # module index . "\n" . "\n
$PREVIOUS$UP$NEXT$t_title$CONTENTS$CUSTOM_BUTTONS$INDEX
\n" # textual navigation . make_nav_sectref("Previous", $PREVIOUS_TITLE) . make_nav_sectref("Up", $UP_TITLE) . make_nav_sectref("Next", $NEXT_TITLE) ); # remove these; they are unnecessary and cause errors from validation $s =~ s/ NAME="tex2html\d+"\n */ /g; return $s; } sub get_version_text { if ($PACKAGE_VERSION ne '' && $t_date) { return ("" . "Release $PACKAGE_VERSION," . " documentation updated on $t_date."); } if ($PACKAGE_VERSION ne '') { return ("" . "Release $PACKAGE_VERSION."); } if ($t_date) { return ("Documentation released on " . "$t_date."); } return ''; } sub top_navigation_panel { return "\n" . make_nav_panel() . "

\n"; } sub bot_navigation_panel { return "\n


\n" . make_nav_panel() . "
\n" . get_version_text() . "\n"; } sub add_link { # Returns a pair (iconic link, textual link) my($icon, $current_file, @link) = @_; my($dummy, $file, $title) = split($delim, $section_info{join(' ',@link)}); if ($icon =~ /\/) { my $r = get_my_icon($1); $icon =~ s/\/$r/; } if ($title && ($file ne $current_file)) { $title = purify($title); $title = get_first_words($title, $WORDS_IN_NAVIGATION_PANEL_TITLES); return (make_href($file, $icon), make_href($file, "$title")) } elsif ($icon eq get_my_icon('up') && $EXTERNAL_UP_LINK) { return (make_href($EXTERNAL_UP_LINK, $icon), make_href($EXTERNAL_UP_LINK, "$EXTERNAL_UP_TITLE")) } elsif ($icon eq get_my_icon('previous') && $EXTERNAL_PREV_LINK && $EXTERNAL_PREV_TITLE) { return (make_href($EXTERNAL_PREV_LINK, $icon), make_href($EXTERNAL_PREV_LINK, "$EXTERNAL_PREV_TITLE")) } elsif ($icon eq get_my_icon('next') && $EXTERNAL_DOWN_LINK && $EXTERNAL_DOWN_TITLE) { return (make_href($EXTERNAL_DOWN_LINK, $icon), make_href($EXTERNAL_DOWN_LINK, "$EXTERNAL_DOWN_TITLE")) } return (&inactive_img($icon), ""); } sub add_special_link { my($icon, $file, $current_file) = @_; if ($icon =~ /\/) { my $r = get_my_icon($1); $icon =~ s/\/$r/; } return (($file && ($file ne $current_file)) ? make_href($file, $icon) : undef) } # The img_tag() function seems only to be called with the parameter # 'anchor_invisible_mark', which we want to turn into ''. Since # replace_icon_marks() is the only interesting caller, and all it really # does is call img_tag(), we can just define the hook alternative to be # a no-op instead. # sub replace_icons_hook {} sub do_cmd_arabic { # get rid of that nasty ... my($ctr, $val, $id, $text) = &read_counter_value(@_[0]); return ($val ? farabic($val) : "0") . $text; } sub gen_index_id { # this is used to ensure common index key generation and a stable sort my($str,$extra) = @_; sprintf('%s###%s%010d', $str, $extra, ++$global{'max_id'}); } sub insert_index { my($mark,$datafile,$columns,$letters,$prefix) = @_; my $prog = "$myrootdir/tools/buildindex.py"; my $index; if ($letters) { $index = `$prog --columns $columns --letters $datafile`; } else { $index = `$prog --columns $columns $datafile`; } if (!s/$mark/$prefix$index/) { print "\nCould not locate index mark: $mark"; } } sub add_idx { print "\nBuilding HTML for the index ..."; close(IDXFILE); insert_index($idx_mark, 'index.dat', $INDEX_COLUMNS, 1, ''); } $idx_module_mark = ''; $idx_module_title = 'Module Index'; sub add_module_idx { print "\nBuilding HTML for the module index ..."; my $key; my $first = 1; my $prevplat = ''; my $allthesame = 1; my $prefix = ''; foreach $key (keys %Modules) { $key =~ s/([a-zA-Z0-9._]*)<\/tt>/\1/; my $plat = "$ModulePlatforms{$key}"; $plat = '' if ($plat eq $IGNORE_PLATFORM_ANNOTATION); if (!$first) { $allthesame = 0 if ($prevplat ne $plat); } else { $first = 0; } $prevplat = $plat; } open(MODIDXFILE, '>modindex.dat') || die "\n$!\n"; foreach $key (keys %Modules) { # dump the line in the data file; just use a dummy seqno field my $nkey = $1; my $moditem = "$Modules{$key}"; my $plat = ''; $key =~ s/([a-zA-Z0-9._]*)<\/tt>/\1/; if ($ModulePlatforms{$key} && !$allthesame) { $plat = (" ($ModulePlatforms{$key}" . ')'); } print MODIDXFILE $moditem . $IDXFILE_FIELD_SEP . "$key$plat###\n"; } close(MODIDXFILE); if ($GLOBAL_MODULE_INDEX) { $prefix = < This index only lists modules documented in this manual. The
Global Module Index lists all modules that are documented in this set of manuals.

MODULE_INDEX_PREFIX } if (!$allthesame) { $prefix .= < Some module names are followed by an annotation indicating what platform they are available on.

PLAT_DISCUSS } insert_index($idx_module_mark, 'modindex.dat', $MODULE_INDEX_COLUMNS, 0, $prefix); } # replace both indexes as needed: sub add_idx_hook { add_idx() if (/$idx_mark/); process_python_state(); if ($MODULE_INDEX_FILE) { local ($_); open(MYFILE, "<$MODULE_INDEX_FILE"); sysread(MYFILE, $_, 1024*1024); close(MYFILE); add_module_idx(); open(MYFILE,">$MODULE_INDEX_FILE"); print MYFILE $_; close(MYFILE); } } # In addition to the standard stuff, add label to allow named node files and # support suppression of the page complete (for HTML Help use). sub do_cmd_tableofcontents { local($_) = @_; $TITLE = $toc_title; $tocfile = $CURRENT_FILE; my($closures,$reopens) = preserve_open_tags(); anchor_label('contents', $CURRENT_FILE, $_); # this is added join('', "
\n\\tableofchildlinks[off]", $closures , make_section_heading($toc_title, 'H2'), $toc_mark , $reopens, $_); } # In addition to the standard stuff, add label to allow named node files. sub do_cmd_listoffigures { local($_) = @_; $TITLE = $lof_title; $loffile = $CURRENT_FILE; my($closures,$reopens) = preserve_open_tags(); anchor_label('lof', $CURRENT_FILE, $_); # this is added join('', "
\n", $closures , make_section_heading($lof_title, 'H2'), $lof_mark , $reopens, $_); } # In addition to the standard stuff, add label to allow named node files. sub do_cmd_listoftables { local($_) = @_; $TITLE = $lot_title; $lotfile = $CURRENT_FILE; my($closures,$reopens) = preserve_open_tags(); anchor_label('lot', $CURRENT_FILE, $_); # this is added join('', "
\n", $closures , make_section_heading($lot_title, 'H2'), $lot_mark , $reopens, $_); } # In addition to the standard stuff, add label to allow named node files. sub do_cmd_textohtmlinfopage { local($_) = @_; if ($INFO) { # anchor_label("about",$CURRENT_FILE,$_); # this is added } # my $the_version = ''; # and the rest is if ($t_date) { # mostly ours $the_version = ",\n$t_date"; if ($PACKAGE_VERSION) { $the_version .= ", Release $PACKAGE_VERSION"; } } $_ = (($INFO == 1) ? join('', $close_all, "$t_title$the_version\n", `cat $ABOUT_FILE`, $open_all, $_) : join('', $close_all, $INFO,"\n", $open_all, $_)); $_; } # $idx_mark will be replaced with the real index at the end sub do_cmd_textohtmlindex { local($_) = @_; $TITLE = $idx_title; $idxfile = $CURRENT_FILE; if (%index_labels) { make_index_labels(); } if (($SHORT_INDEX) && (%index_segment)) { make_preindex(); } else { $preindex = ''; } my $heading = make_section_heading($idx_title, 'h2') . $idx_mark; my($pre,$post) = minimize_open_tags($heading); anchor_label('genindex',$CURRENT_FILE,$_); # this is added return "
\n" . $pre . $_; } $MODULE_INDEX_FILE = ''; # $idx_module_mark will be replaced with the real index at the end sub do_cmd_textohtmlmoduleindex { local($_) = @_; $TITLE = $idx_module_title; anchor_label('modindex', $CURRENT_FILE, $_); $MODULE_INDEX_FILE = "$CURRENT_FILE"; $_ = ('

' . make_section_heading($idx_module_title, 'h2') . $idx_module_mark . $_); return $_; } # The bibliography and the index should be treated as separate # sections in their own HTML files. The \bibliography{} command acts # as a sectioning command that has the desired effect. But when the # bibliography is constructed manually using the thebibliography # environment, or when using the theindex environment it is not # possible to use the normal sectioning mechanism. This subroutine # inserts a \bibliography{} or a dummy \textohtmlindex command just # before the appropriate environments to force sectioning. # XXX This *assumes* that if there are two {theindex} environments, # the first is the module index and the second is the standard # index. This is sufficient for the current Python documentation, # but that's about it. sub add_bbl_and_idx_dummy_commands { my $id = $global{'max_id'}; s/([\\]begin\s*$O\d+$C\s*thebibliography)/$bbl_cnt++; $1/eg; s/([\\]begin\s*$O\d+$C\s*thebibliography)/$id++; "\\bibliography$O$id$C$O$id$C $1"/geo; my(@parts) = split(/\\begin\s*$O\d+$C\s*theindex/); if (scalar(@parts) == 3) { # Be careful to re-write the string in place, since $_ is *not* # returned explicity; *** nasty side-effect dependency! *** print "\nadd_bbl_and_idx_dummy_commands ==> adding module index"; my $rx = "([\\\\]begin\\s*$O\\d+$C\\s*theindex[\\s\\S]*)" . "([\\\\]begin\\s*$O\\d+$C\\s*theindex)"; s/$rx/\\textohtmlmoduleindex \1 \\textohtmlindex \2/o; # Add a button to the navigation areas: $CUSTOM_BUTTONS .= ('' . get_my_icon('modules') . ''); } else { $CUSTOM_BUTTONS .= get_my_icon('blank'); $global{'max_id'} = $id; # not sure why.... s/([\\]begin\s*$O\d+$C\s*theindex)/\\textohtmlindex $1/o; s/[\\]printindex/\\textohtmlindex /o; } #---------------------------------------------------------------------- lib_add_bbl_and_idx_dummy_commands() if defined(&lib_add_bbl_and_idx_dummy_commands); } # The bibliographic references, the appendices, the lists of figures # and tables etc. must appear in the contents table at the same level # as the outermost sectioning command. This subroutine finds what is # the outermost level and sets the above to the same level; sub set_depth_levels { # Sets $outermost_level my $level; #RRM: do not alter user-set value for $MAX_SPLIT_DEPTH foreach $level ("part", "chapter", "section", "subsection", "subsubsection", "paragraph") { last if (($outermost_level) = /\\($level)$delimiter_rx/); } $level = ($outermost_level ? $section_commands{$outermost_level} : do {$outermost_level = 'section'; 3;}); #RRM: but calculate value for $MAX_SPLIT_DEPTH when a $REL_DEPTH was given if ($REL_DEPTH && $MAX_SPLIT_DEPTH) { $MAX_SPLIT_DEPTH = $level + $MAX_SPLIT_DEPTH; } elsif (!($MAX_SPLIT_DEPTH)) { $MAX_SPLIT_DEPTH = 1 }; %unnumbered_section_commands = ('tableofcontents' => $level, 'listoffigures' => $level, 'listoftables' => $level, 'bibliography' => $level, 'textohtmlindex' => $level, 'textohtmlmoduleindex' => $level); $section_headings{'textohtmlmoduleindex'} = 'h1'; %section_commands = (%unnumbered_section_commands, %section_commands); make_sections_rx(); } # This changes the markup used for {verbatim} environments, and is the # best way I've found that ensures the

goes on the outside of the #
...
. # # Note that this *must* be done in the init file, not the python.perl # style support file. The %declarations must be set before # initialize() is called in the main LaTeX2HTML script (which happens # before style files are loaded). # %declarations = ('preform' => '
', %declarations); # This is added to get rid of the long comment that follows the # doctype declaration; MSIE5 on NT4 SP4 barfs on it and drops the # content of the page. sub make_head_and_body { my($title, $body) = @_; $body = " $body" unless ($body eq ''); my $DTDcomment = ''; my($version, $isolanguage) = ($HTML_VERSION, 'EN'); my %isolanguages = ( 'english', 'EN' , 'USenglish', 'EN.US' , 'original', 'EN' , 'german' , 'DE' , 'austrian', 'DE.AT', 'french' , 'FR' , 'spanish', 'ES'); $isolanguage = $isolanguages{$default_language}; $isolanguage = 'EN' unless $isolanguage; $title = &purify($title,1); eval("\$title = ". $default_title ) unless ($title); # allow user-modification of the tag; thanks Dan Young if (defined &custom_TITLE_hook) { $title = &custom_TITLE_hook($title, $toc_sec_title); } if ($DOCTYPE =~ /\/\/[\w\.]+\s*$/) { # language spec included $DTDcomment = "<!DOCTYPE html PUBLIC \"$DOCTYPE\">\n"; } else { $DTDcomment = "<!DOCTYPE html PUBLIC \"$DOCTYPE//" . ($ISO_LANGUAGE ? $ISO_LANGUAGE : $isolanguage) . "\">\n"; } $STYLESHEET = $FILE.".css" unless $STYLESHEET; if (!$charset && $CHARSET) { $charset = $CHARSET; $charset =~ s/_/\-/go; } join('', ($DOCTYPE ? $DTDcomment : '' ) ,"<html>\n<head>\n<title>", $title, "\n" , &meta_information($title) , ($CHARSET && $HTML_VERSION ge "2.1" ? "\n" : "" ) , ($BASE ? "\n" : "" ) , "" , $more_links_mark , "\n\n"); } 1; # This must be the last line pyOpenSSL-0.13/doc/tools/perl/ltxmarkup.perl0000644000214500021450000000360111630175105021020 0ustar bb-slavebb-slave# LaTeX2HTML support for the ltxmarkup package. Doesn't do indexing. package main; sub ltx_next_argument{ my $param; $param = missing_braces() unless ((s/$next_pair_pr_rx/$param=$2;''/eo) ||(s/$next_pair_rx/$param=$2;''/eo)); return $param; } sub do_cmd_macro{ local($_) = @_; my $macro = ltx_next_argument(); return "\$macro" . $_; } sub do_cmd_env{ local($_) = @_; my $env = ltx_next_argument(); return "\$env" . $_; } sub ltx_process_params{ # Handle processing of \p and \op for parameter specifications for # envdesc and macrodesc. It's done this way to avoid defining do_cmd_p() # and do_cmd_op() functions, which would be interpreted outside the context # in which these commands are legal, and cause LaTeX2HTML to think they're # defined. This way, other uses of \p and \op are properly flagged as # unknown macros. my $s = @_[0]; $s =~ s%\\op<<(\d+)>>(.+)<<\1>>%[$2]%; while ($s =~ /\\p<<(\d+)>>(.+)<<\1>>/) { $s =~ s%\\p<<(\d+)>>(.+)<<\1>>%{$2}%; } return $s; } sub do_env_macrodesc{ local($_) = @_; my $macro = ltx_next_argument(); my $params = ltx_process_params(ltx_next_argument()); return "\n
" . "\n
\$macro" . "\n $params" . "\n
" . $_ . "
"; } sub do_env_envdesc{ local($_) = @_; my $env = ltx_next_argument(); my $params = ltx_process_params(ltx_next_argument()); return "\n
" . "\n
\begin{$env}" . "\n $params" . "\n
\end{$env}" . "\n
" . $_ . "
"; } 1; # Must end with this, because Perl is bogus. pyOpenSSL-0.13/doc/tools/perl/manual.perl0000644000214500021450000000072111630175105020246 0ustar bb-slavebb-slave# -*- perl -*- # # This implements the Python manual class. All it really needs to do it # load the "python" style. The style code is not moved into the class code # at this time, since we expect additional document class to be developed # for the Python documentation in the future. Appropriate relocations will # be made at that time. package main; do_require_package("report"); do_require_package("alltt"); do_require_package("python"); 1; # sheesh.... pyOpenSSL-0.13/doc/tools/perl/python.perl0000644000214500021450000013316411630175105020322 0ustar bb-slavebb-slave# python.perl by Fred L. Drake, Jr. -*- perl -*- # # Heavily based on Guido van Rossum's myformat.perl (now obsolete). # # Extension to LaTeX2HTML for documents using myformat.sty. # Subroutines of the form do_cmd_ here define translations # for LaTeX commands \ defined in the corresponding .sty file. package main; use File::Basename; sub next_argument{ my $param; $param = missing_braces() unless ((s/$next_pair_pr_rx/$param=$2;''/eo) ||(s/$next_pair_rx/$param=$2;''/eo)); return $param; } sub next_optional_argument{ my($param,$rx) = ('', "^\\s*(\\[([^]]*)\\])?"); s/$rx/$param=$2;''/eo; return $param; } sub make_icon_filename($){ my($myname, $mydir, $myext) = fileparse(@_[0], '\..*'); chop $mydir; if ($mydir eq '.') { $mydir = $ICONSERVER; } $myext = ".$IMAGE_TYPE" unless $myext; return "$mydir$dd$myname$myext"; } sub get_link_icon($){ my $url = @_[0]; if ($OFF_SITE_LINK_ICON && ($url =~ /^[-a-zA-Z0-9.]+:/)) { # absolute URL; assume it points off-site my $icon = make_icon_filename($OFF_SITE_LINK_ICON); return (" [off-site link]"); } return ''; } # This is a fairly simple hack; it supports \let when it is used to create # (or redefine) a macro to exactly be some other macro: \let\newname=\oldname. # Many possible uses of \let aren't supported or aren't supported correctly. # sub do_cmd_let{ local($_) = @_; my $matched = 0; s/[\\]([a-zA-Z]+)\s*(=\s*)?[\\]([a-zA-Z]*)/$matched=1; ''/e; if ($matched) { my($new, $old) = ($1, $3); eval "sub do_cmd_$new { do_cmd_$old" . '(@_); }'; print "\ndefining handler for \\$new using \\$old\n"; } else { s/[\\]([a-zA-Z]+)\s*(=\s*)?([^\\])/$matched=1; ''/es; if ($matched) { my($new, $char) = ($1, $3); eval "sub do_cmd_$new { \"\\$char\" . \@_[0]; }"; print "\ndefining handler for \\$new to insert '$char'\n"; } else { write_warnings("Could not interpret \\let construct..."); } } return $_; } # the older version of LaTeX2HTML we use doesn't support this, but we use it: sub do_cmd_textasciitilde{ '~' . @_[0]; } # words typeset in a special way (not in HTML though) sub do_cmd_ABC{ 'ABC' . @_[0]; } sub do_cmd_UNIX{ 'Unix'. @_[0]; } sub do_cmd_ASCII{ 'ASCII' . @_[0]; } sub do_cmd_POSIX{ 'POSIX' . @_[0]; } sub do_cmd_C{ 'C' . @_[0]; } sub do_cmd_Cpp{ 'C++' . @_[0]; } sub do_cmd_EOF{ 'EOF' . @_[0]; } sub do_cmd_NULL{ 'NULL' . @_[0]; } sub do_cmd_e{ '\' . @_[0]; } $DEVELOPER_ADDRESS = ''; $SHORT_VERSION = ''; $PACKAGE_VERSION = ''; sub do_cmd_version{ $PACKAGE_VERSION . @_[0]; } sub do_cmd_shortversion{ $SHORT_VERSION . @_[0]; } sub do_cmd_release{ local($_) = @_; $PACKAGE_VERSION = next_argument(); return $_; } sub do_cmd_setshortversion{ local($_) = @_; $SHORT_VERSION = next_argument(); return $_; } sub do_cmd_authoraddress{ local($_) = @_; $DEVELOPER_ADDRESS = next_argument(); return $_; } #sub do_cmd_developer{ do_cmd_author(@_[0]); } #sub do_cmd_developers{ do_cmd_author(@_[0]); } #sub do_cmd_developersaddress{ do_cmd_authoraddress(@_[0]); } sub do_cmd_hackscore{ local($_) = @_; next_argument(); return '_' . $_; } sub use_wrappers{ local($_,$before,$after) = @_; my $stuff = next_argument(); return $before . $stuff . $after . $_; } $IN_DESC_HANDLER = 0; sub do_cmd_optional{ if ($IN_DESC_HANDLER) { return use_wrappers(@_[0], "\[", "\]"); } else { return use_wrappers(@_[0], "\[", "\]"); } } # Logical formatting (some based on texinfo), needs to be converted to # minimalist HTML. The "minimalist" is primarily to reduce the size of # output files for users that read them over the network rather than # from local repositories. # \file and \samp are at the end of this file since they screw up fontlock. sub do_cmd_pytype{ return @_[0]; } sub do_cmd_makevar{ return use_wrappers(@_[0], '', ''); } sub do_cmd_code{ return use_wrappers(@_[0], '', ''); } sub do_cmd_module{ return use_wrappers(@_[0], '', ''); } sub do_cmd_keyword{ return use_wrappers(@_[0], '', ''); } sub do_cmd_exception{ return use_wrappers(@_[0], '', ''); } sub do_cmd_class{ return use_wrappers(@_[0], '', ''); } sub do_cmd_function{ return use_wrappers(@_[0], '', ''); } sub do_cmd_constant{ return use_wrappers(@_[0], '', ''); } sub do_cmd_member{ return use_wrappers(@_[0], '', ''); } sub do_cmd_method{ return use_wrappers(@_[0], '', ''); } sub do_cmd_cfunction{ return use_wrappers(@_[0], '', ''); } sub do_cmd_cdata{ return use_wrappers(@_[0], '', ''); } sub do_cmd_ctype{ return use_wrappers(@_[0], '', ''); } sub do_cmd_regexp{ return use_wrappers(@_[0], '', ''); } sub do_cmd_character{ return use_wrappers(@_[0], '"', '"'); } sub do_cmd_program{ return use_wrappers(@_[0], '', ''); } sub do_cmd_programopt{ return use_wrappers(@_[0], '', ''); } sub do_cmd_longprogramopt{ # note that the --- will be later converted to -- by LaTeX2HTML return use_wrappers(@_[0], '---', ''); } sub do_cmd_email{ return use_wrappers(@_[0], ''); } sub do_cmd_mimetype{ return use_wrappers(@_[0], '', ''); } sub do_cmd_var{ return use_wrappers(@_[0], "", ""); } sub do_cmd_dfn{ return use_wrappers(@_[0], '', ''); } sub do_cmd_emph{ return use_wrappers(@_[0], '', ''); } sub do_cmd_file{ return use_wrappers(@_[0], '', ''); } sub do_cmd_filenq{ return do_cmd_file(@_[0]); } sub do_cmd_samp{ return use_wrappers(@_[0], '"', '"'); } sub do_cmd_kbd{ return use_wrappers(@_[0], '', ''); } sub do_cmd_strong{ return use_wrappers(@_[0], '', ''); } sub do_cmd_textbf{ return use_wrappers(@_[0], '', ''); } sub do_cmd_textit{ return use_wrappers(@_[0], '', ''); } sub do_cmd_moreargs{ return '...' . @_[0]; } sub do_cmd_unspecified{ return '...' . @_[0]; } sub do_cmd_refmodule{ # Insert the right magic to jump to the module definition. local($_) = @_; my $key = next_optional_argument(); my $module = next_argument(); $key = $module unless $key; return "$module" . $_; } sub do_cmd_newsgroup{ local($_) = @_; my $newsgroup = next_argument(); my $icon = get_link_icon("news:$newsgroup"); my $stuff = "" . "$newsgroup$icon"; return $stuff . $_; } sub do_cmd_envvar{ local($_) = @_; my $envvar = next_argument(); my($name,$aname,$ahref) = new_link_info(); # The here is really to keep buildindex.py from making # the variable name case-insensitive. add_index_entry("environment variables!$envvar@$envvar", $ahref); add_index_entry("$envvar (environment variable)", $ahref); $aname =~ s/" . $_; } sub do_cmd_url{ # use the URL as both text and hyperlink local($_) = @_; my $url = next_argument(); my $icon = get_link_icon($url); $url =~ s/~/~/g; return "$url$icon" . $_; } sub do_cmd_manpage{ # two parameters: \manpage{name}{section} local($_) = @_; my $page = next_argument(); my $section = next_argument(); return "$page($section)" . $_; } $PEP_FORMAT = "http://python.sourceforge.net/peps/pep-XXXX.html"; $RFC_FORMAT = "http://www.ietf.org/rfc/rfcXXXX.txt"; sub get_rfc_url($$){ my($rfcnum, $format) = @_; $rfcnum = sprintf("%04d", $rfcnum); $format = "$format"; $format =~ s/XXXX/$rfcnum/; return $format; } sub do_cmd_pep{ local($_) = @_; my $rfcnumber = next_argument(); my $id = "rfcref-" . ++$global{'max_id'}; my $href = get_rfc_url($rfcnumber, $PEP_FORMAT); my $icon = get_link_icon($href); # Save the reference my $nstr = gen_index_id("Python Enhancement Proposals!PEP $rfcnumber", ''); $index{$nstr} .= make_half_href("$CURRENT_FILE#$id"); return ("PEP $rfcnumber" . "$icon" . $_); } sub do_cmd_rfc{ local($_) = @_; my $rfcnumber = next_argument(); my $id = "rfcref-" . ++$global{'max_id'}; my $href = get_rfc_url($rfcnumber, $RFC_FORMAT); my $icon = get_link_icon($href); # Save the reference my $nstr = gen_index_id("RFC!RFC $rfcnumber", ''); $index{$nstr} .= make_half_href("$CURRENT_FILE#$id"); return ("RFC $rfcnumber" . "$icon" . $_); } sub do_cmd_citetitle{ local($_) = @_; my $url = next_optional_argument(); my $title = next_argument(); my $icon = get_link_icon($url); my $repl = ''; if ($url) { $repl = ("$title$icon"); } else { $repl = "$title"; } return $repl . $_; } sub do_cmd_deprecated{ # two parameters: \deprecated{version}{whattodo} local($_) = @_; my $release = next_argument(); my $reason = next_argument(); return ('
' . "Deprecated since release $release." . "\n$reason

" . $_); } sub do_cmd_versionadded{ # one parameter: \versionadded{version} local($_) = @_; my $release = next_argument(); return ("\nNew in version $release.\n" . $_); } sub do_cmd_versionchanged{ # one parameter: \versionchanged{version} local($_) = @_; my $explanation = next_optional_argument(); my $release = next_argument(); my $text = "Changed in version $release."; if ($explanation) { $text = "Changed in version $release:\n$explanation."; } return "\n$text\n" . $_; } # # These function handle platform dependency tracking. # sub do_cmd_platform{ local($_) = @_; my $platform = next_argument(); $ModulePlatforms{"$THIS_MODULE"} = $platform; $platform = "Macintosh" if $platform eq 'Mac'; return "\n

Availability: $platform.

\n" . $_; } $IGNORE_PLATFORM_ANNOTATION = ''; sub do_cmd_ignorePlatformAnnotation{ local($_) = @_; $IGNORE_PLATFORM_ANNOTATION = next_argument(); return $_; } # index commands $INDEX_SUBITEM = ""; sub get_indexsubitem{ return $INDEX_SUBITEM ? " $INDEX_SUBITEM" : ''; } sub do_cmd_setindexsubitem{ local($_) = @_; $INDEX_SUBITEM = next_argument(); return $_; } sub do_cmd_withsubitem{ # We can't really do the right thing, because LaTeX2HTML doesn't # do things in the right order, but we need to at least strip this stuff # out, and leave anything that the second argument expanded out to. # local($_) = @_; my $oldsubitem = $INDEX_SUBITEM; $INDEX_SUBITEM = next_argument(); my $stuff = next_argument(); my $br_id = ++$globals{'max_id'}; my $marker = "$O$br_id$C"; return $stuff . "\\setindexsubitem$marker$oldsubitem$marker" . $_; } # This is the prologue macro which is required to start writing the # mod\jobname.idx file; we can just ignore it. (Defining this suppresses # a warning that \makemodindex is unknown.) # sub do_cmd_makemodindex{ return @_[0]; } # We're in the document subdirectory when this happens! # open(IDXFILE, '>index.dat') || die "\n$!\n"; open(INTLABELS, '>intlabels.pl') || die "\n$!\n"; print INTLABELS "%internal_labels = ();\n"; print INTLABELS "1; # hack in case there are no entries\n\n"; # Using \0 for this is bad because we can't use common tools to work with the # resulting files. Things like grep can be useful with this stuff! # $IDXFILE_FIELD_SEP = "\1"; sub write_idxfile{ my ($ahref, $str) = @_; print IDXFILE $ahref, $IDXFILE_FIELD_SEP, $str, "\n"; } sub gen_link{ my($node,$target) = @_; print INTLABELS "\$internal_labels{\"$target\"} = \"$URL/$node\";\n"; return ""; } sub add_index_entry{ # add an entry to the index structures; ignore the return value my($str,$ahref) = @_; $str = gen_index_id($str, ''); $index{$str} .= $ahref; write_idxfile($ahref, $str); } sub new_link_info{ my $name = "l2h-" . ++$globals{'max_id'}; my $aname = ""; my $ahref = gen_link($CURRENT_FILE, $name); return ($name, $aname, $ahref); } $IndexMacroPattern = ''; sub define_indexing_macro{ my $count = @_; my $i = 0; for (; $i < $count; ++$i) { my $name = @_[$i]; my $cmd = "idx_cmd_$name"; die "\nNo function $cmd() defined!\n" if (!defined &$cmd); eval ("sub do_cmd_$name { return process_index_macros(" . "\@_[0], '$name'); }"); if (length($IndexMacroPattern) == 0) { $IndexMacroPattern = "$name"; } else { $IndexMacroPattern .= "|$name"; } } } $DEBUG_INDEXING = 0; sub process_index_macros{ local($_) = @_; my $cmdname = @_[1]; # This is what triggered us in the first place; # we know it's real, so just process it. my($name,$aname,$ahref) = new_link_info(); my $cmd = "idx_cmd_$cmdname"; print "\nIndexing: \\$cmdname" if $DEBUG_INDEXING; &$cmd($ahref); # modifies $_ and adds index entries while (/^[\s\n]*\\($IndexMacroPattern)" . $_; } define_indexing_macro('index'); sub idx_cmd_index{ my $str = next_argument(); add_index_entry("$str", @_[0]); } define_indexing_macro('kwindex'); sub idx_cmd_kwindex{ my $str = next_argument(); add_index_entry("$str!keyword", @_[0]); add_index_entry("keyword!$str", @_[0]); } define_indexing_macro('indexii'); sub idx_cmd_indexii{ my $str1 = next_argument(); my $str2 = next_argument(); add_index_entry("$str1!$str2", @_[0]); add_index_entry("$str2!$str1", @_[0]); } define_indexing_macro('indexiii'); sub idx_cmd_indexiii{ my $str1 = next_argument(); my $str2 = next_argument(); my $str3 = next_argument(); add_index_entry("$str1!$str2 $str3", @_[0]); add_index_entry("$str2!$str3, $str1", @_[0]); add_index_entry("$str3!$str1 $str2", @_[0]); } define_indexing_macro('indexiv'); sub idx_cmd_indexiv{ my $str1 = next_argument(); my $str2 = next_argument(); my $str3 = next_argument(); my $str4 = next_argument(); add_index_entry("$str1!$str2 $str3 $str4", @_[0]); add_index_entry("$str2!$str3 $str4, $str1", @_[0]); add_index_entry("$str3!$str4, $str1 $str2", @_[0]); add_index_entry("$str4!$$str1 $str2 $str3", @_[0]); } define_indexing_macro('ttindex'); sub idx_cmd_ttindex{ my $str = next_argument(); my $entry = $str . get_indexsubitem(); add_index_entry($entry, @_[0]); } sub my_typed_index_helper{ my($word,$ahref) = @_; my $str = next_argument(); add_index_entry("$str $word", $ahref); add_index_entry("$word!$str", $ahref); } define_indexing_macro('stindex', 'opindex', 'exindex', 'obindex'); sub idx_cmd_stindex{ my_typed_index_helper('statement', @_[0]); } sub idx_cmd_opindex{ my_typed_index_helper('operator', @_[0]); } sub idx_cmd_exindex{ my_typed_index_helper('exception', @_[0]); } sub idx_cmd_obindex{ my_typed_index_helper('object', @_[0]); } define_indexing_macro('bifuncindex'); sub idx_cmd_bifuncindex{ my $str = next_argument(); add_index_entry("$str() (built-in function)", @_[0]); } sub make_mod_index_entry{ my($str,$define) = @_; my($name,$aname,$ahref) = new_link_info(); # equivalent of add_index_entry() using $define instead of '' $ahref =~ s/\#[-_a-zA-Z0-9]*\"/\"/ if ($define eq 'DEF'); $str = gen_index_id($str, $define); $index{$str} .= $ahref; write_idxfile($ahref, $str); if ($define eq 'DEF') { # add to the module index $str =~ /()/; my $nstr = $1; $Modules{$nstr} .= $ahref; } return "$aname$anchor_invisible_mark2"; } $THIS_MODULE = ''; $THIS_CLASS = ''; sub define_module{ my($word,$name) = @_; my $section_tag = join('', @curr_sec_id); if ($word ne "built-in" && $word ne "extension" && $word ne "standard" && $word ne "") { write_warnings("Bad module type '$word'" . " for \\declaremodule (module $name)"); $word = ""; } $word = "$word " if $word; $THIS_MODULE = "$name"; $INDEX_SUBITEM = "(in module $name)"; print "[$name]"; return make_mod_index_entry( "$name (${word}module)", 'DEF'); } sub my_module_index_helper{ local($word, $_) = @_; my $name = next_argument(); return define_module($word, $name) . $_; } sub do_cmd_modindex{ return my_module_index_helper('', @_); } sub do_cmd_bimodindex{ return my_module_index_helper('built-in', @_); } sub do_cmd_exmodindex{ return my_module_index_helper('extension', @_); } sub do_cmd_stmodindex{ return my_module_index_helper('standard', @_); } sub ref_module_index_helper{ my($word, $ahref) = @_; my $str = next_argument(); $word = "$word " if $word; $str = "$str (${word}module)"; # can't use add_index_entry() since the 2nd arg to gen_index_id() is used; # just inline it all here $str = gen_index_id($str, 'REF'); $index{$str} .= $ahref; write_idxfile($ahref, $str); } # these should be adjusted a bit.... define_indexing_macro('refmodindex', 'refbimodindex', 'refexmodindex', 'refstmodindex'); sub idx_cmd_refmodindex{ return ref_module_index_helper('', @_); } sub idx_cmd_refbimodindex{ return ref_module_index_helper('built-in', @_); } sub idx_cmd_refexmodindex{ return ref_module_index_helper('extension', @_); } sub idx_cmd_refstmodindex{ return ref_module_index_helper('standard', @_); } sub do_cmd_nodename{ return do_cmd_label(@_); } sub init_myformat{ $anchor_invisible_mark = ' '; $anchor_invisible_mark2 = ''; $anchor_mark = ''; $icons{'anchor_mark'} = ''; } init_myformat(); # Create an index entry, but include the string in the target anchor # instead of the dummy filler. # sub make_str_index_entry{ my($str) = @_; my($name,$aname,$ahref) = new_link_info(); add_index_entry($str, $ahref); return "$aname$str"; } $REFCOUNTS_LOADED = 0; sub load_refcounts{ $REFCOUNTS_LOADED = 1; my $myname, $mydir, $myext; ($myname, $mydir, $myext) = fileparse(__FILE__, '\..*'); chop $mydir; # remove trailing '/' ($myname, $mydir, $myext) = fileparse($mydir, '\..*'); chop $mydir; # remove trailing '/' $mydir = getcwd() . "$dd$mydir" unless $mydir =~ s|^/|/|; local $_; my $filename = "$mydir${dd}api${dd}refcounts.dat"; open(REFCOUNT_FILE, "<$filename") || die "\n$!\n"; print "[loading API refcount data]"; while () { if (/([a-zA-Z0-9_]+):PyObject\*:([a-zA-Z0-9_]*):(0|[-+]1|null):(.*)$/) { my($func, $param, $count, $comment) = ($1, $2, $3, $4); #print "\n$func($param) --> $count"; $REFCOUNTS{"$func:$param"} = $count; } } } sub get_refcount{ my ($func, $param) = @_; load_refcounts() unless $REFCOUNTS_LOADED; return $REFCOUNTS{"$func:$param"}; } sub do_env_cfuncdesc{ local($_) = @_; my $return_type = next_argument(); my $function_name = next_argument(); my $arg_list = next_argument(); my $idx = make_str_index_entry( "$function_name()" . get_indexsubitem()); $idx =~ s/ \(.*\)//; $idx =~ s/\(\)//; # ???? - why both of these? my $result_rc = get_refcount($function_name, ''); my $rcinfo = ''; if ($result_rc eq '+1') { $rcinfo = 'New reference'; } elsif ($result_rc eq '0') { $rcinfo = 'Borrowed reference'; } elsif ($result_rc eq 'null') { $rcinfo = 'Always NULL'; } if ($rcinfo ne '') { $rcinfo = ( "\n
" . "\n Return value:" . "\n $rcinfo." . "\n
"); } return "
$return_type $idx($arg_list)\n
" . $rcinfo . $_ . '
'; } sub do_env_csimplemacrodesc{ local($_) = @_; my $name = next_argument(); my $idx = make_str_index_entry("$name"); return "
$idx\n
" . $_ . '
' } sub do_env_ctypedesc{ local($_) = @_; my $index_name = next_optional_argument(); my $type_name = next_argument(); $index_name = $type_name unless $index_name; my($name,$aname,$ahref) = new_link_info(); add_index_entry("$index_name (C type)", $ahref); return "
$aname$type_name\n
" . $_ . '
' } sub do_env_cvardesc{ local($_) = @_; my $var_type = next_argument(); my $var_name = next_argument(); my $idx = make_str_index_entry("$var_name" . get_indexsubitem()); $idx =~ s/ \(.*\)//; return "
$var_type $idx\n" . '
' . $_ . '
'; } sub convert_args($){ local($IN_DESC_HANDLER) = 1; local($_) = @_; return translate_commands($_); } sub do_env_funcdesc{ local($_) = @_; my $function_name = next_argument(); my $arg_list = convert_args(next_argument()); my $idx = make_str_index_entry("$function_name()" . get_indexsubitem()); $idx =~ s/ \(.*\)//; $idx =~ s/\(\)<\/tt>/<\/tt>/; return "
$idx($arg_list)\n
" . $_ . '
'; } sub do_env_funcdescni{ local($_) = @_; my $function_name = next_argument(); my $arg_list = convert_args(next_argument()); return "
$function_name" . "($arg_list)\n" . '
' . $_ . '
'; } sub do_cmd_funcline{ local($_) = @_; my $function_name = next_argument(); my $arg_list = convert_args(next_argument()); my $prefix = "$function_name()"; my $idx = make_str_index_entry($prefix . get_indexsubitem()); $prefix =~ s/\(\)//; return "
$prefix($arg_list)\n
" . $_; } sub do_cmd_funclineni{ local($_) = @_; my $function_name = next_argument(); my $arg_list = convert_args(next_argument()); my $prefix = "$function_name"; return "
$prefix($arg_list)\n
" . $_; } # Change this flag to index the opcode entries. I don't think it's very # useful to index them, since they're only presented to describe the dis # module. # $INDEX_OPCODES = 0; sub do_env_opcodedesc{ local($_) = @_; my $opcode_name = next_argument(); my $arg_list = next_argument(); my $idx; if ($INDEX_OPCODES) { $idx = make_str_index_entry("$opcode_name" . " (byte code instruction)"); $idx =~ s/ \(byte code instruction\)//; } else { $idx = "$opcode_name"; } my $stuff = "
$idx"; if ($arg_list) { $stuff .= "    $arg_list"; } return $stuff . "\n
" . $_ . '
'; } sub do_env_datadesc{ local($_) = @_; my $dataname = next_argument(); my $idx = make_str_index_entry("$dataname" . get_indexsubitem()); $idx =~ s/ \(.*\)//; return "
$idx\n
" . $_ . '
'; } sub do_env_datadescni{ local($_) = @_; my $idx = next_argument(); if (! $STRING_INDEX_TT) { $idx = "$idx"; } return "
$idx\n
" . $_ . '
'; } sub do_cmd_dataline{ local($_) = @_; my $data_name = next_argument(); my $idx = make_str_index_entry("$data_name" . get_indexsubitem()); $idx =~ s/ \(.*\)//; return "
$idx
" . $_; } sub do_cmd_datalineni{ local($_) = @_; my $data_name = next_argument(); return "
$data_name
" . $_; } sub do_env_excdesc{ local($_) = @_; my $excname = next_argument(); my $idx = make_str_index_entry("$excname"); return "
exception $idx\n
" . $_ . '
' } sub do_env_fulllineitems{ return do_env_itemize(@_); } sub handle_classlike_descriptor{ local($_, $what) = @_; $THIS_CLASS = next_argument(); my $arg_list = convert_args(next_argument()); $idx = make_str_index_entry( "$THIS_CLASS ($what in $THIS_MODULE)" ); $idx =~ s/ \(.*\)//; return ("
$what $idx($arg_list)\n
" . $_ . '
'); } sub do_env_classdesc{ return handle_classlike_descriptor(@_[0], "class"); } sub do_env_excclassdesc{ return handle_classlike_descriptor(@_[0], "exception"); } sub do_env_methoddesc{ local($_) = @_; my $class_name = next_optional_argument(); $class_name = $THIS_CLASS unless $class_name; my $method = next_argument(); my $arg_list = convert_args(next_argument()); my $extra = ''; if ($class_name) { $extra = " ($class_name method)"; } my $idx = make_str_index_entry("$method()$extra"); $idx =~ s/ \(.*\)//; $idx =~ s/\(\)//; return "
$idx($arg_list)\n
" . $_ . '
'; } sub do_cmd_methodline{ local($_) = @_; my $class_name = next_optional_argument(); $class_name = $THIS_CLASS unless $class_name; my $method = next_argument(); my $arg_list = convert_args(next_argument()); my $extra = ''; if ($class_name) { $extra = " ($class_name method)"; } my $idx = make_str_index_entry("$method()$extra"); $idx =~ s/ \(.*\)//; $idx =~ s/\(\)//; return "
$idx($arg_list)\n
" . $_; } sub do_cmd_methodlineni{ local($_) = @_; next_optional_argument(); my $method = next_argument(); my $arg_list = convert_args(next_argument()); return "
$method($arg_list)\n
" . $_; } sub do_env_methoddescni{ local($_) = @_; next_optional_argument(); my $method = next_argument(); my $arg_list = convert_args(next_argument()); return "
$method($arg_list)\n
" . $_ . '
'; } sub do_env_memberdesc{ local($_) = @_; my $class = next_optional_argument(); my $member = next_argument(); $class = $THIS_CLASS unless $class; my $extra = ''; $extra = " ($class attribute)" if ($class ne ''); my $idx = make_str_index_entry("$member$extra"); $idx =~ s/ \(.*\)//; $idx =~ s/\(\)//; return "
$idx\n
" . $_ . '
'; } sub do_cmd_memberline{ local($_) = @_; my $class = next_optional_argument(); my $member = next_argument(); $class = $THIS_CLASS unless $class; my $extra = ''; $extra = " ($class attribute)" if ($class ne ''); my $idx = make_str_index_entry("$member$extra"); $idx =~ s/ \(.*\)//; $idx =~ s/\(\)//; return "
$idx
" . $_; } sub do_env_memberdescni{ local($_) = @_; next_optional_argument(); my $member = next_argument(); return "
$member\n
" . $_ . '
'; } sub do_cmd_memberlineni{ local($_) = @_; next_optional_argument(); my $member = next_argument(); return "
$member
" . $_; } @col_aligns = ('', '', '', ''); sub fix_font{ # do a little magic on a font name to get the right behavior in the first # column of the output table my $font = @_[0]; if ($font eq 'textrm') { $font = ''; } elsif ($font eq 'file' || $font eq 'filenq') { $font = 'tt class="file"'; } elsif ($font eq 'member') { $font = 'tt class="member"'; } elsif ($font eq 'class') { $font = 'tt class="class"'; } elsif ($font eq 'constant') { $font = 'tt class="constant"'; } elsif ($font eq 'kbd') { $font = 'kbd'; } elsif ($font eq 'programopt') { $font = 'b'; } elsif ($font eq 'exception') { $font = 'tt class="exception"'; } return $font; } sub figure_column_alignment{ my $a = @_[0]; my $mark = substr($a, 0, 1); my $r = ''; if ($mark eq 'c') { $r = ' align="center"'; } elsif ($mark eq 'r') { $r = ' align="right"'; } elsif ($mark eq 'l') { $r = ' align="left"'; } elsif ($mark eq 'p') { $r = ' align="left"'; } return $r; } sub setup_column_alignments{ local($_) = @_; my($s1,$s2,$s3,$s4) = split(/[|]/,$_); my $a1 = figure_column_alignment($s1); my $a2 = figure_column_alignment($s2); my $a3 = figure_column_alignment($s3); my $a4 = figure_column_alignment($s4); $col_aligns[0] = ""; $col_aligns[1] = ""; $col_aligns[2] = ""; $col_aligns[3] = ""; # return the aligned header start tags return ("", "", "", ""); } sub get_table_col1_fonts{ my $font = $globals{'lineifont'}; my ($sfont,$efont) = ('', ''); if ($font) { $sfont = "<$font>"; $efont = ""; $efont =~ s/ .*>/>/; } return ($sfont, $efont); } sub do_env_tableii{ local($_) = @_; my($th1,$th2,$th3,$th4) = setup_column_alignments(next_argument()); my $font = fix_font(next_argument()); my $h1 = next_argument(); my $h2 = next_argument(); s/[\s\n]+//; $globals{'lineifont'} = $font; my $a1 = $col_aligns[0]; my $a2 = $col_aligns[1]; s/\\lineii' . "\n " . "\n " . "\n $th1$h1\ " . "\n $th2$h2\ " . "\n " . "\n " . "\n " . $_ . "\n " . "\n"; } sub do_env_longtableii{ return do_env_tableii(@_); } sub do_cmd_lineii{ local($_) = @_; my $aligns = next_optional_argument(); my $c1 = next_argument(); my $c2 = next_argument(); s/[\s\n]+//; my($sfont,$efont) = get_table_col1_fonts(); $c2 = ' ' if ($c2 eq ''); my($c1align,$c2align) = split('\|', $aligns); my $padding = ''; if ($c1align =~ /align="right"/ || $c1 eq '') { $padding = ' '; } return "\n $c1align$sfont$c1$efont$padding\n" . " $c2align$c2" . $_; } sub do_env_tableiii{ local($_) = @_; my($th1,$th2,$th3,$th4) = setup_column_alignments(next_argument()); my $font = fix_font(next_argument()); my $h1 = next_argument(); my $h2 = next_argument(); my $h3 = next_argument(); s/[\s\n]+//; $globals{'lineifont'} = $font; my $a1 = $col_aligns[0]; my $a2 = $col_aligns[1]; my $a3 = $col_aligns[2]; s/\\lineiii' . "\n " . "\n " . "\n $th1$h1\ " . "\n $th2$h2\ " . "\n $th3$h3\ " . "\n " . "\n " . "\n " . $_ . "\n " . "\n"; } sub do_env_longtableiii{ return do_env_tableiii(@_); } sub do_cmd_lineiii{ local($_) = @_; my $aligns = next_optional_argument(); my $c1 = next_argument(); my $c2 = next_argument(); my $c3 = next_argument(); s/[\s\n]+//; my($sfont,$efont) = get_table_col1_fonts(); $c3 = ' ' if ($c3 eq ''); my($c1align,$c2align,$c3align) = split('\|', $aligns); my $padding = ''; if ($c1align =~ /align="right"/ || $c1 eq '') { $padding = ' '; } return "\n $c1align$sfont$c1$efont$padding\n" . " $c2align$c2\n" . " $c3align$c3" . $_; } sub do_env_tableiv{ local($_) = @_; my($th1,$th2,$th3,$th4) = setup_column_alignments(next_argument()); my $font = fix_font(next_argument()); my $h1 = next_argument(); my $h2 = next_argument(); my $h3 = next_argument(); my $h4 = next_argument(); s/[\s\n]+//; $globals{'lineifont'} = $font; my $a1 = $col_aligns[0]; my $a2 = $col_aligns[1]; my $a3 = $col_aligns[2]; my $a4 = $col_aligns[3]; s/\\lineiv' . "\n " . "\n " . "\n $th1$h1\ " . "\n $th2$h2\ " . "\n $th3$h3\ " . "\n $th4$h4\ " . "\n " . "\n " . "\n " . $_ . "\n " . "\n"; } sub do_env_longtableiv{ return do_env_tableiv(@_); } sub do_cmd_lineiv{ local($_) = @_; my $aligns = next_optional_argument(); my $c1 = next_argument(); my $c2 = next_argument(); my $c3 = next_argument(); my $c4 = next_argument(); s/[\s\n]+//; my($sfont,$efont) = get_table_col1_fonts(); $c4 = ' ' if ($c4 eq ''); my($c1align,$c2align,$c3align,$c4align) = split('\|', $aligns); my $padding = ''; if ($c1align =~ /align="right"/ || $c1 eq '') { $padding = ' '; } return "\n $c1align$sfont$c1$efont$padding\n" . " $c2align$c2\n" . " $c3align$c3\n" . " $c4align$c4" . $_; } # These can be used to control the title page appearance; # they need a little bit of documentation. # # If $TITLE_PAGE_GRAPHIC is set, it should be the name of a file in the # $ICONSERVER directory, or include path information (other than "./"). The # default image type will be assumed if an extension is not provided. # # If specified, the "title page" will contain two colums: one containing the # title/author/etc., and the other containing the graphic. Use the other # four variables listed here to control specific details of the layout; all # are optional. # # $TITLE_PAGE_GRAPHIC = "my-company-logo"; # $TITLE_PAGE_GRAPHIC_COLWIDTH = "30%"; # $TITLE_PAGE_GRAPHIC_WIDTH = 150; # $TITLE_PAGE_GRAPHIC_HEIGHT = 150; # $TITLE_PAGE_GRAPHIC_ON_RIGHT = 0; sub make_my_titlepage() { my $the_title = ""; if ($t_title) { $the_title .= "\n

$t_title

"; } else { write_warnings("\nThis document has no title."); } if ($t_author) { if ($t_authorURL) { my $href = translate_commands($t_authorURL); $href = make_named_href('author', $href, "$t_author"); $the_title .= "\n

$href

"; } else { $the_title .= ("\n

$t_author

"); } } else { write_warnings("\nThere is no author for this document."); } if ($t_institute) { $the_title .= "\n

$t_institute

"; } if ($DEVELOPER_ADDRESS) { $the_title .= "\n

$DEVELOPER_ADDRESS

"; } if ($t_affil) { $the_title .= "\n

$t_affil

"; } if ($t_date) { $the_title .= "\n

"; if ($PACKAGE_VERSION) { $the_title .= "Release $PACKAGE_VERSION
\n"; } $the_title .= "$t_date

" } if ($t_address) { $the_title .= "\n

$t_address

"; } else { $the_title .= "\n

"; } if ($t_email) { $the_title .= "\n

$t_email

"; } return $the_title; } sub make_my_titlegraphic() { my $filename = make_icon_filename($TITLE_PAGE_GRAPHIC); my $graphic = "\n"; return $graphic; } sub do_cmd_maketitle { local($_) = @_; my $the_title = "\n
"; if ($TITLE_PAGE_GRAPHIC) { if ($TITLE_PAGE_GRAPHIC_ON_RIGHT) { $the_title .= ("\n" . "\n\n" . make_my_titlegraphic() . "\n
" . make_my_titlepage() . "
"); } else { $the_title .= ("\n\n" . make_my_titlegraphic() . "\n
" . make_my_titlepage() . "
"); } } else { $the_title .= ("\n
" . make_my_titlepage() . "\n
"); } $the_title .= "\n
"; return $the_title . $_; $the_title .= "\n"; return $the_title . $_ ; } # # Module synopsis support # require SynopsisTable; sub get_chapter_id(){ my $id = do_cmd_thechapter(''); $id =~ s/(\d+)<\/SPAN>/\1/; $id =~ s/\.//; return $id; } # 'chapter' => 'SynopsisTable instance' %ModuleSynopses = (); sub get_synopsis_table($){ my($chap) = @_; my $key; foreach $key (keys %ModuleSynopses) { if ($key eq $chap) { return $ModuleSynopses{$chap}; } } my $st = SynopsisTable->new(); $ModuleSynopses{$chap} = $st; return $st; } sub do_cmd_moduleauthor{ local($_) = @_; next_argument(); next_argument(); return $_; } sub do_cmd_sectionauthor{ local($_) = @_; next_argument(); next_argument(); return $_; } sub do_cmd_declaremodule{ local($_) = @_; my $key = next_optional_argument(); my $type = next_argument(); my $name = next_argument(); my $st = get_synopsis_table(get_chapter_id()); # $key = $name unless $key; $type = 'built-in' if $type eq 'builtin'; $st->declare($name, $key, $type); define_module($type, $name); return anchor_label("module-$key",$CURRENT_FILE,$_) } sub do_cmd_modulesynopsis{ local($_) = @_; my $st = get_synopsis_table(get_chapter_id()); $st->set_synopsis($THIS_MODULE, translate_commands(next_argument())); return $_; } sub do_cmd_localmoduletable{ local($_) = @_; my $chap = get_chapter_id(); my $st = get_synopsis_table($chap); $st->set_file("$CURRENT_FILE"); return "<$chap>\\tableofchildlinks[off]" . $_; } sub process_all_localmoduletables{ my $key; my $st, $file; foreach $key (keys %ModuleSynopses) { $st = $ModuleSynopses{$key}; $file = $st->get_file(); if ($file) { process_localmoduletables_in_file($file); } else { print "\nsynopsis table $key has no file association"; } } } sub process_localmoduletables_in_file{ my $file = @_[0]; open(MYFILE, "<$file"); local($_); sysread(MYFILE, $_, 1024*1024); close(MYFILE); # need to get contents of file in $_ while (/<(\d+)>/) { my $match = $&; my $chap = $1; my $st = get_synopsis_table($chap); my $data = $st->tohtml(); s/$match/$data/; } open(MYFILE,">$file"); print MYFILE $_; close(MYFILE); } sub process_python_state{ process_all_localmoduletables(); } # # "See also:" -- references placed at the end of a \section # sub do_env_seealso{ return "
\n " . "

See Also:

\n" . @_[0] . '
'; } sub do_cmd_seemodule{ # Insert the right magic to jump to the module definition. This should # work most of the time, at least for repeat builds.... local($_) = @_; my $key = next_optional_argument(); my $module = next_argument(); my $text = next_argument(); my $period = '.'; $key = $module unless $key; if ($text =~ /\.$/) { $period = ''; } return '
' . "\n
Module " . "$module:" . "\n
$text$period\n
" . $_; } sub strip_html_markup($){ my $str = @_[0]; my $s = "$str"; $s =~ s/<[a-zA-Z0-9]+(\s+[a-zA-Z0-9]+(\s*=\s*(\'[^\']*\'|\"[^\"]*\"|[a-zA-Z0-9]+))?)*\s*>//g; $s =~ s/<\/[a-zA-Z0-9]+>//g; return $s; } sub handle_rfclike_reference{ local($_, $what, $format) = @_; my $rfcnum = next_argument(); my $title = next_argument(); my $text = next_argument(); my $url = get_rfc_url($rfcnum, $format); my $icon = get_link_icon($url); my $attrtitle = strip_html_markup($title); return '
' . "\n
$what $rfcnum, $title$icon" . "\n
$text\n
" . $_; } sub do_cmd_seepep{ return handle_rfclike_reference(@_[0], "PEP", $PEP_FORMAT); } sub do_cmd_seerfc{ return handle_rfclike_reference(@_[0], "RFC", $RFC_FORMAT); } sub do_cmd_seetitle{ local($_) = @_; my $url = next_optional_argument(); my $title = next_argument(); my $text = next_argument(); if ($url) { my $icon = get_link_icon($url); return '
' . "\n
$title$icon" . "\n
$text\n
" . $_; } return '
' . "\n
$title" . "\n
$text\n
" . $_; } sub do_cmd_seeurl{ local($_) = @_; my $url = next_argument(); my $text = next_argument(); my $icon = get_link_icon($url); return '
' . "\n
$url$icon" . "\n
$text\n
" . $_; } sub do_cmd_seetext{ local($_) = @_; my $content = next_argument(); return '

' . $content . '

' . $_; } # # Definition list support. # sub do_env_definitions{ return "
" . @_[0] . "
\n"; } sub do_cmd_term{ local($_) = @_; my $term = next_argument(); my($name,$aname,$ahref) = new_link_info(); # could easily add an index entry here... return "
$aname" . $term . "\n
" . $_; } # I don't recall exactly why this was needed, but it was very much needed. # We'll see if anything breaks when I move the "code" line out -- some # things broke with it in. #code # {} process_commands_wrap_deferred(<<_RAW_ARG_DEFERRED_CMDS_); declaremodule # [] # {} # {} memberline # [] # {} methodline # [] # {} # {} modulesynopsis # {} platform # {} samp # {} setindexsubitem # {} withsubitem # {} # {} _RAW_ARG_DEFERRED_CMDS_ $alltt_start = '
';
$alltt_end = '
'; sub do_env_alltt { local ($_) = @_; local($closures,$reopens,@open_block_tags); # get the tag-strings for all open tags local(@keep_open_tags) = @$open_tags_R; ($closures,$reopens) = &preserve_open_tags() if (@$open_tags_R); # get the tags for text-level tags only $open_tags_R = [ @keep_open_tags ]; local($local_closures, $local_reopens); ($local_closures, $local_reopens,@open_block_tags) = &preserve_open_block_tags if (@$open_tags_R); $open_tags_R = [ @open_block_tags ]; do { local($open_tags_R) = [ @open_block_tags ]; local(@save_open_tags) = (); local($cnt) = ++$global{'max_id'}; $_ = join('',"$O$cnt$C\\tt$O", ++$global{'max_id'}, $C , $_ , $O, $global{'max_id'}, "$C$O$cnt$C"); $_ = &translate_environments($_); $_ = &translate_commands($_) if (/\\/); # preserve space-runs, using   while (s/(\S) ( +)/$1$2;SPMnbsp;/g){}; s/(
) /$1;SPMnbsp;/g; $_ = join('', $closures, $alltt_start, $local_reopens , $_ , &balance_tags() #, $local_closures , $alltt_end, $reopens); undef $open_tags_R; undef @save_open_tags; }; $open_tags_R = [ @keep_open_tags ]; $_; } 1; # This must be the last line pyOpenSSL-0.13/doc/tools/sgmlconv/0000755000214500021450000000000011630175113016772 5ustar bb-slavebb-slavepyOpenSSL-0.13/doc/tools/sgmlconv/Makefile0000644000214500021450000000232711630175105020437 0ustar bb-slavebb-slave# Simple makefile to control XML generation for the entire document tree. # This should be used from the top-level directory (Doc/), not the directory # that actually contains this file: # # $ pwd # .../Doc # $ make -f tools/sgmlconv/Makefile TOPDIR=. TOOLSDIR=tools SGMLRULES=../$(TOOLSDIR)/sgmlconv/make.rules # The 'inst' directory breaks the conversion, so skip it for now. SUBDIRS=api dist ext lib mac ref tut SUBMAKE=$(MAKE) -f $(SGMLRULES) TOOLSDIR=../$(TOOLSDIR) all: xml .PHONY: esis xml .PHONY: $(SUBDIRS) xml: for DIR in $(SUBDIRS) ; do \ (cd $$DIR; $(SUBMAKE) xml) || exit $$? ; done esis: for DIR in $(SUBDIRS) ; do \ (cd $$DIR; $(SUBMAKE) esis) || exit $$? ; done esis1: for DIR in $(SUBDIRS) ; do \ (cd $$DIR; $(SUBMAKE) esis1) || exit $$? ; done tarball: xml tar cf - tools/sgmlconv */*.xml | gzip -9 >xml-1.5.2b2.tgz api: cd api; $(SUBMAKE) dist: cd dist; $(SUBMAKE) ext: cd ext; $(SUBMAKE) inst: cd inst; $(SUBMAKE) lib: cd lib; $(SUBMAKE) mac: cd mac; $(SUBMAKE) ref: cd ref; $(SUBMAKE) tut: cd tut; $(SUBMAKE) clean: for DIR in $(SUBDIRS) ; do \ (cd $$DIR; $(SUBMAKE) clean) ; done clobber: for DIR in $(SUBDIRS) ; do \ (cd $$DIR; $(SUBMAKE) clobber) ; done pyOpenSSL-0.13/doc/tools/sgmlconv/README0000644000214500021450000000453211630175105017657 0ustar bb-slavebb-slaveThese scripts and Makefile fragment are used to convert the Python documentation in LaTeX format to XML. This material is preliminary and incomplete. Python 2.0 is required. To convert all documents to XML: cd Doc/ make -f tools/sgmlconv/Makefile To convert one document to XML: cd Doc/ make -f ../tools/sgmlconv/make.rules TOOLSDIR=../tools Please send comments and bug reports to python-docs@python.org. What do the tools do? --------------------- latex2esis.py Reads in a conversion specification written in XML (conversion.xml), reads a LaTeX document fragment, and interprets the markup according to the specification. The output is a stream of ESIS events like those created by the nsgmls SGML parser, but is *not* guaranteed to represent a single tree! This is done to allow conversion per entity rather than per document. Since many of the LaTeX files for the Python documentation contain two sections on closely related modules, it is important to allow both of the resulting
elements to exist in the same output stream. Additionally, since comments are not supported in ESIS, comments are converted to elements, which might exist at the same level as the top-level content elements. The output of latex2esis.py gets saved as .esis1. docfixer.py This is the really painful part of the conversion. Well, it's the second really painful part, but more of the pain is specific to the structure of the Python documentation and desired output rather than to the parsing of LaTeX markup. This script loads the ESIS data created by latex2esis.py into a DOM document *fragment* (remember, the latex2esis.py output may not be well-formed). Once loaded, it walks over the tree many times looking for a variety of possible specific micro-conversions. Most of the code is not in any way "general". After processing the fragment, a new ESIS data stream is written out. Like the input, it may not represent a well-formed document, but does represent a parsed entity. The output of docfixer.py is what gets saved in .esis. esis2sgml.py Reads an ESIS stream and convert to SGML or XML. This also converts elements to real comments. This works quickly because there's not much to actually do. pyOpenSSL-0.13/doc/tools/sgmlconv/conversion.xml0000644000214500021450000004607411630175105021715 0ustar bb-slavebb-slave yes no no no no no tt no no no no no no visible 2 2 3 3 4 4 C++ LaTeX ... TeX no ABC ASCII C EOF \ NULL POSIX Unix ~ pyOpenSSL-0.13/doc/tools/sgmlconv/docfixer.py0000755000214500021450000010524711630175105021164 0ustar bb-slavebb-slave#! /usr/bin/env python """Perform massive transformations on a document tree created from the LaTeX of the Python documentation, and dump the ESIS data for the transformed tree. """ import errno import esistools import re import string import sys import xml.dom import xml.dom.minidom ELEMENT = xml.dom.Node.ELEMENT_NODE ENTITY_REFERENCE = xml.dom.Node.ENTITY_REFERENCE_NODE TEXT = xml.dom.Node.TEXT_NODE class ConversionError(Exception): pass ewrite = sys.stderr.write try: # We can only do this trick on Unix (if tput is on $PATH)! if sys.platform != "posix" or not sys.stderr.isatty(): raise ImportError import commands except ImportError: bwrite = ewrite else: def bwrite(s, BOLDON=commands.getoutput("tput bold"), BOLDOFF=commands.getoutput("tput sgr0")): ewrite("%s%s%s" % (BOLDON, s, BOLDOFF)) PARA_ELEMENT = "para" DEBUG_PARA_FIXER = 0 if DEBUG_PARA_FIXER: def para_msg(s): ewrite("*** %s\n" % s) else: def para_msg(s): pass def get_first_element(doc, gi): for n in doc.childNodes: if n.nodeName == gi: return n def extract_first_element(doc, gi): node = get_first_element(doc, gi) if node is not None: doc.removeChild(node) return node def get_documentElement(node): result = None for child in node.childNodes: if child.nodeType == ELEMENT: result = child return result def set_tagName(elem, gi): elem.nodeName = elem.tagName = gi def find_all_elements(doc, gi): nodes = [] if doc.nodeName == gi: nodes.append(doc) for child in doc.childNodes: if child.nodeType == ELEMENT: if child.tagName == gi: nodes.append(child) for node in child.getElementsByTagName(gi): nodes.append(node) return nodes def find_all_child_elements(doc, gi): nodes = [] for child in doc.childNodes: if child.nodeName == gi: nodes.append(child) return nodes def find_all_elements_from_set(doc, gi_set): return __find_all_elements_from_set(doc, gi_set, []) def __find_all_elements_from_set(doc, gi_set, nodes): if doc.nodeName in gi_set: nodes.append(doc) for child in doc.childNodes: if child.nodeType == ELEMENT: __find_all_elements_from_set(child, gi_set, nodes) return nodes def simplify(doc, fragment): # Try to rationalize the document a bit, since these things are simply # not valid SGML/XML documents as they stand, and need a little work. documentclass = "document" inputs = [] node = extract_first_element(fragment, "documentclass") if node is not None: documentclass = node.getAttribute("classname") node = extract_first_element(fragment, "title") if node is not None: inputs.append(node) # update the name of the root element node = get_first_element(fragment, "document") if node is not None: set_tagName(node, documentclass) while 1: node = extract_first_element(fragment, "input") if node is None: break inputs.append(node) if inputs: docelem = get_documentElement(fragment) inputs.reverse() for node in inputs: text = doc.createTextNode("\n") docelem.insertBefore(text, docelem.firstChild) docelem.insertBefore(node, text) docelem.insertBefore(doc.createTextNode("\n"), docelem.firstChild) while fragment.firstChild and fragment.firstChild.nodeType == TEXT: fragment.removeChild(fragment.firstChild) def cleanup_root_text(doc): discards = [] skip = 0 for n in doc.childNodes: prevskip = skip skip = 0 if n.nodeType == TEXT and not prevskip: discards.append(n) elif n.nodeName == "COMMENT": skip = 1 for node in discards: doc.removeChild(node) DESCRIPTOR_ELEMENTS = ( "cfuncdesc", "cvardesc", "ctypedesc", "classdesc", "memberdesc", "memberdescni", "methoddesc", "methoddescni", "excdesc", "funcdesc", "funcdescni", "opcodedesc", "datadesc", "datadescni", ) def fixup_descriptors(doc, fragment): sections = find_all_elements(fragment, "section") for section in sections: find_and_fix_descriptors(doc, section) def find_and_fix_descriptors(doc, container): children = container.childNodes for child in children: if child.nodeType == ELEMENT: tagName = child.tagName if tagName in DESCRIPTOR_ELEMENTS: rewrite_descriptor(doc, child) elif tagName == "subsection": find_and_fix_descriptors(doc, child) def rewrite_descriptor(doc, descriptor): # # Do these things: # 1. Add an "index='no'" attribute to the element if the tagName # ends in 'ni', removing the 'ni' from the name. # 2. Create a from the name attribute # 2a.Create an if it appears to be available. # 3. Create additional s from <*line{,ni}> elements, # if found. # 4. If a is found, move it to an attribute on the # descriptor. # 5. Move remaining child nodes to a element. # 6. Put it back together. # # 1. descname = descriptor.tagName index = 1 if descname[-2:] == "ni": descname = descname[:-2] descriptor.setAttribute("index", "no") set_tagName(descriptor, descname) index = 0 desctype = descname[:-4] # remove 'desc' linename = desctype + "line" if not index: linename = linename + "ni" # 2. signature = doc.createElement("signature") name = doc.createElement("name") signature.appendChild(doc.createTextNode("\n ")) signature.appendChild(name) name.appendChild(doc.createTextNode(descriptor.getAttribute("name"))) descriptor.removeAttribute("name") # 2a. if descriptor.hasAttribute("var"): if descname != "opcodedesc": raise RuntimeError, \ "got 'var' attribute on descriptor other than opcodedesc" variable = descriptor.getAttribute("var") if variable: args = doc.createElement("args") args.appendChild(doc.createTextNode(variable)) signature.appendChild(doc.createTextNode("\n ")) signature.appendChild(args) descriptor.removeAttribute("var") newchildren = [signature] children = descriptor.childNodes pos = skip_leading_nodes(children) if pos < len(children): child = children[pos] if child.nodeName == "args": # move to , or remove if empty: child.parentNode.removeChild(child) if len(child.childNodes): signature.appendChild(doc.createTextNode("\n ")) signature.appendChild(child) signature.appendChild(doc.createTextNode("\n ")) # 3, 4. pos = skip_leading_nodes(children, pos) while pos < len(children) \ and children[pos].nodeName in (linename, "versionadded"): if children[pos].tagName == linename: # this is really a supplemental signature, create oldchild = children[pos].cloneNode(1) try: sig = methodline_to_signature(doc, children[pos]) except KeyError: print oldchild.toxml() raise newchildren.append(sig) else: # descriptor.setAttribute( "added", children[pos].getAttribute("version")) pos = skip_leading_nodes(children, pos + 1) # 5. description = doc.createElement("description") description.appendChild(doc.createTextNode("\n")) newchildren.append(description) move_children(descriptor, description, pos) last = description.childNodes[-1] if last.nodeType == TEXT: last.data = string.rstrip(last.data) + "\n " # 6. # should have nothing but whitespace and signature lines in ; # discard them while descriptor.childNodes: descriptor.removeChild(descriptor.childNodes[0]) for node in newchildren: descriptor.appendChild(doc.createTextNode("\n ")) descriptor.appendChild(node) descriptor.appendChild(doc.createTextNode("\n")) def methodline_to_signature(doc, methodline): signature = doc.createElement("signature") signature.appendChild(doc.createTextNode("\n ")) name = doc.createElement("name") name.appendChild(doc.createTextNode(methodline.getAttribute("name"))) methodline.removeAttribute("name") signature.appendChild(name) if len(methodline.childNodes): args = doc.createElement("args") signature.appendChild(doc.createTextNode("\n ")) signature.appendChild(args) move_children(methodline, args) signature.appendChild(doc.createTextNode("\n ")) return signature def move_children(origin, dest, start=0): children = origin.childNodes while start < len(children): node = children[start] origin.removeChild(node) dest.appendChild(node) def handle_appendix(doc, fragment): # must be called after simplfy() if document is multi-rooted to begin with docelem = get_documentElement(fragment) toplevel = docelem.tagName == "manual" and "chapter" or "section" appendices = 0 nodes = [] for node in docelem.childNodes: if appendices: nodes.append(node) elif node.nodeType == ELEMENT: appnodes = node.getElementsByTagName("appendix") if appnodes: appendices = 1 parent = appnodes[0].parentNode parent.removeChild(appnodes[0]) parent.normalize() if nodes: map(docelem.removeChild, nodes) docelem.appendChild(doc.createTextNode("\n\n\n")) back = doc.createElement("back-matter") docelem.appendChild(back) back.appendChild(doc.createTextNode("\n")) while nodes and nodes[0].nodeType == TEXT \ and not string.strip(nodes[0].data): del nodes[0] map(back.appendChild, nodes) docelem.appendChild(doc.createTextNode("\n")) def handle_labels(doc, fragment): for label in find_all_elements(fragment, "label"): id = label.getAttribute("id") if not id: continue parent = label.parentNode parentTagName = parent.tagName if parentTagName == "title": parent.parentNode.setAttribute("id", id) else: parent.setAttribute("id", id) # now, remove