blob: b1c9488bd56f067bf3956ba76394654698a246f4 [file] [log] [blame]
/*
* 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 <Python.h>
#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 {
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_setattr(crypto_X509NameObj *self, char *name, PyObject *value)
{
int nid;
int result;
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;
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 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, "<X509Name object '%s'>", 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;
}