blob: 148c69d9d4a20741d3df69e805693a37e2361a3d [file] [log] [blame]
Radek Krejcic61f0b42017-06-07 13:21:41 +02001/**
2 * @file tls.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief TLS parameters management
5 *
6 * Copyright (c) 2017 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
15/* Python API header */
16#include <Python.h>
17#include <structmember.h>
18
19/* standard headers */
20#include <string.h>
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <unistd.h>
24
25#include "netconf.h"
26
27static void
28ncTLSFree(ncTLSObject *self)
29{
30 Py_XDECREF(self->cert_file);
31 Py_XDECREF(self->key_file);
32 Py_XDECREF(self->ca_file);
33 Py_XDECREF(self->ca_dir);
34 Py_XDECREF(self->crl_file);
35 Py_XDECREF(self->crl_dir);
36
37 Py_TYPE(self)->tp_free((PyObject*)self);
38}
39
40static int
41ncTLSInit(ncTLSObject *self, PyObject *args, PyObject *kwds)
42{
43 char *kwlist[] = {"cert_file", "key_file", "ca_file", "ca_dir", "crl_file", "crl_dir", NULL};
44
45 /* Get input parameters */
46 if (!PyArg_ParseTupleAndKeywords(args, kwds, "UU|UUUU", kwlist,
47 &self->cert_file, &self->key_file,
48 &self->ca_file, &self->ca_dir,
49 &self->crl_file, &self->crl_dir)) {
50 return -1;
51 }
52
53 return 0;
54}
55
56static PyObject *
57ncTLSStr(ncTLSObject *self)
58{
59 return PyUnicode_FromFormat("TLS Settings with certificate \"%U\" and the key \"%U\".",
60 self->cert_file, self->key_file);
61}
62
63/*
64 * tp_getset callbacs held by ncTLSGetSetters[]
65 */
66static int
67ncTLSSetCert(ncTLSObject *self, PyObject *value, void *closure)
68{
Michal Vaskoe3db4322020-04-23 11:58:51 +020069 const char *path;
Radek Krejcic61f0b42017-06-07 13:21:41 +020070 struct stat st;
71
72 if (!value) {
73 PyErr_SetString(PyExc_TypeError, "Client certificate path cannot be unset.");
74 return -1;
75 } else if (!PyUnicode_Check(value)) {
76 PyErr_SetString(PyExc_TypeError, "The certificate path value must be a string.");
77 return -1;
78 }
79
80 path = PyUnicode_AsUTF8(value);
81 if (!path) {
82 return -1;
83 }
84
85 if (stat(path, &st)) {
86 PyErr_SetFromErrno(PyExc_SystemError);
87 return -1;
88 }
89
90 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
91 PyErr_SetString(PyExc_FileNotFoundError, "Certificate file cannot be used.");
92 return -1;
93 }
94
95 Py_XDECREF(self->cert_file);
96 Py_INCREF(value);
97 self->cert_file = value;
98
99 return 0;
100}
101
102static PyObject *
103ncTLSGetCert(ncTLSObject *self, void *closure)
104{
105 Py_XINCREF(self->cert_file);
106 return self->cert_file;
107}
108
109static int
110ncTLSSetKey(ncTLSObject *self, PyObject *value, void *closure)
111{
Michal Vaskoe3db4322020-04-23 11:58:51 +0200112 const char *path;
Radek Krejcic61f0b42017-06-07 13:21:41 +0200113 struct stat st;
114
115 if (!value) {
116 PyErr_SetString(PyExc_TypeError, "Client certificate key path cannot be unset.");
117 return -1;
118 } else if (!PyUnicode_Check(value)) {
119 PyErr_SetString(PyExc_TypeError, "The certificate key path value must be a string.");
120 return -1;
121 }
122
123 path = PyUnicode_AsUTF8(value);
124 if (!path) {
125 return -1;
126 }
127
128 if (stat(path, &st)) {
129 PyErr_SetFromErrno(PyExc_SystemError);
130 return -1;
131 }
132
133 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
134 PyErr_SetString(PyExc_FileNotFoundError, "Certificate key file cannot be used.");
135 return -1;
136 }
137
138 Py_XDECREF(self->key_file);
139 Py_INCREF(value);
140 self->key_file = value;
141
142 return 0;
143}
144
145static PyObject *
146ncTLSGetKey(ncTLSObject *self, void *closure)
147{
148 Py_XINCREF(self->key_file);
149 return self->key_file;
150}
151
152/*
153 * Callback structures
154 */
155
156static PyGetSetDef ncTLSGetSetters[] = {
157 {"cert", (getter)ncTLSGetCert, (setter)ncTLSSetCert, "Client certificate filepath.", NULL},
158 {"key", (getter)ncTLSGetKey, (setter)ncTLSSetKey, "Client certificate private key filepath.", NULL},
159 {NULL} /* Sentinel */
160};
161
162PyDoc_STRVAR(ncTLSDoc,
Radek Krejcib03ebe42017-07-04 14:00:33 +0200163 "Settings for TLS authentication\n\n"
164 "Arguments: (cert=None, key=None, ca_file=None, ca_dir=None, crl_file=None, crl_dir=None)\n");
Radek Krejcic61f0b42017-06-07 13:21:41 +0200165
166PyTypeObject ncTLSType = {
167 PyVarObject_HEAD_INIT(NULL, 0)
168 "netconf2.TLS", /* tp_name */
169 sizeof(ncTLSObject), /* tp_basicsize */
170 0, /* tp_itemsize */
171 (destructor)ncTLSFree, /* tp_dealloc */
172 0, /* tp_print */
173 0, /* tp_getattr */
174 0, /* tp_setattr */
175 0, /* tp_reserved */
176 (reprfunc)ncTLSStr, /* tp_repr */
177 0, /* tp_as_number */
178 0, /* tp_as_sequence */
179 0, /* tp_as_mapping */
180 0, /* tp_hash */
181 0, /* tp_call */
182 (reprfunc)ncTLSStr, /* tp_str */
183 0, /* tp_getattro */
184 0, /* tp_setattro */
185 0, /* tp_as_buffer */
186 Py_TPFLAGS_DEFAULT |
187 Py_TPFLAGS_BASETYPE, /* tp_flags */
188 ncTLSDoc, /* tp_doc */
189 0, /* tp_traverse */
190 0, /* tp_clear */
191 0, /* tp_richcompare */
192 0, /* tp_weaklistoffset */
193 0, /* tp_iter */
194 0, /* tp_iternext */
195 0, /* tp_methods */
196 0, /* tp_members */
197 ncTLSGetSetters, /* tp_getset */
198 0, /* tp_base */
199 0, /* tp_dict */
200 0, /* tp_descr_get */
201 0, /* tp_descr_set */
202 0, /* tp_dictoffset */
203 (initproc)ncTLSInit, /* tp_init */
204 0, /* tp_alloc */
205 0, /* tp_new */
206};
207