# $Id$ # # Copyright (C) 2014 Dragon Research Labs ("DRL") # Portions copyright (C) 2009-2013 Internet Systems Consortium ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notices and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND DRL AND ISC DISCLAIM ALL # WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DRL OR # 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. """ PDU classes for the RPKI-RTR protocol (RFC 6810 et sequalia). """ import struct import base64 import logging import rpki.POW # Exceptions class PDUException(Exception): """ Parent exception type for exceptions that signal particular protocol errors. String value of exception instance will be the message to put in the ErrorReportPDU, error_report_code value of exception will be the numeric code to use. """ def __init__(self, msg = None, pdu = None): super(PDUException, self).__init__() assert msg is None or isinstance(msg, (str, unicode)) self.error_report_msg = msg self.error_report_pdu = pdu def __str__(self): return self.error_report_msg or self.__class__.__name__ def make_error_report(self, version): return ErrorReportPDU(version = version, errno = self.error_report_code, errmsg = self.error_report_msg, errpdu = self.error_report_pdu) class UnsupportedProtocolVersion(PDUException): error_report_code = 4 class UnsupportedPDUType(PDUException): error_report_code = 5 class CorruptData(PDUException): error_report_code = 0 # Decorators def wire_pdu(cls, versions = None): """ Class decorator to add a PDU class to the set of known PDUs for all supported protocol versions. """ for v in PDU.version_map.iterkeys() if versions is None else versions: assert cls.pdu_type not in PDU.version_map[v] PDU.version_map[v][cls.pdu_type] = cls return cls def wire_pdu_only(*versions): """ Class decorator to add a PDU class to the set of known PDUs for specific protocol versions. """ assert versions and all(v in PDU.version_map for v in versions) return lambda cls: wire_pdu(cls, versions) def clone_pdu_root(root_pdu_class): """ Replace a PDU root class's version_map with a two-level deep copy of itself, and return a class decorator which subclasses can use to replace their parent classes with themselves in the resulting cloned version map. This function is not itself a decorator, it returns one. """ root_pdu_class.version_map = dict((k, v.copy()) for k, v in root_pdu_class.version_map.iteritems()) def decorator(cls): for pdu_map in root_pdu_class.version_map.itervalues(): for pdu_type, pdu_class in pdu_map.items(): if pdu_class in cls.__bases__: pdu_map[pdu_type] = cls return cls return decorator # PDUs class PDU(object): """ Base PDU. Real PDUs are subclasses of this class. """ version_map = {0 : {}, 1 : {}} # Updated by @wire_pdu _pdu = None # Cached when first generated header_struct = struct.Struct("!BB2xL") pdu_type = None def __init__(self, version): assert version in self.version_map self.version = version def __cmp__(self, other): return cmp(self.to_pdu(), other.to_pdu()) def to_pdu(self, announce = None): return NotImplementedError @property def default_version(self): return max(self.version_map.iterkeys()) def check(self): pass @classmethod def read_pdu(cls, reader): return reader.update(need = cls.header_struct.size, callback = cls.got_header) @classmethod def got_header(cls, reader): if not reader.ready(): return None assert reader.available() >= cls.header_struct.size version, pdu_type, length = cls.header_struct.unpack(reader.buffer[:cls.header_struct.size]) reader.check_version(version) if pdu_type not in cls.version_map[version]: raise UnsupportedPDUType( "Received unsupported PDU type %d" % pdu_type) if length < 8: raise CorruptData( "Received PDU with length %d, which is too short to be valid" % length) self = cls.version_map[version][pdu_type](version = version) return reader.update(need = length, callback = self.got_pdu) class PDUWithSerial(PDU): """ Base class for PDUs consisting of just a serial number and nonce. """ header_struct = struct.Struct("!BBHLL") def __init__(self, version, serial = None, nonce = None): super(PDUWithSerial, self).__init__(version) if serial is not None: assert isinstance(serial, int) self.serial = serial if nonce is not None: assert isinstance(nonce, int) self.nonce = nonce def __str__(se
/* ssl/ssl_err2.c */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
 * All rights reserved.
 *
 * This package is an SSL implementation written
 * by Eric Young (eay@cryptsoft.com).
 * The implementation was written so as to conform with Netscapes SSL.
 * 
 * This library is free for commercial and non-commercial use as long as
 * the following conditions are aheared to.  The following conditions
 * apply to all code found in this distribution, be it the RC4, RSA,
 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
 * included with this distribution is covered by the same copyright terms
 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
 * 
 * Copyright remains Eric Young's, and as such any Copyright notices in
 * the code are not to be removed.
 * If this package is used in a product, Eric Young should be given attribution
 * as the author of the parts of the library used.
 * This can be in the form of a textual message at program startup or
 * in documentation (online or textual) provided with the package.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    "This product includes cryptographic software written by
 *     Eric Young (eay@cryptsoft.com)"
 *    The word 'cryptographic' can be left out if the rouines from the library
 *    being used are not cryptographic related :-).
 * 4. If you include any Windows specific code (or a derivative thereof) from 
 *    the apps directory (application code) you must include an acknowledgement:
 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
 * 
 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * 
 * The licence and distribution terms for any publically available version or
 * derivative of this code cannot be changed.  i.e. this code cannot simply be
 * copied and put under another distribution licence
 * [including the GNU Public Licence.]
 */

#include <stdio.h>
#include <openssl/err.h>
#include <openssl/ssl.h>

void SSL_load_error_strings(void)
	{
#ifndef OPENSSL_NO_ERR
	ERR_load_crypto_strings();
	ERR_load_SSL_strings();
#endif
	}
lass IPv6PrefixPDU(PrefixPDU): """ IPv6 flavor of a prefix. """ pdu_type = 6 address_byte_count = 16 @wire_pdu_only(1) class RouterKeyPDU(PDU): """ Router Key PDU. """ pdu_type = 9 header_struct = struct.Struct("!BBBxL20sL") def __init__(self, version): super(RouterKeyPDU, self).__init__(version) self.announce = None self.ski = None self.asn = None self.key = None def __str__(self): return "%s %8s %-32s %s" % ("+" if self.announce else "-", self.asn, base64.urlsafe_b64encode(self.ski).rstrip("="), ":".join(("%02X" % ord(b) for b in self.to_pdu()))) def check(self): """ Check attributes to make sure they're within range. """ if self.announce not in (0, 1): raise CorruptData("Announce value %d is neither zero nor one" % self.announce, pdu = self) if len(self.ski) != 20: raise CorruptData("Implausible SKI length %d" % len(self.ski), pdu = self) pdulen = self.header_struct.size + len(self.key) if len(self.to_pdu()) != pdulen: raise CorruptData("Expected %d byte PDU, got %d" % (pdulen, len(self.to_pdu())), pdu = self) def to_pdu(self, announce = None): if announce is not None: assert announce in (0, 1) elif self._pdu is not None: return self._pdu pdulen = self.header_struct.size + len(self.key) pdu = (self.header_struct.pack(self.version, self.pdu_type, announce if announce is not None else self.announce, pdulen, self.ski, self.asn) + self.key) if announce is None: assert self._pdu is None self._pdu = pdu return pdu def got_pdu(self, reader): if not reader.ready(): return None header = reader.get(self.header_struct.size) version, pdu_type, self.announce, length, self.ski, self.asn = self.header_struct.unpack(header) assert version == self.version and pdu_type == self.pdu_type remaining = length - self.header_struct.size if remaining <= 0: raise CorruptData("Got PDU length %d, minimum is %d" % (length, self.header_struct.size + 1), pdu = self) self.key = reader.get(remaining) assert header + self.key == self.to_pdu() return self @wire_pdu class ErrorReportPDU(PDU): """ Error Report PDU. """ pdu_type = 10 header_struct = struct.Struct("!BBHL") string_struct = struct.Struct("!L") errors = { 2 : "No Data Available" } fatal = { 0 : "Corrupt Data", 1 : "Internal Error", 3 : "Invalid Request", 4 : "Unsupported Protocol Version", 5 : "Unsupported PDU Type", 6 : "Withdrawal of Unknown Record", 7 : "Duplicate Announcement Received" } assert set(errors) & set(fatal) == set() errors.update(fatal) codes = dict((v, k) for k, v in errors.items()) def __init__(self, version, errno = None, errpdu = None, errmsg = None): super(ErrorReportPDU, self).__init__(version) assert errno is None or errno in self.errors self.errno = errno self.errpdu = errpdu self.errmsg = errmsg if errmsg is not None or errno is None else self.errors[errno] self.pdulen = None self.errlen = None def __str__(self): return "[%s, error #%s: %r]" % (self.__class__.__name__, self.errno, self.errmsg) def to_counted_string(self, s): return self.string_struct.pack(len(s)) + s def read_counted_string(self, reader, remaining): assert remaining >= self.string_struct.size n = self.string_struct.unpack(reader.get(self.string_struct.size))[0] assert remaining >= self.string_struct.size + n return n, reader.get(n), (remaining - self.string_struct.size - n) def to_pdu(self, announce = None): """ Generate the wire format PDU for this error report. """ assert announce is None if self._pdu is None: assert isinstance(self.errno, int) assert not isinstance(self.errpdu, ErrorReportPDU) p = self.errpdu if p is None: p = "" elif isinstance(p, PDU): p = p.to_pdu() assert isinstance(p, str) pdulen = self.header_struct.size + self.string_struct.size * 2 + len(p) + len(self.errmsg) self._pdu = self.header_struct.pack(self.version, self.pdu_type, self.errno, pdulen) self._pdu += self.to_counted_string(p) self._pdu += self.to_counted_string(self.errmsg.encode("utf8")) return self._pdu def got_pdu(self, reader): if not reader.ready(): return None header = reader.get(self.header_struct.size) version, pdu_type, self.errno, length = self.header_struct.unpack(header) assert version == self.version and pdu_type == self.pdu_type remaining = length - self.header_struct.size self.pdulen, self.errpdu, remaining = self.read_counted_string(reader, remaining) self.errlen, self.errmsg, remaining = self.read_counted_string(reader, remaining) if length != self.header_struct.size + self.string_struct.size * 2 + self.pdulen + self.errlen: raise CorruptData("Got PDU length %d, expected %d" % ( length, self.header_struct.size + self.string_struct.size * 2 + self.pdulen + self.errlen)) assert (header + self.to_counted_string(self.errpdu) + self.to_counted_string(self.errmsg.encode("utf8")) == self.to_pdu()) return self