Commit f4e74020 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

merged trac #381 (tsigkey class)


git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@3622 e5f2f494-b856-4b98-b285-d166d9295462
parents faa0af46 d096cf54
......@@ -81,7 +81,7 @@ libdns___la_SOURCES += rrttl.h rrttl.cc
libdns___la_SOURCES += rrtype.cc
libdns___la_SOURCES += question.h question.cc
libdns___la_SOURCES += util/sha1.h util/sha1.cc
libdns___la_SOURCES += tsig.h tsig.cc
libdns___la_SOURCES += tsigkey.h tsigkey.cc
nodist_libdns___la_SOURCES = rdataclass.cc rrclass.h rrtype.h
nodist_libdns___la_SOURCES += rrparamregistry.cc
......@@ -109,7 +109,7 @@ libdns___include_HEADERS = \
rrsetlist.h \
rrttl.h \
rrtype.h \
tsig.h
tsigkey.h
# Purposely not installing these headers:
# util/*.h: used only internally, and not actually DNS specific
# rrclass-placeholder.h
......
......@@ -24,6 +24,7 @@ EXTRA_DIST += question_python.cc
EXTRA_DIST += rrttl_python.cc
EXTRA_DIST += rdata_python.cc
EXTRA_DIST += rrtype_python.cc
EXTRA_DIST += tsigkey_python.cc
# Python prefers .so, while some OSes (specifically MacOS) use a different
# suffix for dynamic objects. -module is necessary to work this around.
......
......@@ -57,6 +57,7 @@ static PyObject* po_DNSMessageBADVERS;
#include <dns/python/rrset_python.cc> // needs Rdata, RRTTL
#include <dns/python/question_python.cc> // needs RRClass, RRType, RRTTL,
// Name
#include <dns/python/tsigkey_python.cc> // needs Name
#include <dns/python/opcode_python.cc>
#include <dns/python/rcode_python.cc>
#include <dns/python/edns_python.cc> // needs Messagerenderer, Rcode
......@@ -146,6 +147,14 @@ PyInit_pydnspp(void) {
return (NULL);
}
if (!initModulePart_TSIGKey(mod)) {
return (NULL);
}
if (!initModulePart_TSIGKeyRing(mod)) {
return (NULL);
}
return (mod);
}
......@@ -10,6 +10,7 @@ PYTESTS += rrclass_python_test.py
PYTESTS += rrset_python_test.py
PYTESTS += rrttl_python_test.py
PYTESTS += rrtype_python_test.py
PYTESTS += tsigkey_python_test.py
EXTRA_DIST = $(PYTESTS)
EXTRA_DIST += testutil.py
......
# Copyright (C) 2010 Internet Systems Consortium.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# $Id$
import unittest
from pydnspp import *
class TSIGKeyTest(unittest.TestCase):
key_name = Name('example.com')
secret = b'anotherRandomData'
def test_algorithm_names(self):
self.assertEqual(Name('hmac-md5.sig-alg.reg.int'),
TSIGKey.HMACMD5_NAME)
self.assertEqual(Name('hmac-sha1'), TSIGKey.HMACSHA1_NAME)
self.assertEqual(Name('hmac-sha256'), TSIGKey.HMACSHA256_NAME)
def test_init(self):
key = TSIGKey(self.key_name, TSIGKey.HMACMD5_NAME, self.secret)
self.assertEqual(self.key_name, key.get_key_name())
self.assertEqual(Name('hmac-md5.sig-alg.reg.int'),
key.get_algorithm_name())
self.assertEqual(self.secret, key.get_secret())
self.assertRaises(InvalidParameter, TSIGKey, self.key_name,
Name('unknown-alg'), self.secret)
self.assertEqual('hmac-sha1.',
TSIGKey(self.key_name, TSIGKey.HMACSHA1_NAME,
self.secret).get_algorithm_name().to_text())
self.assertRaises(TypeError, TSIGKey, self.key_name,
TSIGKey.HMACMD5_NAME,
'should be binary') # signature mismatch
class TSIGKeyRingTest(unittest.TestCase):
key_name = Name('example.com')
secret = b'someRandomData'
def setUp(self):
self.keyring = TSIGKeyRing()
def test_init(self):
self.assertEqual(0, self.keyring.size())
self.assertRaises(TypeError, TSIGKeyRing, 1)
self.assertRaises(TypeError, TSIGKeyRing, 'there should not be arg')
def test_add(self):
self.assertEqual(TSIGKeyRing.SUCCESS,
self.keyring.add(TSIGKey(self.key_name,
TSIGKey.HMACSHA256_NAME,
self.secret)))
self.assertEqual(1, self.keyring.size())
self.assertEqual(TSIGKeyRing.EXIST,
self.keyring.add(TSIGKey(self.key_name,
TSIGKey.HMACSHA256_NAME,
self.secret)))
self.assertEqual(TSIGKeyRing.EXIST,
self.keyring.add(TSIGKey(self.key_name,
TSIGKey.HMACSHA1_NAME,
self.secret)))
self.assertEqual(TSIGKeyRing.EXIST,
self.keyring.add(TSIGKey(Name('EXAMPLE.COM'),
TSIGKey.HMACSHA1_NAME,
self.secret)))
self.assertEqual(1, self.keyring.size())
def test_add_more(self):
self.assertEqual(TSIGKeyRing.SUCCESS,
self.keyring.add(TSIGKey(self.key_name,
TSIGKey.HMACSHA256_NAME,
self.secret)))
self.assertEqual(TSIGKeyRing.SUCCESS,
self.keyring.add(TSIGKey(Name('another.example'),
TSIGKey.HMACMD5_NAME,
self.secret)))
self.assertEqual(TSIGKeyRing.SUCCESS,
self.keyring.add(TSIGKey(Name('more.example'),
TSIGKey.HMACSHA1_NAME,
self.secret)))
self.assertEqual(3, self.keyring.size())
self.assertRaises(TypeError, self.keyring.add, 1)
self.assertRaises(TypeError, self.keyring.add, 'invalid arg')
def test_remove(self):
self.assertEqual(TSIGKeyRing.SUCCESS,
self.keyring.add(TSIGKey(self.key_name,
TSIGKey.HMACSHA256_NAME,
self.secret)))
self.assertEqual(TSIGKeyRing.SUCCESS,
self.keyring.remove(self.key_name))
self.assertEqual(TSIGKeyRing.NOTFOUND,
self.keyring.remove(self.key_name))
self.assertRaises(TypeError, self.keyring.add, 1)
self.assertRaises(TypeError, self.keyring.add, 'invalid arg')
self.assertRaises(TypeError, self.keyring.add, self.key_name, 0)
def test_remove_from_some(self):
self.assertEqual(TSIGKeyRing.SUCCESS,
self.keyring.add(TSIGKey(self.key_name,
TSIGKey.HMACSHA256_NAME,
self.secret)))
self.assertEqual(TSIGKeyRing.SUCCESS,
self.keyring.add(TSIGKey(Name('another.example'),
TSIGKey.HMACMD5_NAME,
self.secret)))
self.assertEqual(TSIGKeyRing.SUCCESS,
self.keyring.add(TSIGKey(Name('more.example'),
TSIGKey.HMACSHA1_NAME,
self.secret)))
self.assertEqual(TSIGKeyRing.SUCCESS,
self.keyring.remove(Name('another.example')))
self.assertEqual(TSIGKeyRing.NOTFOUND,
self.keyring.remove(Name('noexist.example')))
self.assertEqual(2, self.keyring.size())
def test_find(self):
self.assertEqual((TSIGKeyRing.NOTFOUND, None),
self.keyring.find(self.key_name))
self.assertEqual(TSIGKeyRing.SUCCESS,
self.keyring.add(TSIGKey(self.key_name,
TSIGKey.HMACSHA256_NAME,
self.secret)))
(code, key) = self.keyring.find(self.key_name)
self.assertEqual(TSIGKeyRing.SUCCESS, code)
self.assertEqual(self.key_name, key.get_key_name())
self.assertEqual(TSIGKey.HMACSHA256_NAME, key.get_algorithm_name())
self.assertEqual(self.secret, key.get_secret())
self.assertRaises(TypeError, self.keyring.find, 1)
self.assertRaises(TypeError, self.keyring.find, 'should be a name')
self.assertRaises(TypeError, self.keyring.find, self.key_name, 0)
def test_find_from_some(self):
self.assertEqual(TSIGKeyRing.SUCCESS,
self.keyring.add(TSIGKey(self.key_name,
TSIGKey.HMACSHA256_NAME,
self.secret)))
self.assertEqual(TSIGKeyRing.SUCCESS,
self.keyring.add(TSIGKey(Name('another.example'),
TSIGKey.HMACMD5_NAME,
self.secret)))
self.assertEqual(TSIGKeyRing.SUCCESS,
self.keyring.add(TSIGKey(Name('more.example'),
TSIGKey.HMACSHA1_NAME,
self.secret)))
(code, key) = self.keyring.find(Name('another.example'))
self.assertEqual(TSIGKeyRing.SUCCESS, code)
self.assertEqual(Name('another.example'), key.get_key_name())
self.assertEqual(TSIGKey.HMACMD5_NAME, key.get_algorithm_name())
self.assertEqual((TSIGKeyRing.NOTFOUND, None),
self.keyring.find(Name('noexist.example')))
if __name__ == '__main__':
unittest.main()
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
// $Id$
#include <new>
#include <dns/tsigkey.h>
using namespace isc::dns;
using namespace isc::dns::rdata;
//
// Definition of the classes
//
// For each class, we need a struct, a helper functions (init, destroy,
// and static wrappers around the methods we export), a list of methods,
// and a type description
namespace {
//
// TSIGKey
//
// The s_* Class simply covers one instantiation of the object
class s_TSIGKey : public PyObject {
public:
s_TSIGKey() : tsigkey(NULL) {}
TSIGKey* tsigkey;
};
//
// We declare the functions here, the definitions are below
// the type definition of the object, since both can use the other
//
// General creation and destruction
int TSIGKey_init(s_TSIGKey* self, PyObject* args);
void TSIGKey_destroy(s_TSIGKey* self);
// These are the functions we export
// This is a second version of toText, we need one where the argument
// is a PyObject*, for the str() function in python.
PyObject* TSIGKey_getKeyName(const s_TSIGKey* self);
PyObject* TSIGKey_getAlgorithmName(const s_TSIGKey* self);
PyObject* TSIGKey_getSecret(const s_TSIGKey* self);
// This list contains the actual set of functions we have in
// python. Each entry has
// 1. Python method name
// 2. Our static function here
// 3. Argument type
// 4. Documentation
PyMethodDef TSIGKey_methods[] = {
{ "get_key_name",
reinterpret_cast<PyCFunction>(TSIGKey_getKeyName), METH_NOARGS,
"Return the key name." },
{ "get_algorithm_name",
reinterpret_cast<PyCFunction>(TSIGKey_getAlgorithmName), METH_NOARGS,
"Return the algorithm name." },
{ "get_secret",
reinterpret_cast<PyCFunction>(TSIGKey_getSecret), METH_NOARGS,
"Return the value of the TSIG secret." },
{ NULL, NULL, 0, NULL }
};
// This defines the complete type for reflection in python and
// parsing of PyObject* to s_EDNS
// Most of the functions are not actually implemented and NULL here.
PyTypeObject tsigkey_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"libdns_python.TSIGKey",
sizeof(s_TSIGKey), // tp_basicsize
0, // tp_itemsize
(destructor)TSIGKey_destroy, // tp_dealloc
NULL, // tp_print
NULL, // tp_getattr
NULL, // tp_setattr
NULL, // tp_reserved
NULL, // tp_repr
NULL, // tp_as_number
NULL, // tp_as_sequence
NULL, // tp_as_mapping
NULL, // tp_hash
NULL, // tp_call
NULL, // tp_str
NULL, // tp_getattro
NULL, // tp_setattro
NULL, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
"The TSIGKey class holds a TSIG key along with some related attributes as "
"defined in RFC2845.",
NULL, // tp_traverse
NULL, // tp_clear
NULL, // tp_richcompare
0, // tp_weaklistoffset
NULL, // tp_iter
NULL, // tp_iternext
TSIGKey_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
(initproc)TSIGKey_init, // tp_init
NULL, // tp_alloc
PyType_GenericNew, // tp_new
NULL, // tp_free
NULL, // tp_is_gc
NULL, // tp_bases
NULL, // tp_mro
NULL, // tp_cache
NULL, // tp_subclasses
NULL, // tp_weaklist
NULL, // tp_del
0 // tp_version_tag
};
// A helper function to build a python "Name" object with error handling
// encapsulated.
s_Name*
createNameObject(const Name& source) {
s_Name* name = PyObject_New(s_Name, &name_type);
if (name == NULL) {
return (NULL);
}
name->name = new(nothrow) Name(source);
if (name->name == NULL) {
Py_DECREF(name);
PyErr_SetString(po_IscException, "Allocating Name object failed");
return (NULL);
}
return (name);
}
int
TSIGKey_init(s_TSIGKey* self, PyObject* args) {
const s_Name* key_name;
const s_Name* algorithm_name;
PyObject* bytes_obj;
const char* secret;
Py_ssize_t secret_len;
if (PyArg_ParseTuple(args, "O!O!O", &name_type, &key_name,
&name_type, &algorithm_name, &bytes_obj) &&
PyObject_AsCharBuffer(bytes_obj, &secret, &secret_len) != -1) {
try {
self->tsigkey = new TSIGKey(*key_name->name,
*algorithm_name->name,
secret, secret_len);
} catch (const isc::InvalidParameter& ex) {
PyErr_SetString(po_InvalidParameter, ex.what());
return (-1);
} catch (...) {
PyErr_SetString(po_IscException, "Unexpected exception");
return (-1);
}
return (0);
}
PyErr_Clear();
PyErr_SetString(PyExc_TypeError,
"Invalid arguments to TSIGKey constructor");
return (-1);
}
void
TSIGKey_destroy(s_TSIGKey* const self) {
delete self->tsigkey;
self->tsigkey = NULL;
Py_TYPE(self)->tp_free(self);
}
PyObject*
TSIGKey_getKeyName(const s_TSIGKey* const self) {
return (createNameObject(self->tsigkey->getKeyName()));
}
PyObject*
TSIGKey_getAlgorithmName(const s_TSIGKey* const self) {
return (createNameObject(self->tsigkey->getAlgorithmName()));
}
PyObject*
TSIGKey_getSecret(const s_TSIGKey* const self) {
return (Py_BuildValue("y#", self->tsigkey->getSecret(),
self->tsigkey->getSecretLength()));
}
// Module Initialization, all statics are initialized here
bool
initModulePart_TSIGKey(PyObject* mod) {
// We initialize the static description object with PyType_Ready(),
// then add it to the module. This is not just a check! (leaving
// this out results in segmentation faults)
if (PyType_Ready(&tsigkey_type) < 0) {
return (false);
}
Py_INCREF(&tsigkey_type);
void* p = &tsigkey_type;
if (PyModule_AddObject(mod, "TSIGKey", static_cast<PyObject*>(p)) != 0) {
Py_DECREF(&tsigkey_type);
return (false);
}
s_Name* name;
if ((name = createNameObject(TSIGKey::HMACMD5_NAME())) == NULL) {
goto cleanup;
}
addClassVariable(tsigkey_type, "HMACMD5_NAME", name);
if ((name = createNameObject(TSIGKey::HMACSHA1_NAME())) == NULL) {
goto cleanup;
}
addClassVariable(tsigkey_type, "HMACSHA1_NAME", name);
if ((name = createNameObject(TSIGKey::HMACSHA256_NAME())) == NULL) {
goto cleanup;
}
addClassVariable(tsigkey_type, "HMACSHA256_NAME", name);
return (true);
cleanup:
Py_DECREF(&tsigkey_type);
return (false);
}
//
// End of TSIGKey
//
//
// TSIGKeyRing
//
// The s_* Class simply covers one instantiation of the object
// The s_* Class simply covers one instantiation of the object
class s_TSIGKeyRing : public PyObject {
public:
s_TSIGKeyRing() : keyring(NULL) {}
TSIGKeyRing* keyring;
};
//
// We declare the functions here, the definitions are below
// the type definition of the object, since both can use the other
//
int TSIGKeyRing_init(s_TSIGKeyRing* self, PyObject* args);
void TSIGKeyRing_destroy(s_TSIGKeyRing* self);
PyObject* TSIGKeyRing_size(const s_TSIGKeyRing* self);
PyObject* TSIGKeyRing_add(const s_TSIGKeyRing* self, PyObject* args);
PyObject* TSIGKeyRing_remove(const s_TSIGKeyRing* self, PyObject* args);
PyObject* TSIGKeyRing_find(const s_TSIGKeyRing* self, PyObject* args);
PyMethodDef TSIGKeyRing_methods[] = {
{ "size", reinterpret_cast<PyCFunction>(TSIGKeyRing_size), METH_NOARGS,
"Return the number of keys stored in the TSIGKeyRing." },
{ "add", reinterpret_cast<PyCFunction>(TSIGKeyRing_add), METH_VARARGS,
"Add a TSIGKey to the TSIGKeyRing." },
{ "remove", reinterpret_cast<PyCFunction>(TSIGKeyRing_remove),
METH_VARARGS,
"Remove a TSIGKey for the given name from the TSIGKeyRing." },
{ "find", reinterpret_cast<PyCFunction>(TSIGKeyRing_find), METH_VARARGS,
"Find a TSIGKey for the given name in the TSIGKeyRing. "
"It returns a tuple of (result_code, key)." },
{ NULL, NULL, 0, NULL }
};
PyTypeObject tsigkeyring_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"libdns_python.TSIGKeyRing",
sizeof(s_TSIGKeyRing), // tp_basicsize
0, // tp_itemsize
(destructor)TSIGKeyRing_destroy, // tp_dealloc
NULL, // tp_print
NULL, // tp_getattr
NULL, // tp_setattr
NULL, // tp_reserved
NULL, // tp_repr
NULL, // tp_as_number
NULL, // tp_as_sequence
NULL, // tp_as_mapping
NULL, // tp_hash
NULL, // tp_call
NULL, // tp_str
NULL, // tp_getattro
NULL, // tp_setattro
NULL, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
"A simple repository of a set of TSIGKey objects.",
NULL, // tp_traverse
NULL, // tp_clear
NULL, // tp_richcompare
0, // tp_weaklistoffset
NULL, // tp_iter
NULL, // tp_iternext
TSIGKeyRing_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
(initproc)TSIGKeyRing_init, // tp_init
NULL, // tp_alloc
PyType_GenericNew, // tp_new
NULL, // tp_free
NULL, // tp_is_gc
NULL, // tp_bases
NULL, // tp_mro
NULL, // tp_cache
NULL, // tp_subclasses
NULL, // tp_weaklist
NULL, // tp_del
0 // tp_version_tag
};
int
TSIGKeyRing_init(s_TSIGKeyRing* self, PyObject* args) {
if (!PyArg_ParseTuple(args, "")) {
PyErr_Clear();
PyErr_SetString(PyExc_TypeError,
"Invalid arguments to TSIGKeyRing constructor");
return (-1);
}
self->keyring = new(nothrow) TSIGKeyRing();
if (self->keyring == NULL) {
PyErr_SetString(po_IscException, "Allocating TSIGKeyRing failed");
return (-1);
}
return (0);
}
void
TSIGKeyRing_destroy(s_TSIGKeyRing* self) {
delete self->keyring;
self->keyring = NULL;
Py_TYPE(self)->tp_free(self);
}
PyObject*
TSIGKeyRing_size(const s_TSIGKeyRing* const self) {
return (Py_BuildValue("I", self->keyring->size()));
}
PyObject*
TSIGKeyRing_add(const s_TSIGKeyRing* const self, PyObject* args) {