summaryrefslogtreecommitdiff
path: root/OpenSSL/crypto/x509ext.c
blob: f65fd0f8e38dc7586538e9569c8cdd08095461fc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
/*
 * 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 <Python.h>
#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 :py:data:`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: :py:data:`str`\n\
:param critical: A flag indicating whether this is a critical extension.\n\
:param value: The value of the extension.\n\
:type value: :py:data:`str`\n\
:param subject: Optional X509 cert to use as subject.\n\
:type subject: :py:class:`X509`\n\
:param issuer: Optional X509 cert to use as issuer.\n\
:type issuer: :py:class:`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;
}