/* * x509name.c * * Copyright (C) AB Strakt 2001, All rights reserved * * 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 char *CVSid = "@(#) $Id: x509name.c,v 1.16 2003/01/09 17:08:32 martin Exp $"; /* * 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; } /* * 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(); 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, utf8string, -1, -1, 0)) { exception_from_error_queue(); 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_getattr(crypto_X509NameObj *self, char *name) { int nid, len; char *utf8string; if ((nid = OBJ_txt2nid(name)) == NID_undef) { PyErr_SetString(PyExc_AttributeError, "No such attribute"); return NULL; } 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 return PyUnicode_Decode(utf8string, len, "utf-8", NULL); } /* * Set attribute * * Arguments: self - The X509Name object * name - The attribute name * value - The value to set */ static int crypto_X509Name_setattr(crypto_X509NameObj *self, char *name, PyObject *value) { int nid; char *buffer; if ((nid = OBJ_txt2nid(name)) == NID_undef) { 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; return set_name_by_nid(self->x509_name, nid, buffer); } /* * 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 int crypto_X509Name_compare(crypto_X509NameObj *n, crypto_X509NameObj *m) { return X509_NAME_cmp(n->x509_name, m->x509_name); } /* * 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(); return NULL; } else { /* This is safe because tmpbuf is max 512 characters */ sprintf(realbuf, "", tmpbuf); return PyString_FromString(realbuf); } } /* * 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); } PyTypeObject crypto_X509Name_Type = { PyObject_HEAD_INIT(NULL) 0, "X509Name", sizeof(crypto_X509NameObj), 0, (destructor)crypto_X509Name_dealloc, NULL, /* print */ (getattrfunc)crypto_X509Name_getattr, (setattrfunc)crypto_X509Name_setattr, (cmpfunc)crypto_X509Name_compare, (reprfunc)crypto_X509Name_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, NULL, /* doc */ (traverseproc)crypto_X509Name_traverse, (inquiry)crypto_X509Name_clear, }; /* * Initialize the X509Name part of the crypto module * * Arguments: dict - The crypto module dictionary * Returns: None */ int init_crypto_x509name(PyObject *dict) { crypto_X509Name_Type.ob_type = &PyType_Type; Py_INCREF(&crypto_X509Name_Type); PyDict_SetItemString(dict, "X509NameType", (PyObject *)&crypto_X509Name_Type); return 1; }