diff options
Diffstat (limited to 'scripts/rpki')
-rw-r--r-- | scripts/rpki/Doxyfile | 1269 | ||||
-rw-r--r-- | scripts/rpki/__init__.py | 42 | ||||
-rw-r--r-- | scripts/rpki/cms.py | 120 | ||||
-rw-r--r-- | scripts/rpki/config.py | 57 | ||||
-rw-r--r-- | scripts/rpki/exceptions.py | 86 | ||||
-rw-r--r-- | scripts/rpki/https.py | 146 | ||||
-rw-r--r-- | scripts/rpki/ipaddrs.py | 70 | ||||
-rw-r--r-- | scripts/rpki/left_right.py | 1002 | ||||
-rw-r--r-- | scripts/rpki/log.py | 54 | ||||
-rw-r--r-- | scripts/rpki/manifest.py | 53 | ||||
-rw-r--r-- | scripts/rpki/oids.py | 49 | ||||
-rw-r--r-- | scripts/rpki/pkcs10.py | 62 | ||||
-rw-r--r-- | scripts/rpki/relaxng.py | 1208 | ||||
-rw-r--r-- | scripts/rpki/resource_set.py | 528 | ||||
-rw-r--r-- | scripts/rpki/roa.py | 49 | ||||
-rw-r--r-- | scripts/rpki/sax_utils.py | 93 | ||||
-rw-r--r-- | scripts/rpki/sql.py | 801 | ||||
-rw-r--r-- | scripts/rpki/sundial.py | 147 | ||||
-rw-r--r-- | scripts/rpki/up_down.py | 518 | ||||
-rw-r--r-- | scripts/rpki/x509.py | 700 |
20 files changed, 0 insertions, 7054 deletions
diff --git a/scripts/rpki/Doxyfile b/scripts/rpki/Doxyfile deleted file mode 100644 index 276c0967..00000000 --- a/scripts/rpki/Doxyfile +++ /dev/null @@ -1,1269 +0,0 @@ -# $Id$ - -# Doxyfile 1.5.2 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file that -# follow. The default is UTF-8 which is also the encoding used for all text before -# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into -# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of -# possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = "Resource PKI Engine" - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = RPKI - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, -# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, -# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, -# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = "The $name class" \ - "The $name widget" \ - "The $name file" \ - is \ - provides \ - specifies \ - contains \ - represents \ - a \ - an \ - the - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = NO - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like the Qt-style comments (thus requiring an -# explicit @brief command for a brief description. - -JAVADOC_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the DETAILS_AT_TOP tag is set to YES then Doxygen -# will output the detailed description near the top, like JavaDoc. -# If set to NO, the detailed description appears after the member -# documentation. - -DETAILS_AT_TOP = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 8 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for Java. -# For instance, namespaces will be presented as packages, qualified scopes -# will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = YES - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to -# include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = YES - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = YES - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = YES - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = YES - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. - -SHOW_DIRECTORIES = NO - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from the -# version control system). Doxygen will invoke the program by executing (via -# popen()) the command <command> <input-file>, where <command> is the value of -# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = "perl -e '@a = split(q( ), qx(svn stat -v $ARGV[0])); shift @a until $a[0] =~ /^[0-9]+$/ or @a == 0; shift @a; print shift(@a), qq(\n)'" - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = YES - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = . - -# This tag can be used to specify the character encoding of the source files that -# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default -# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. -# See http://www.gnu.org/software/libiconv for the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py - -FILE_PATTERNS = *.py - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = NO - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the output. -# The symbol name can be a fully qualified name, a word, or if the wildcard * is used, -# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = * - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command <filter> <input-file>, where <filter> -# is the value of the INPUT_FILTER tag, and <input-file> is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - -SOURCE_BROWSER = YES - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES (the default) -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = YES - -# If the REFERENCES_RELATION tag is set to YES (the default) -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = YES - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. Otherwise they will link to the documentstion. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = YES - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = - -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - -DISABLE_INDEX = NO - -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - -ENUM_VALUES_PER_LINE = 4 - -# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be -# generated containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, -# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are -# probably better off using the HTML help feature. - -GENERATE_TREEVIEW = NO - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = NO - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = YES - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = letter - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = YES - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = YES - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = YES - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = YES - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = NO - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. - -CLASS_DIAGRAMS = NO - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to -# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to -# specify the directory where the mscgen tool resides. If left empty the tool is assumed to -# be found in the default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = NO - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = YES - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = NO - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = YES - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = NO - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will -# generate a call dependency graph for every global function or class method. -# Note that enabling this option will significantly increase the time of a run. -# So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. - -CALL_GRAPH = YES - -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will -# generate a caller dependency graph for every global function or class method. -# Note that enabling this option will significantly increase the time of a run. -# So in most cases it will be better to enable caller graphs for selected -# functions only using the \callergraph command. - -CALLER_GRAPH = YES - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = NO - -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. - -DOT_IMAGE_FORMAT = png - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen will always -# show the root nodes and its direct children regardless of this setting. - -DOT_GRAPH_MAX_NODES = 50 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, which results in a white background. -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = NO - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = NO - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to the search engine -#--------------------------------------------------------------------------- - -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - -SEARCHENGINE = NO diff --git a/scripts/rpki/__init__.py b/scripts/rpki/__init__.py deleted file mode 100644 index 690c7f9c..00000000 --- a/scripts/rpki/__init__.py +++ /dev/null @@ -1,42 +0,0 @@ -# $Id$ - -# Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") -# -# 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 ARIN DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL ARIN 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. - -# This file exists to tell Python that this the content of this -# directory constitute a Python package. Since we're not doing -# anything exotic, this file doesn't need to contain any code, but -# since its existance defines the package, it's as sensible a place as -# any to put the Doxygen mainpage. - -## @mainpage -## -## This collection of Python modules implements a prototype of the -## RPKI Engine. This is a work in progress. -## -## See http://viewvc.hactrn.net/subvert-rpki.hactrn.net/ for code, -## design documents, a text mirror of portions of APNIC's Wiki, etc. -## -## The documentation you're reading is generated automatically by -## Doxygen from comments and documentation in -## <a href="http://viewvc.hactrn.net/subvert-rpki.hactrn.net/scripts/rpki/">the code</a>. -## -## This work is funded by <a href="http://www.arin.net/">ARIN</a>, in -## collaboration with the other RIRs. If you're interested in this -## package you might also be interested in: -## -## @li <a href="http://viewvc.hactrn.net/subvert-rpki.hactrn.net/rcynic/">the rcynic validation tool</a> -## @li <a href="http://www.hactrn.net/opaque/rcynic.html">a sample of rcynic's summary output</a> -## @li <a href="http://mirin.apnic.net/resourcecerts/wiki/">APNIC's Wiki</a> -## @li <a href="http://mirin.apnic.net/trac/">APNIC's project Trac instance</a> diff --git a/scripts/rpki/cms.py b/scripts/rpki/cms.py deleted file mode 100644 index 7b4916dc..00000000 --- a/scripts/rpki/cms.py +++ /dev/null @@ -1,120 +0,0 @@ -# $Id$ - -# Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") -# -# 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 ARIN DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL ARIN 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. - -"""CMS routines. - -These used to use the OpenSSL CLI too, which was slow. I've since -added minimal PKCS #7 / CMS capability to POW, so we now use that -instead. I should write a pretty DER_object wrapper around the POW -code and include it in x509.py, but I haven't gotten to that yet. -""" - -import os, rpki.x509, rpki.exceptions, lxml.etree, rpki.log, POW - -debug = 1 - -# openssl smime -sign -nodetach -outform DER -signer biz-certs/Alice-EE.cer -# -certfile biz-certs/Alice-CA.cer -inkey biz-certs/Alice-EE.key -# -in THING -out THING.der - -def sign(plaintext, keypair, certs): - """Sign plaintext as CMS with specified key and bag of certificates. - - We have to sort the certificates into the correct order before the - OpenSSL CLI tool will accept them. rpki.x509 handles that for us. - """ - - p7 = POW.PKCS7() - p7.sign(certs[0].get_POW(), keypair.get_POW(), [x.get_POW() for x in certs[1:]], plaintext) - cms = p7.derWrite() - - if debug >= 2: - print - print "Signed CMS:" - dumpasn1(cms) - - return cms - -# openssl smime -verify -inform DER -in THING.der -CAfile biz-certs/Alice-Root.cer - -def verify(cms, ta): - """Verify the signature of a chunk of CMS. - - Returns the plaintext on success, otherwise raise an exception. - """ - - if debug >= 2: - print - print "Verifying CMS:" - dumpasn1(cms) - - p7 = POW.derRead(POW.PKCS7_MESSAGE, cms) - - store = POW.X509Store() - store.addTrust(ta.get_POW()) - - try: - return p7.verify(store) - - except: - if debug >= 1: - print "CMS verification failed, dumping inputs:" - print - print "TA:" - dumpasn1(ta.get_DER()) - print - print "CMS:" - dumpasn1(cms) - raise rpki.exceptions.CMSVerificationFailed, "CMS verification failed" - -# openssl smime -verify -noverify -inform DER -in THING.der - -def extract(cms): - """Extract the content of a signed CMS message WITHOUT verifying the - signature. Don't try this at home, kids. - """ - - return POW.derRead(POW.PKCS7_MESSAGE, cms).extract() - -def xml_verify(cms, ta): - """Composite routine to verify CMS-wrapped XML.""" - - val = lxml.etree.fromstring(verify(cms, ta)) - return val - -def xml_sign(elt, key, certs, encoding = "us-ascii"): - """Composite routine to sign CMS-wrapped XML.""" - - val = sign(lxml.etree.tostring(elt, pretty_print = True, encoding = encoding, xml_declaration = True), - key, certs) - return val - -def dumpasn1(thing): - """Prettyprint an ASN.1 DER object using cryptlib dumpasn1 tool. - Use a temporary file rather than popen4() because dumpasn1 uses - seek() when decoding ASN.1 content nested in OCTET STRING values. - """ - - fn = "dumpasn1.tmp" - try: - f = open(fn, "w") - f.write(thing) - f.close() - f = os.popen("dumpasn1 2>&1 -a " + fn) - print "\n".join(x for x in f.read().splitlines() if x.startswith(" ")) - f.close() - finally: - os.unlink(fn) diff --git a/scripts/rpki/config.py b/scripts/rpki/config.py deleted file mode 100644 index 54540bbc..00000000 --- a/scripts/rpki/config.py +++ /dev/null @@ -1,57 +0,0 @@ -# $Id$ - -# Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") -# -# 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 ARIN DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL ARIN 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. - -"""Configuration file parsing utilities. - -Layered on top of stock Python ConfigParser module. -""" - -import ConfigParser - -class parser(ConfigParser.RawConfigParser): - - def __init__(self, file = None, section = None): - """Initialize this parser.""" - ConfigParser.RawConfigParser.__init__(self) - if file: - self.read(file) - self.default_section = section - - def multiget(self, option, section = None): - """Parse OpenSSL-style foo.0, foo.1, ... subscripted options. - - Returns a list of values matching the specified option name. - """ - matches = [] - if section is None: - section = self.default_section - if self.has_option(section, option): - matches.append((-1, self.get(option, section = section))) - for key, value in self.items(section): - s = key.rsplit(".", 1) - if len(s) == 2 and s[0] == option and s[1].isdigit(): - matches.append((int(s[1]), value)) - matches.sort() - return [match[1] for match in matches] - - def get(self, option, default = None, section = None): - """Get an option, perhaps with a default value.""" - if section is None: - section = self.default_section - if default is None or self.has_option(section, option): - return ConfigParser.RawConfigParser.get(self, section, option) - else: - return default diff --git a/scripts/rpki/exceptions.py b/scripts/rpki/exceptions.py deleted file mode 100644 index c1475680..00000000 --- a/scripts/rpki/exceptions.py +++ /dev/null @@ -1,86 +0,0 @@ -# $Id$ - -# Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") -# -# 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 ARIN DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL ARIN 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. - -"""Exception definitions for RPKI modules.""" - -class NotInDatabase(Exception): - """Lookup failed for an object expected to be in the database.""" - -class BadURISyntax(Exception): - """Illegal syntax for a URI.""" - -class BadStatusCode(Exception): - """Unrecognized protocol status code.""" - -class BadQuery(Exception): - """Unexpected protocol query.""" - -class DBConsistancyError(Exception): - """Found multiple matches for a database query that shouldn't ever return that.""" - -class CMSVerificationFailed(Exception): - """Verification of a CMS message failed.""" - -class HTTPRequestFailed(Exception): - """HTTP request failed.""" - -class DERObjectConversionError(Exception): - """Error trying to convert a DER-based object from one representation to another.""" - -class NotACertificateChain(Exception): - """Certificates don't form a proper chain.""" - -class BadContactURL(Exception): - """Error trying to parse up-down protocol contact URL.""" - -class BadClassNameSyntax(Exception): - """Illegal syntax for a class_name.""" - -class BadIssueResponse(Exception): - """issue_response PDU with wrong number of classes or certificates.""" - -class NotImplementedYet(Exception): - """Internal error -- not implemented yet.""" - -class BadPKCS10(Exception): - """Bad PKCS #10 object.""" - -class UpstreamError(Exception): - """Received an error from upstream.""" - -class ChildNotFound(Exception): - """Could not find specified child in database.""" - -class BSCNotFound(Exception): - """Could not find specified BSC in database.""" - -class BadSender(Exception): - """Unexpected XML sender value.""" - -class ClassNameMismatch(Exception): - """class_name does not match child context.""" - -class SKIMismatch(Exception): - """SKI value in response does not match request.""" - -class SubprocessError(Exception): - """Subprocess returned unexpected error.""" - -class BadIRDBReply(Exception): - """Unexpected reply to IRDB query.""" - -class NotFound(Exception): - """Object not found in database.""" diff --git a/scripts/rpki/https.py b/scripts/rpki/https.py deleted file mode 100644 index bca5a8b1..00000000 --- a/scripts/rpki/https.py +++ /dev/null @@ -1,146 +0,0 @@ -# $Id$ - -# Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") -# -# 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 ARIN DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL ARIN 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. - -"""HTTPS utilities, both client and server. - -At the moment this only knows how to use the PEM certs in my -subversion repository; generalizing it would not be hard, but the more -general version should use SQL anyway. -""" - -import httplib, BaseHTTPServer, tlslite.api, glob, traceback, urlparse, socket -import rpki.x509, rpki.exceptions, rpki.log - -rpki_content_type = "application/x-rpki" - -def client(msg, privateKey, certChain, x509TrustList, url, timeout = 300): - """Open client HTTPS connection, send a message, wait for response. - - This function wraps most of what one needs to do to send a message - over HTTPS and get a response. The certificate checking isn't quite - up to snuff; it's better than with the other packages I've found, - but doesn't appear to handle subjectAltName extensions (sigh). - """ - - u = urlparse.urlparse(url) - - assert u.scheme in ("", "https") and \ - u.username is None and \ - u.password is None and \ - u.params == "" and \ - u.query == "" and \ - u.fragment == "" - - # We could add a "settings = foo" argument to the following call to - # pass in a tlslite.HandshakeSettings object that would let us - # insist on, eg, particular SSL/TLS versions. - - httpc = tlslite.api.HTTPTLSConnection(host = u.hostname or "localhost", - port = u.port or 443, - privateKey = privateKey.get_tlslite(), - certChain = certChain.tlslite_certChain(), - x509TrustList = x509TrustList.tlslite_trustList()) - httpc.connect() - httpc.sock.settimeout(timeout) - httpc.request("POST", u.path, msg, {"Content-Type" : rpki_content_type}) - response = httpc.getresponse() - if response.status == httplib.OK: - return response.read() - else: - r = response.read() - raise rpki.exceptions.HTTPRequestFailed, \ - "HTTP request failed with status %s, response %s" % (response.status, r) - -class requestHandler(BaseHTTPServer.BaseHTTPRequestHandler): - """Derived type to supply POST handler and override logging.""" - - rpki_handlers = None # Subclass must bind - - def rpki_find_handler(self): - """Helper method to search self.rpki_handlers.""" - for s,h in self.rpki_handlers: - if self.path.startswith(s): - return h - return None - - def do_POST(self): - """POST handler.""" - try: - handler = self.rpki_find_handler() - if self.headers["Content-Type"] != rpki_content_type: - rcode, rtext = 415, "Received Content-Type %s, expected %s" \ - % (self.headers["Content-Type"], rpki_content_type) - elif handler is None: - rcode, rtext = 404, "No handler found for URL " + self.path - else: - rcode, rtext = handler(query = self.rfile.read(int(self.headers["Content-Length"])), - path = self.path) - except Exception, edata: - rpki.log.error(traceback.format_exc()) - rcode, rtext = 500, "Unhandled exception %s" % edata - self.send_response(rcode) - self.send_header("Content-Type", rpki_content_type) - self.end_headers() - self.wfile.write(rtext) - - def log_message(self, format, *args): - """Redirect HTTP server logging into our own logging system.""" - if args: - rpki.log.info(format % args) - else: - rpki.log.info(format) - -class httpServer(tlslite.api.TLSSocketServerMixIn, BaseHTTPServer.HTTPServer): - """Derived type to handle TLS aspects of HTTPS.""" - - rpki_certChain = None - rpki_privateKey = None - rpki_sessionCache = None - - def handshake(self, tlsConnection): - """TLS handshake handler.""" - assert self.rpki_certChain is not None - assert self.rpki_privateKey is not None - assert self.rpki_sessionCache is not None - try: - # We could add a "settings = foo" argument to the following call - # to pass in a tlslite.HandshakeSettings object that would let - # us insist on, eg, particular SSL/TLS versions. - tlsConnection.handshakeServer(certChain = self.rpki_certChain, - privateKey = self.rpki_privateKey, - sessionCache = self.rpki_sessionCache) - tlsConnection.ignoreAbruptClose = True - return True - except tlslite.api.TLSError, error: - rpki.log.warn("TLS handshake failure: " + str(error)) - return False - -def server(handlers, privateKey, certChain, port = 4433, host = ""): - """Run an HTTPS server and wait (forever) for connections.""" - - if not isinstance(handlers, (tuple, list)): - handlers = (("/", handlers),) - - class boundRequestHandler(requestHandler): - rpki_handlers = handlers - - httpd = httpServer((host, port), boundRequestHandler) - - httpd.rpki_privateKey = privateKey.get_tlslite() - httpd.rpki_certChain = certChain.tlslite_certChain() - httpd.rpki_sessionCache = tlslite.api.SessionCache() - - httpd.serve_forever() diff --git a/scripts/rpki/ipaddrs.py b/scripts/rpki/ipaddrs.py deleted file mode 100644 index 4de2f428..00000000 --- a/scripts/rpki/ipaddrs.py +++ /dev/null @@ -1,70 +0,0 @@ -# $Id$ - -# Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") -# -# 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 ARIN DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL ARIN 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. - -"""Classes to represent IP addresses. - -Given some of the other operations we need to perform on them, it's -most convenient to represent IP addresses as Python "long" values. -The classes in this module just wrap suitable read/write syntax around -the underlying "long" type. - -These classes also supply a "bits" attribute for use by other code -built on these classes; for the most part, IPv6 addresses really are -just IPv4 addresses with more bits, so we supply the number of bits -once, here, thus avoiding a lot of duplicate code elsewhere. -""" - -import socket, struct - -class v4addr(long): - """IPv4 address. - - Derived from long, but supports IPv4 print syntax. - """ - - bits = 32 - - def __new__(cls, x): - """Construct a v4addr object.""" - if isinstance(x, str): - x = ".".join(str(int(i)) for i in x.split(".")) - y = struct.unpack("!I", socket.inet_pton(socket.AF_INET, x)) - x = y[0] - return long.__new__(cls, x) - - def __str__(self): - """Convert a v4addr object to string format.""" - return socket.inet_ntop(socket.AF_INET, struct.pack("!I", long(self))) - -class v6addr(long): - """IPv6 address. - - Derived from long, but supports IPv6 print syntax. - """ - - bits = 128 - - def __new__(cls, x): - """Construct a v6addr object.""" - if isinstance(x, str): - y = struct.unpack("!QQ", socket.inet_pton(socket.AF_INET6, x)) - x = (y[0] << 64) | y[1] - return long.__new__(cls, x) - - def __str__(self): - """Convert a v6addr object to string format.""" - return socket.inet_ntop(socket.AF_INET6, - struct.pack("!QQ", long(self) >> 64, long(self) & 0xFFFFFFFFFFFFFFFF)) diff --git a/scripts/rpki/left_right.py b/scripts/rpki/left_right.py deleted file mode 100644 index 8a5e3433..00000000 --- a/scripts/rpki/left_right.py +++ /dev/null @@ -1,1002 +0,0 @@ -# $Id$ - -# Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") -# -# 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 ARIN DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL ARIN 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. - -"""RPKI "left-right" protocol.""" - -import base64, lxml.etree, time, traceback, os -import rpki.sax_utils, rpki.resource_set, rpki.x509, rpki.sql, rpki.exceptions -import rpki.https, rpki.up_down, rpki.relaxng, rpki.sundial, rpki.log - -xmlns = "http://www.hactrn.net/uris/rpki/left-right-spec/" - -nsmap = { None : xmlns } - -class base_elt(object): - """Virtual base type for left-right message elements.""" - - attributes = () - elements = () - booleans = () - - def startElement(self, stack, name, attrs): - """Default startElement() handler: just process attributes.""" - self.read_attrs(attrs) - - def endElement(self, stack, name, text): - """Default endElement() handler: just pop the stack.""" - stack.pop() - - def read_attrs(self, attrs): - """Template-driven attribute reader.""" - for key in self.attributes: - val = attrs.get(key, None) - if isinstance(val, str) and val.isdigit(): - val = long(val) - setattr(self, key, val) - for key in self.booleans: - setattr(self, key, attrs.get(key, False)) - - def make_elt(self): - """XML element constructor.""" - elt = lxml.etree.Element("{%s}%s" % (xmlns, self.element_name), nsmap = nsmap) - for key in self.attributes: - val = getattr(self, key, None) - if val is not None: - elt.set(key, str(val)) - for key in self.booleans: - if getattr(self, key, False): - elt.set(key, "yes") - return elt - - def make_b64elt(self, elt, name, value = None): - """Constructor for Base64-encoded subelement.""" - if value is None: - value = getattr(self, name, None) - if value is not None: - lxml.etree.SubElement(elt, "{%s}%s" % (xmlns, name), nsmap = nsmap).text = base64.b64encode(value) - - def __str__(self): - """Convert a base_elt object to string format.""" - lxml.etree.tostring(self.toXML(), pretty_print = True, encoding = "us-ascii") - -class data_elt(base_elt, rpki.sql.sql_persistant): - """Virtual class for top-level left-right protocol data elements.""" - - def self(this, gctx): - """Fetch self object to which this object links.""" - return self_elt.sql_fetch(gctx, this.self_id) - - def bsc(self, gctx): - """Return BSC object to which this object links.""" - return bsc_elt.sql_fetch(gctx, self.bsc_id) - - @classmethod - def make_pdu(cls, **kargs): - """Generic left-right PDU constructor.""" - self = cls() - for k,v in kargs.items(): - setattr(self, k, v) - return self - - def make_reply(self, r_pdu = None): - """Construct a reply PDU.""" - if r_pdu is None: - r_pdu = self.__class__() - r_pdu.self_id = self.self_id - setattr(r_pdu, self.sql_template.index, getattr(self, self.sql_template.index)) - else: - for b in r_pdu.booleans: - setattr(r_pdu, b, False) - r_pdu.action = self.action - r_pdu.type = "reply" - r_pdu.tag = self.tag - return r_pdu - - def serve_pre_save_hook(self, gctx, q_pdu, r_pdu): - """Overridable hook.""" - pass - - def serve_post_save_hook(self, gctx, q_pdu, r_pdu): - """Overridable hook.""" - pass - - def serve_create(self, gctx, r_msg): - """Handle a create action.""" - r_pdu = self.make_reply() - self.serve_pre_save_hook(gctx, self, r_pdu) - self.sql_store(gctx) - setattr(r_pdu, self.sql_template.index, getattr(self, self.sql_template.index)) - self.serve_post_save_hook(gctx, self, r_pdu) - r_msg.append(r_pdu) - - def serve_fetch_one(self, gctx): - """Find the object on which a get, set, or destroy method should - operate. This is a separate method because the self object needs - to override it. - """ - where = self.sql_template.index + " = %s AND self_id = %s" - args = (getattr(self, self.sql_template.index), self.self_id) - r = self.sql_fetch_where1(gctx, where, args) - if r is None: - raise rpki.exceptions.NotFound, "Lookup failed where %s" + (where % args) - return r - - def serve_set(self, gctx, r_msg): - """Handle a set action.""" - db_pdu = self.serve_fetch_one(gctx) - r_pdu = self.make_reply() - for a in db_pdu.sql_template.columns[1:]: - v = getattr(self, a) - if v is not None: - setattr(db_pdu, a, v) - db_pdu.sql_mark_dirty() - db_pdu.serve_pre_save_hook(gctx, self, r_pdu) - db_pdu.sql_store(gctx) - db_pdu.serve_post_save_hook(gctx, self, r_pdu) - r_msg.append(r_pdu) - - def serve_get(self, gctx, r_msg): - """Handle a get action.""" - r_pdu = self.serve_fetch_one(gctx) - self.make_reply(r_pdu) - r_msg.append(r_pdu) - - def serve_list(self, gctx, r_msg): - """Handle a list action for non-self objects.""" - for r_pdu in self.sql_fetch_where(gctx, "self_id = %s", (self.self_id,)): - self.make_reply(r_pdu) - r_msg.append(r_pdu) - - def serve_destroy(self, gctx, r_msg): - """Handle a destroy action.""" - db_pdu = self.serve_fetch_one(gctx) - db_pdu.sql_delete(gctx) - r_msg.append(self.make_reply()) - - def serve_dispatch(self, gctx, r_msg): - """Action dispatch handler.""" - dispatch = { "create" : self.serve_create, - "set" : self.serve_set, - "get" : self.serve_get, - "list" : self.serve_list, - "destroy" : self.serve_destroy } - if self.type != "query" or self.action not in dispatch: - raise rpki.exceptions.BadQuery, "Unexpected query: type %s, action %s" % (self.type, self.action) - dispatch[self.action](gctx, r_msg) - - def unimplemented_control(self, *controls): - """Uniform handling for unimplemented control operations.""" - unimplemented = [x for x in controls if getattr(self, x, False)] - if unimplemented: - raise rpki.exceptions.NotImplementedYet, "Unimplemented control %s" % ", ".join(unimplemented) - -class extension_preference_elt(base_elt): - """Container for extension preferences.""" - - element_name = "extension_preference" - attributes = ("name",) - - def startElement(self, stack, name, attrs): - """Handle <extension_preference/> elements.""" - assert name == "extension_preference", "Unexpected name %s, stack %s" % (name, stack) - self.read_attrs(attrs) - - def endElement(self, stack, name, text): - """Handle <extension_preference/> elements.""" - self.value = text - stack.pop() - - def toXML(self): - """Generate <extension_preference/> elements.""" - elt = self.make_elt() - elt.text = self.value - return elt - -class self_elt(data_elt): - """<self/> element.""" - - element_name = "self" - attributes = ("action", "type", "tag", "self_id", "crl_interval") - elements = ("extension_preference",) - booleans = ("rekey", "reissue", "revoke", "run_now", "publish_world_now", "clear_extension_preferences") - - sql_template = rpki.sql.template("self", "self_id", "use_hsm", "crl_interval") - - self_id = None - use_hsm = False - crl_interval = None - - def __init__(self): - """Initialize a self_elt.""" - self.prefs = [] - - def sql_fetch_hook(self, gctx): - """Extra SQL fetch actions for self_elt -- handle extension preferences.""" - gctx.cur.execute("SELECT pref_name, pref_value FROM self_pref WHERE self_id = %s", (self.self_id,)) - for name, value in gctx.cur.fetchall(): - e = extension_preference_elt() - e.name = name - e.value = value - self.prefs.append(e) - - def sql_insert_hook(self, gctx): - """Extra SQL insert actions for self_elt -- handle extension preferences.""" - if self.prefs: - gctx.cur.executemany("INSERT self_pref (self_id, pref_name, pref_value) VALUES (%s, %s, %s)", - ((e.name, e.value, self.self_id) for e in self.prefs)) - - def sql_delete_hook(self, gctx): - """Extra SQL delete actions for self_elt -- handle extension preferences.""" - gctx.cur.execute("DELETE FROM self_pref WHERE self_id = %s", (self.self_id,)) - - def bscs(self, gctx): - """Fetch all BSC objects that link to this self object.""" - return bsc_elt.sql_fetch_where(gctx, "self_id = %s", (self.self_id,)) - - def repositories(self, gctx): - """Fetch all repository objects that link to this self object.""" - return repository_elt.sql_fetch_where(gctx, "self_id = %s", (self.self_id,)) - - def parents(self, gctx): - """Fetch all parent objects that link to this self object.""" - return parent_elt.sql_fetch_where(gctx, "self_id = %s", (self.self_id,)) - - def children(self, gctx): - """Fetch all child objects that link to this self object.""" - return child_elt.sql_fetch_where(gctx, "self_id = %s", (self.self_id,)) - - def route_origins(self, gctx): - """Fetch all route_origin objects that link to this self object.""" - return route_origin_elt.sql_fetch_where(gctx, "self_id = %s", (self.self_id,)) - - def serve_pre_save_hook(self, gctx, q_pdu, r_pdu): - """Extra server actions for self_elt -- handle extension preferences.""" - rpki.log.trace() - if self is not q_pdu: - if q_pdu.clear_extension_preferences: - self.prefs = [] - self.prefs.extend(q_pdu.prefs) - - def serve_post_save_hook(self, gctx, q_pdu, r_pdu): - """Extra server actions for self_elt.""" - rpki.log.trace() - if q_pdu.rekey: - self.serve_rekey(gctx) - if q_pdu.revoke: - self.serve_revoke(gctx) - self.unimplemented_control("reissue", "run_now", "publish_world_now") - - def serve_rekey(self, gctx): - """Handle a left-right rekey action for this self.""" - rpki.log.trace() - for parent in self.parents(gctx): - parent.serve_rekey(gctx) - - def serve_revoke(self, gctx): - """Handle a left-right revoke action for this self.""" - rpki.log.trace() - for parent in self.parents(gctx): - parent.serve_revoke(gctx) - - def serve_fetch_one(self, gctx): - """Find the self object on which a get, set, or destroy method - should operate. - """ - r = self.sql_fetch(gctx, self.self_id) - if r is None: - raise rpki.exceptions.NotFound - return r - - def serve_list(self, gctx, r_msg): - """Handle a list action for self objects. This is different from - the list action for all other objects, where list only works - within a given self_id context. - """ - for r_pdu in self.sql_fetch_all(gctx): - self.make_reply(r_pdu) - r_msg.append(r_pdu) - - def startElement(self, stack, name, attrs): - """Handle <self/> element.""" - if name == "extension_preference": - pref = extension_preference_elt() - self.prefs.append(pref) - stack.append(pref) - pref.startElement(stack, name, attrs) - else: - assert name == "self", "Unexpected name %s, stack %s" % (name, stack) - self.read_attrs(attrs) - - def endElement(self, stack, name, text): - """Handle <self/> element.""" - assert name == "self", "Unexpected name %s, stack %s" % (name, stack) - stack.pop() - - def toXML(self): - """Generate <self/> element.""" - elt = self.make_elt() - elt.extend([i.toXML() for i in self.prefs]) - return elt - - def client_poll(self, gctx): - """Run the regular client poll cycle with each of this self's parents in turn.""" - - rpki.log.trace() - - for parent in self.parents(gctx): - - # This will need a callback when we go event-driven - r_msg = rpki.up_down.list_pdu.query(gctx, parent) - - ca_map = dict((ca.parent_resource_class, ca) for ca in parent.cas(gctx)) - for rc in r_msg.payload.classes: - if rc.class_name in ca_map: - ca = ca_map[rc.class_name] - del ca_map[rc.class_name] - ca.check_for_updates(gctx, parent, rc) - else: - rpki.sql.ca_obj.create(gctx, parent, rc) - for ca in ca_map.values(): - ca.delete(gctx, parent) # CA not listed by parent - rpki.sql.sql_sweep(gctx) - - def update_children(self, gctx): - """Check for updated IRDB data for all of this self's children and - issue new certs as necessary. Must handle changes both in - resources and in expiration date. - """ - - rpki.log.trace() - - now = rpki.sundial.datetime.utcnow() - - for child in self.children(gctx): - child_certs = child.child_certs(gctx) - if not child_certs: - continue - - # This will require a callback when we go event-driven - irdb_resources = rpki.left_right.irdb_query(gctx, child.self_id, child.child_id) - - for child_cert in child_certs: - ca_detail = child_cert.ca_detail(gctx) - if ca_detail.state != "active": - continue - old_resources = child_cert.cert.get_3779resources() - new_resources = irdb_resources.intersection(old_resources) - if old_resources != new_resources: - rpki.log.debug("Need to reissue %s" % repr(child_cert)) - child_cert.reissue( - gctx = gctx, - ca_detail = ca_detail, - resources = new_resources) - elif old_resources.valid_until < now: - parent = ca.parent(gctx) - repository = parent.repository(gctx) - child_cert.sql_delete(gctx) - ca_detail.generate_manifest(gctx) - repository.withdraw(gctx, child_cert.cert, child_cert.uri(ca)) - - def regenerate_crls_and_manifests(self, gctx): - """Generate new CRLs and manifests as necessary for all of this - self's CAs. Extracting nextUpdate from a manifest is hard at the - moment due to implementation silliness, so for now we generate a - new manifest whenever we generate a new CRL - - This method also cleans up tombstones left behind by revoked - ca_detail objects, since we're walking through the relevant - portions of the database anyway. - """ - - rpki.log.trace() - - now = rpki.sundial.datetime.utcnow() - for parent in self.parents(gctx): - repository = parent.repository(gctx) - for ca in parent.cas(gctx): - for ca_detail in ca.fetch_revoked(gctx): - if now > ca_detail.latest_crl.getNextUpdate(): - ca_detail.delete(gctx, ca, repository) - ca_detail = ca.fetch_active(gctx) - if now > ca_detail.latest_crl.getNextUpdate(): - ca_detail.generate_crl(gctx) - ca_detail.generate_manifest(gctx) - -class bsc_elt(data_elt): - """<bsc/> (Business Signing Context) element.""" - - element_name = "bsc" - attributes = ("action", "type", "tag", "self_id", "bsc_id", "key_type", "hash_alg", "key_length") - elements = ('signing_cert',) - booleans = ("generate_keypair", "clear_signing_certs") - - sql_template = rpki.sql.template("bsc", "bsc_id", "self_id", - ("public_key", rpki.x509.RSApublic), - ("private_key_id", rpki.x509.RSA), "hash_alg") - - pkcs10_cert_request = None - public_key = None - private_key_id = None - - def __init__(self): - """Initialize bsc_elt.""" - self.signing_cert = rpki.x509.X509_chain() - - def sql_fetch_hook(self, gctx): - """Extra SQL fetch actions for bsc_elt -- handle signing certs.""" - gctx.cur.execute("SELECT cert FROM bsc_cert WHERE bsc_id = %s", (self.bsc_id,)) - self.signing_cert[:] = [rpki.x509.X509(DER = x) for (x,) in gctx.cur.fetchall()] - - def sql_insert_hook(self, gctx): - """Extra SQL insert actions for bsc_elt -- handle signing certs.""" - if self.signing_cert: - gctx.cur.executemany("INSERT bsc_cert (cert, bsc_id) VALUES (%s, %s)", - ((x.get_DER(), self.bsc_id) for x in self.signing_cert)) - - def sql_delete_hook(self, gctx): - """Extra SQL delete actions for bsc_elt -- handle signing certs.""" - gctx.cur.execute("DELETE FROM bsc_cert WHERE bsc_id = %s", (self.bsc_id,)) - - def repositories(self, gctx): - """Fetch all repository objects that link to this BSC object.""" - return repository_elt.sql_fetch_where(gctx, "bsc_id = %s", (self.bsc_id,)) - - def parents(self, gctx): - """Fetch all parent objects that link to this BSC object.""" - return parent_elt.sql_fetch_where(gctx, "bsc_id = %s", (self.bsc_id,)) - - def children(self, gctx): - """Fetch all child objects that link to this BSC object.""" - return child_elt.sql_fetch_where(gctx, "bsc_id = %s", (self.bsc_id,)) - - def serve_pre_save_hook(self, gctx, q_pdu, r_pdu): - """Extra server actions for bsc_elt -- handle signing certs and key generation.""" - if self is not q_pdu: - if q_pdu.clear_signing_certs: - self.signing_cert[:] = [] - self.signing_cert.extend(q_pdu.signing_cert) - if q_pdu.generate_keypair: - # - # For the moment we only support 2048-bit RSA with SHA-256, no - # HSM. Assertion just checks that the schema hasn't changed out - # from under this code. - # - assert (q_pdu.key_type is None or q_pdu.key_type == "rsa") and \ - (q_pdu.hash_alg is None or q_pdu.hash_alg == "sha256") and \ - (q_pdu.key_length is None or q_pdu.key_length == 2048) - keypair = rpki.x509.RSA() - keypair.generate() - self.private_key_id = keypair - self.public_key = keypair.get_RSApublic() - r_pdu.pkcs10_cert_request = rpki.x509.PKCS10.create(keypair) - - def startElement(self, stack, name, attrs): - """Handle <bsc/> element.""" - if not name in ("signing_cert", "public_key", "pkcs10_cert_request"): - assert name == "bsc", "Unexpected name %s, stack %s" % (name, stack) - self.read_attrs(attrs) - - def endElement(self, stack, name, text): - """Handle <bsc/> element.""" - if name == "signing_cert": - self.signing_cert.append(rpki.x509.X509(Base64 = text)) - elif name == "public_key": - self.public_key = rpki.x509.RSApublic(Base64 = text) - elif name == "pkcs10_cert_request": - self.pkcs10_cert_request = rpki.x509.PKCS10(Base64 = text) - else: - assert name == "bsc", "Unexpected name %s, stack %s" % (name, stack) - stack.pop() - - def toXML(self): - """Generate <bsc/> element.""" - elt = self.make_elt() - for cert in self.signing_cert: - self.make_b64elt(elt, "signing_cert", cert.get_DER()) - if self.pkcs10_cert_request is not None: - self.make_b64elt(elt, "pkcs10_cert_request", self.pkcs10_cert_request.get_DER()) - if self.public_key is not None: - self.make_b64elt(elt, "public_key", self.public_key.get_DER()) - return elt - -class parent_elt(data_elt): - """<parent/> element.""" - - element_name = "parent" - attributes = ("action", "type", "tag", "self_id", "parent_id", "bsc_id", "repository_id", - "peer_contact_uri", "sia_base", "sender_name", "recipient_name") - elements = ("cms_ta", "https_ta") - booleans = ("rekey", "reissue", "revoke") - - sql_template = rpki.sql.template("parent", "parent_id", "self_id", "bsc_id", "repository_id", - ("cms_ta", rpki.x509.X509), ("https_ta", rpki.x509.X509), - "peer_contact_uri", "sia_base", "sender_name", "recipient_name") - - cms_ta = None - https_ta = None - - def repository(self, gctx): - """Fetch repository object to which this parent object links.""" - return repository_elt.sql_fetch(gctx, self.repository_id) - - def cas(self, gctx): - """Fetch all CA objects that link to this parent object.""" - return rpki.sql.ca_obj.sql_fetch_where(gctx, "parent_id = %s", (self.parent_id,)) - - def serve_post_save_hook(self, gctx, q_pdu, r_pdu): - """Extra server actions for parent_elt.""" - if q_pdu.rekey: - self.serve_rekey(gctx) - if q_pdu.revoke: - self.serve_revoke(gctx) - self.unimplemented_control("reissue") - - def serve_rekey(self, gctx): - """Handle a left-right rekey action for this parent.""" - for ca in self.cas(gctx): - ca.rekey(gctx) - - def serve_revoke(self, gctx): - """Handle a left-right revoke action for this parent.""" - for ca in self.cas(gctx): - ca.revoke(gctx) - - def startElement(self, stack, name, attrs): - """Handle <parent/> element.""" - if name not in ("cms_ta", "https_ta"): - assert name == "parent", "Unexpected name %s, stack %s" % (name, stack) - self.read_attrs(attrs) - - def endElement(self, stack, name, text): - """Handle <parent/> element.""" - if name == "cms_ta": - self.cms_ta = rpki.x509.X509(Base64 = text) - elif name == "https_ta": - self.https_ta = rpki.x509.X509(Base64 = text) - else: - assert name == "parent", "Unexpected name %s, stack %s" % (name, stack) - stack.pop() - - def toXML(self): - """Generate <parent/> element.""" - elt = self.make_elt() - if self.cms_ta and not self.cms_ta.empty(): - self.make_b64elt(elt, "cms_ta", self.cms_ta.get_DER()) - if self.https_ta and not self.https_ta.empty(): - self.make_b64elt(elt, "https_ta", self.https_ta.get_DER()) - return elt - - def query_up_down(self, gctx, q_pdu): - """Client code for sending one up-down query PDU to this parent. - - I haven't figured out yet whether this method should do something - clever like dispatching via a method in the response PDU payload, - or just hand back the whole response to the caller. In the long - run this will have to become event driven with a context object - that has methods of its own, but as this method is common code for - several different queries and I don't yet know what the response - processing looks like, it's too soon to tell what will make sense. - - For now, keep this dead simple lock step, rewrite it later. - """ - - rpki.log.trace() - - bsc = self.bsc(gctx) - if bsc is None: - raise rpki.exceptions.BSCNotFound, "Could not find BSC %s" % self.bsc_id - q_msg = rpki.up_down.message_pdu.make_query( - payload = q_pdu, - sender = self.sender_name, - recipient = self.recipient_name) - q_elt = q_msg.toXML() - try: - rpki.relaxng.up_down.assertValid(q_elt) - except lxml.etree.DocumentInvalid: - rpki.log.error("Message does not pass schema check: " + lxml.etree.tostring(q_elt, pretty_print = True)) - raise - q_cms = rpki.cms.xml_sign(q_elt, bsc.private_key_id, bsc.signing_cert, encoding = "UTF-8") - r_cms = rpki.https.client(x509TrustList = rpki.x509.X509_chain(self.https_ta), - privateKey = gctx.https_key, - certChain = gctx.https_certs, - msg = q_cms, - url = self.peer_contact_uri) - r_elt = rpki.cms.xml_verify(r_cms, self.cms_ta) - rpki.relaxng.up_down.assertValid(r_elt) - r_msg = rpki.up_down.sax_handler.saxify(r_elt) - r_msg.payload.check_response() - return r_msg - - -class child_elt(data_elt): - """<child/> element.""" - - element_name = "child" - attributes = ("action", "type", "tag", "self_id", "child_id", "bsc_id") - elements = ("cms_ta",) - booleans = ("reissue", ) - - sql_template = rpki.sql.template("child", "child_id", "self_id", "bsc_id", ("cms_ta", rpki.x509.X509)) - - cms_ta = None - - def child_certs(self, gctx, ca_detail = None, ski = None, revoked = False, unique = False): - """Fetch all child_cert objects that link to this child object.""" - return rpki.sql.child_cert_obj.fetch(gctx, self, ca_detail, ski, revoked, unique) - - def parents(self, gctx): - """Fetch all parent objects that link to self object to which this child object links.""" - return parent_elt.sql_fetch_where(gctx, "self_id = %s", (self.self_id,)) - - def ca_from_class_name(self, gctx, class_name): - """Fetch the CA corresponding to an up-down class_name.""" - if not class_name.isdigit(): - raise rpki.exceptions.BadClassNameSyntax, "Bad class name %s" % class_name - ca = rpki.sql.ca_obj.sql_fetch(gctx, long(class_name)) - parent = ca.parent(gctx) - if self.self_id != parent.self_id: - raise rpki.exceptions.ClassNameMismatch, "child.self_id = %d, parent.self_id = %d" % (self.self_id, parent.self_id) - return ca - - def serve_post_save_hook(self, gctx, q_pdu, r_pdu): - """Extra server actions for child_elt.""" - self.unimplemented_control("reissue") - - def startElement(self, stack, name, attrs): - """Handle <child/> element.""" - if name != "cms_ta": - assert name == "child", "Unexpected name %s, stack %s" % (name, stack) - self.read_attrs(attrs) - - def endElement(self, stack, name, text): - """Handle <child/> element.""" - if name == "cms_ta": - self.cms_ta = rpki.x509.X509(Base64 = text) - else: - assert name == "child", "Unexpected name %s, stack %s" % (name, stack) - stack.pop() - - def toXML(self): - """Generate <child/> element.""" - elt = self.make_elt() - if self.cms_ta: - self.make_b64elt(elt, "cms_ta", self.cms_ta.get_DER()) - return elt - - def serve_up_down(self, gctx, query): - """Outer layer of server handling for one up-down PDU from this child.""" - - rpki.log.trace() - - bsc = self.bsc(gctx) - if bsc is None: - raise rpki.exceptions.BSCNotFound, "Could not find BSC %s" % self.bsc_id - q_elt = rpki.cms.xml_verify(query, self.cms_ta) - rpki.relaxng.up_down.assertValid(q_elt) - q_msg = rpki.up_down.sax_handler.saxify(q_elt) - #if q_msg.sender != str(self.child_id): - # raise rpki.exceptions.BadSender, "Unexpected XML sender %s" % q_msg.sender - try: - r_msg = q_msg.serve_top_level(gctx, self) - except Exception, data: - rpki.log.error(traceback.format_exc()) - r_msg = q_msg.serve_error(data) - # - # Exceptions from this point on are problematic, as we have no - # sane way of reporting errors in the error reporting mechanism. - # May require refactoring, ignore the issue for now. - # - r_elt = r_msg.toXML() - try: - rpki.relaxng.up_down.assertValid(r_elt) - except: - rpki.log.debug(lxml.etree.tostring(r_elt, pretty_print = True, encoding = "UTF-8")) - rpki.log.error(traceback.format_exc()) - raise - return rpki.cms.xml_sign(r_elt, bsc.private_key_id, bsc.signing_cert, encoding = "UTF-8") - -class repository_elt(data_elt): - """<repository/> element.""" - - element_name = "repository" - attributes = ("action", "type", "tag", "self_id", "repository_id", "bsc_id", "peer_contact_uri") - elements = ("cms_ta", "https_ta") - - sql_template = rpki.sql.template("repository", "repository_id", "self_id", "bsc_id", - ("cms_ta", rpki.x509.X509), "peer_contact_uri", - ("https_ta", rpki.x509.X509)) - - cms_ta = None - https_ta = None - - def parents(self, gctx): - """Fetch all parent objects that link to this repository object.""" - return parent_elt.sql_fetch_where(gctx, "repository_id = %s", (self.repository_id,)) - - def startElement(self, stack, name, attrs): - """Handle <repository/> element.""" - if name not in ("cms_ta", "https_ta"): - assert name == "repository", "Unexpected name %s, stack %s" % (name, stack) - self.read_attrs(attrs) - - def endElement(self, stack, name, text): - """Handle <repository/> element.""" - if name == "cms_ta": - self.cms_ta = rpki.x509.X509(Base64 = text) - elif name == "https_ta": - self.https_ta = rpki.x509.X509(Base64 = text) - else: - assert name == "repository", "Unexpected name %s, stack %s" % (name, stack) - stack.pop() - - def toXML(self): - """Generate <repository/> element.""" - elt = self.make_elt() - if self.cms_ta: - self.make_b64elt(elt, "cms_ta", self.cms_ta.get_DER()) - if self.https_ta: - self.make_b64elt(elt, "https_ta", self.https_ta.get_DER()) - return elt - - @staticmethod - def uri_to_filename(base, uri): - """Convert a URI to a filename. [TEMPORARY]""" - if not uri.startswith("rsync://"): - raise rpki.exceptions.BadURISyntax - filename = base + uri[len("rsync://"):] - if filename.find("//") >= 0 or filename.find("/../") >= 0 or filename.endswith("/.."): - raise rpki.exceptions.BadURISyntax - return filename - - @classmethod - def object_write(cls, base, uri, obj): - """Write an object to disk. [TEMPORARY]""" - rpki.log.trace() - filename = cls.uri_to_filename(base, uri) - dirname = os.path.dirname(filename) - if not os.path.isdir(dirname): - os.makedirs(dirname) - f = open(filename, "wb") - f.write(obj.get_DER()) - f.close() - - @classmethod - def object_delete(cls, base, uri): - """Delete an object from disk. [TEMPORARY]""" - rpki.log.trace() - os.remove(cls.uri_to_filename(base, uri)) - - def publish(self, gctx, obj, uri): - """Placeholder for publication operation. [TEMPORARY]""" - rpki.log.trace() - rpki.log.info("Publishing %s to repository %s at %s" % (repr(obj), repr(self), repr(uri))) - self.object_write(gctx.publication_kludge_base, uri, obj) - - def withdraw(self, gctx, obj, uri): - """Placeholder for publication withdrawal operation. [TEMPORARY]""" - rpki.log.trace() - rpki.log.info("Withdrawing %s from repository %s at %s" % (repr(obj), repr(self), repr(uri))) - self.object_delete(gctx.publication_kludge_base, uri) - -class route_origin_elt(data_elt): - """<route_origin/> element.""" - - element_name = "route_origin" - attributes = ("action", "type", "tag", "self_id", "route_origin_id", "as_number", "ipv4", "ipv6") - booleans = ("suppress_publication",) - - sql_template = rpki.sql.template("route_origin", "route_origin_id", "self_id", "as_number", - "ca_detail_id", "roa") - - ca_detail_id = None - roa = None - - def sql_fetch_hook(self, gctx): - """Extra SQL fetch actions for route_origin_elt -- handle address ranges.""" - self.ipv4 = rpki.resource_set.resource_set_ipv4.from_sql(gctx.cur, """ - SELECT start_ip, end_ip FROM route_origin_range - WHERE route_origin_id = %s AND start_ip NOT LIKE '%:%' - """, (self.route_origin_id,)) - self.ipv6 = rpki.resource_set.resource_set_ipv6.from_sql(gctx.cur, """ - SELECT start_ip, end_ip FROM route_origin_range - WHERE route_origin_id = %s AND start_ip LIKE '%:%' - """, (self.route_origin_id,)) - - def sql_insert_hook(self, gctx): - """Extra SQL insert actions for route_origin_elt -- handle address ranges.""" - if self.ipv4 + self.ipv6: - gctx.cur.executemany(""" - INSERT route_origin_range (route_origin_id, start_ip, end_ip) - VALUES (%s, %s, %s)""", - ((self.route_origin_id, x.min, x.max) for x in self.ipv4 + self.ipv6)) - - def sql_delete_hook(self, gctx): - """Extra SQL delete actions for route_origin_elt -- handle address ranges.""" - gctx.cur.execute("DELETE FROM route_origin_range WHERE route_origin_id = %s", (self.route_origin_id,)) - - def ca_detail(self, gctx): - """Fetch all ca_detail objects that link to this route_origin object.""" - return rpki.sql.ca_detail_obj.sql_fetch(gctx, self.ca_detail_id) - - def serve_post_save_hook(self, gctx, q_pdu, r_pdu): - """Extra server actions for route_origin_elt.""" - self.unimplemented_control("suppress_publication") - - def startElement(self, stack, name, attrs): - """Handle <route_origin/> element.""" - assert name == "route_origin", "Unexpected name %s, stack %s" % (name, stack) - self.read_attrs(attrs) - if self.as_number is not None: - self.as_number = long(self.as_number) - if self.ipv4 is not None: - self.ipv4 = rpki.resource_set.resource_set_ipv4(self.ipv4) - if self.ipv6 is not None: - self.ipv6 = rpki.resource_set.resource_set_ipv6(self.ipv4) - - def endElement(self, stack, name, text): - """Handle <route_origin/> element.""" - assert name == "route_origin", "Unexpected name %s, stack %s" % (name, stack) - stack.pop() - - def toXML(self): - """Generate <route_origin/> element.""" - return self.make_elt() - -class list_resources_elt(base_elt): - """<list_resources/> element.""" - - element_name = "list_resources" - attributes = ("type", "self_id", "tag", "child_id", "valid_until", "as", "ipv4", "ipv6", "subject_name") - valid_until = None - - def startElement(self, stack, name, attrs): - """Handle <list_resources/> element.""" - assert name == "list_resources", "Unexpected name %s, stack %s" % (name, stack) - self.read_attrs(attrs) - if isinstance(self.valid_until, str): - self.valid_until = rpki.sundial.datetime.fromXMLtime(self.valid_until) - if self.as is not None: - self.as = rpki.resource_set.resource_set_as(self.as) - if self.ipv4 is not None: - self.ipv4 = rpki.resource_set.resource_set_ipv4(self.ipv4) - if self.ipv6 is not None: - self.ipv6 = rpki.resource_set.resource_set_ipv6(self.ipv6) - - def toXML(self): - """Generate <list_resources/> element.""" - elt = self.make_elt() - if isinstance(self.valid_until, int): - elt.set("valid_until", self.valid_until.toXMLtime()) - return elt - -class report_error_elt(base_elt): - """<report_error/> element.""" - - element_name = "report_error" - attributes = ("tag", "self_id", "error_code") - - def startElement(self, stack, name, attrs): - """Handle <report_error/> element.""" - assert name == self.element_name, "Unexpected name %s, stack %s" % (name, stack) - self.read_attrs(attrs) - - def toXML(self): - """Generate <report_error/> element.""" - return self.make_elt() - - @classmethod - def from_exception(cls, exc, self_id = None): - """Generate a <report_error/> element from an exception.""" - self = cls() - self.self_id = self_id - self.error_code = exc.__class__.__name__ - return self - -class msg(list): - """Left-right PDU.""" - - ## @var version - # Protocol version - version = 1 - - ## @var pdus - # Dispatch table of PDUs for this protocol. - pdus = dict((x.element_name, x) - for x in (self_elt, child_elt, parent_elt, bsc_elt, repository_elt, - route_origin_elt, list_resources_elt, report_error_elt)) - - def startElement(self, stack, name, attrs): - """Handle left-right PDU.""" - if name == "msg": - assert self.version == int(attrs["version"]) - else: - elt = self.pdus[name]() - self.append(elt) - stack.append(elt) - elt.startElement(stack, name, attrs) - - def endElement(self, stack, name, text): - """Handle left-right PDU.""" - assert name == "msg", "Unexpected name %s, stack %s" % (name, stack) - assert len(stack) == 1 - stack.pop() - - def __str__(self): - """Convert msg object to string.""" - lxml.etree.tostring(self.toXML(), pretty_print = True, encoding = "us-ascii") - - def toXML(self): - """Generate left-right PDU.""" - elt = lxml.etree.Element("{%s}msg" % (xmlns), nsmap = nsmap, version = str(self.version)) - elt.extend([i.toXML() for i in self]) - return elt - - def serve_top_level(self, gctx): - """Serve one msg PDU.""" - r_msg = self.__class__() - for q_pdu in self: - q_pdu.serve_dispatch(gctx, r_msg) - return r_msg - -class sax_handler(rpki.sax_utils.handler): - """SAX handler for Left-Right protocol.""" - - ## @var pdu - # Top-level PDU class - pdu = msg - - def create_top_level(self, name, attrs): - """Top-level PDU for this protocol is <msg/>.""" - assert name == "msg" and attrs["version"] == "1" - return self.pdu() - -def irdb_query(gctx, self_id, child_id = None): - """Perform an IRDB callback query. In the long run this should not - be a blocking routine, it should instead issue a query and set up a - handler to receive the response. For the moment, though, we are - doing simple lock step and damn the torpedos. Not yet doing - anything useful with subject name. Most likely this function should - really be wrapped up in a class that carries both the query result - and also the intermediate state needed for the event-driven code - that this function will need to become. - """ - - rpki.log.trace() - - q_msg = msg() - q_msg.append(list_resources_elt()) - q_msg[0].type = "query" - q_msg[0].self_id = self_id - q_msg[0].child_id = child_id - q_elt = q_msg.toXML() - rpki.relaxng.left_right.assertValid(q_elt) - q_cms = rpki.cms.xml_sign(q_elt, gctx.cms_key, gctx.cms_certs) - r_cms = rpki.https.client( - privateKey = gctx.https_key, - certChain = gctx.https_certs, - x509TrustList = gctx.https_ta, - url = gctx.irdb_url, - msg = q_cms) - r_elt = rpki.cms.xml_verify(r_cms, gctx.cms_ta_irdb) - rpki.relaxng.left_right.assertValid(r_elt) - r_msg = rpki.left_right.sax_handler.saxify(r_elt) - if len(r_msg) == 0 or not isinstance(r_msg[0], list_resources_elt) or r_msg[0].type != "reply": - raise rpki.exceptions.BadIRDBReply, "Unexpected response to IRDB query: %s" % lxml.etree.tostring(r_msg.toXML(), pretty_print = True, encoding = "us-ascii") - return rpki.resource_set.resource_bag( - as = r_msg[0].as, - v4 = r_msg[0].ipv4, - v6 = r_msg[0].ipv6, - valid_until = r_msg[0].valid_until) diff --git a/scripts/rpki/log.py b/scripts/rpki/log.py deleted file mode 100644 index 1f85f667..00000000 --- a/scripts/rpki/log.py +++ /dev/null @@ -1,54 +0,0 @@ -# $Id$ - -# Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") -# -# 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 ARIN DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL ARIN 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. - -"""Logging facilities for RPKI libraries. -""" - -import syslog, traceback - -enable_trace = False - -def init(ident = "rpki", flags = syslog.LOG_PID | syslog.LOG_PERROR, facility = syslog.LOG_DAEMON): - """Initialize logging system.""" - - return syslog.openlog(ident, flags, facility) - -def set_trace(trace): - """Enable or disable call tracing.""" - - global enable_trace - enable_trace = trace - -class logger(object): - """Closure for logging.""" - - def __init__(self, priority): - self.priority = priority - - def __call__(self, message): - return syslog.syslog(self.priority, message) - -error = logger(syslog.LOG_ERR) -warn = logger(syslog.LOG_WARNING) -note = logger(syslog.LOG_NOTICE) -info = logger(syslog.LOG_INFO) -debug = logger(syslog.LOG_DEBUG) - -def trace(): - """Execution trace -- where are we now, and whence came we here?""" - if enable_trace: - bt = traceback.extract_stack(limit = 3) - return debug("[%s() at %s:%d from %s:%d]" % (bt[1][2], bt[1][0], bt[1][1], bt[0][0], bt[0][1])) diff --git a/scripts/rpki/manifest.py b/scripts/rpki/manifest.py deleted file mode 100644 index c219cc8f..00000000 --- a/scripts/rpki/manifest.py +++ /dev/null @@ -1,53 +0,0 @@ -# $Id$ - -# Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") -# -# 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 ARIN DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL ARIN 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. - -"""Signed manifests. This is just the ASN.1 encoder, the rest is in -rpki.x509 with the rest of the DER_object code. - -Note that rpki.x509.SignedManifest implements the signed manifest; -the structures here are just the payload of the CMS eContent field. -""" - -from POW._der import * - -class FileAndHash(Sequence): - def __init__(self, optional=0, default=''): - self.file = IA5String() - self.hash = AltBitString() - contents = [ self.file, self.hash ] - Sequence.__init__(self, contents, optional, default) - -class FilesAndHashes(SequenceOf): - def __init__(self, optional=0, default=''): - SequenceOf.__init__(self, FileAndHash, optional, default) - -class Manifest(Sequence): - def __init__(self, optional=0, default=''): - self.version = Integer() - self.explicitVersion = Explicit(CLASS_CONTEXT, FORM_CONSTRUCTED, 0, self.version, 0, 'oAMCAQA=') - self.manifestNumber = Integer() - self.thisUpdate = GeneralizedTime() - self.nextUpdate = GeneralizedTime() - self.fileHashAlg = Oid() - self.fileList = FilesAndHashes() - - contents = [ self.explicitVersion, - self.manifestNumber, - self.thisUpdate, - self.nextUpdate, - self.fileHashAlg, - self.fileList ] - Sequence.__init__(self, contents, optional, default) diff --git a/scripts/rpki/oids.py b/scripts/rpki/oids.py deleted file mode 100644 index 4e08aef7..00000000 --- a/scripts/rpki/oids.py +++ /dev/null @@ -1,49 +0,0 @@ -# $Id$ - -# Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") -# -# 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 ARIN DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL ARIN 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. - -"""OID database.""" - -## @var oid2name -# Mapping table of OIDs to conventional string names. - -oid2name = { - (1, 2, 840, 113549, 1, 1, 11) : "sha256WithRSAEncryption", - (1, 2, 840, 113549, 1, 1, 12) : "sha384WithRSAEncryption", - (1, 2, 840, 113549, 1, 1, 13) : "sha512WithRSAEncryption", - (1, 3, 6, 1, 5, 5, 7, 1, 1) : "authorityInfoAccess", - (1, 3, 6, 1, 5, 5, 7, 1, 11) : "subjectInfoAccess", - (1, 3, 6, 1, 5, 5, 7, 1, 7) : "sbgp-ipAddrBlock", - (1, 3, 6, 1, 5, 5, 7, 1, 8) : "sbgp-autonomousSysNum", - (1, 3, 6, 1, 5, 5, 7, 14, 2) : "id-cp-ipAddr-asNumber", - (1, 3, 6, 1, 5, 5, 7, 48, 2) : "id-ad-caIssuers", - (1, 3, 6, 1, 5, 5, 7, 48, 5) : "id-ad-caRepository", - (1, 3, 6, 1, 5, 5, 7, 48, 9) : "id-ad-signedObjectRepository", - (1, 3, 6, 1, 5, 5, 7, 48, 10) : "id-ad-rpkiManifest", - (1, 3, 6, 1, 5, 5, 7, 48, 11) : "id-ad-signedObject", - (2, 5, 29, 14) : "subjectKeyIdentifier", - (2, 5, 29, 15) : "keyUsage", - (2, 5, 29, 19) : "basicConstraints", - (2, 5, 29, 20) : "cRLNumber", - (2, 5, 29, 31) : "cRLDistributionPoints", - (2, 5, 29, 32) : "certificatePolicies", - (2, 5, 29, 35) : "authorityKeyIdentifier", - (2, 5, 4, 3) : "commonName", -} - -## @var name2oid -# Mapping table of string names to OIDs - -name2oid = dict((v,k) for k,v in oid2name.items()) diff --git a/scripts/rpki/pkcs10.py b/scripts/rpki/pkcs10.py deleted file mode 100644 index 9ed38470..00000000 --- a/scripts/rpki/pkcs10.py +++ /dev/null @@ -1,62 +0,0 @@ -# $Id$ - -# Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") -# -# 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 ARIN DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL ARIN 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. - -"""Old code to generate PKCS #10 certification requests. - -This has been replaced by direct support for PKCS #10 in my hacked -version of the POW package. This module will go away eventually, I'm -just keeping it around in case I discover some horrible bug in the new -code that would make me want to fall back to this. -""" - -raise NotImplementedError, "You shouldn't be using this module anymore, see rpki.x509.PKCS10" - -import POW, rpki.x509, os, rpki.exceptions, binascii - -req_fmt = ''' -[ req ] -distinguished_name = req_dn -default_md = sha256 -prompt = no - -[ req_dn ] -CN = %s -''' - -def make_request(keypair): - """Generate a PKCS #10 request.""" - - digest = POW.Digest(POW.SHA1_DIGEST) - digest.update(keypair.get_POW().derWrite(POW.RSA_PUBLIC_KEY)) - commonName = "0x" + binascii.hexlify(digest.digest()) - - try: - config_filename = "req.tmp.conf" - f = open(config_filename, "w") - f.write(req_fmt % commonName) - f.close() - - i,o = os.popen2(["openssl", "req", "-config", config_filename, "-new", - "-key", "/dev/stdin", "-outform", "DER"]) - i.write(keypair.get_PEM()) - i.close() - pkcs10 = rpki.x509.PKCS10(DER = o.read()) - o.close() - - finally: - os.unlink(config_filename) - - return pkcs10 diff --git a/scripts/rpki/relaxng.py b/scripts/rpki/relaxng.py deleted file mode 100644 index b045b1c6..00000000 --- a/scripts/rpki/relaxng.py +++ /dev/null @@ -1,1208 +0,0 @@ -# Automatically generated, do not edit. - -import lxml.etree - -## @var left_right -## Parsed RelaxNG left_right schema -left_right = lxml.etree.RelaxNG(lxml.etree.fromstring('''<?xml version="1.0" encoding="UTF-8"?> -<!-- - $Id: left-right-schema.rnc 1383 2007-12-17 18:20:46Z sra $ - - RelaxNG (Compact Syntax) Schema for RPKI left-right protocol. - - libxml2 (including xmllint) only groks the XML syntax of RelaxNG, so - run the compact syntax through trang to get XML syntax. ---> -<grammar ns="http://www.hactrn.net/uris/rpki/left-right-spec/" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> - <!-- Top level PDU --> - <start> - <element name="msg"> - <attribute name="version"> - <data type="positiveInteger"> - <param name="maxInclusive">1</param> - </data> - </attribute> - <zeroOrMore> - <choice> - <ref name="self_elt"/> - <ref name="bsc_elt"/> - <ref name="parent_elt"/> - <ref name="child_elt"/> - <ref name="repository_elt"/> - <ref name="ro_elt"/> - <ref name="list_resources_elt"/> - <ref name="report_error_elt"/> - </choice> - </zeroOrMore> - </element> - </start> - <!-- Tag attributes for bulk operations --> - <define name="tag"> - <optional> - <attribute name="tag"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - </optional> - </define> - <!-- - Combinations of action and type attributes used in later definitions. - The same patterns repeat in most of the elements in this protocol. - --> - <define name="ctl_cq"> - <attribute name="action"> - <value>create</value> - </attribute> - <attribute name="type"> - <value>query</value> - </attribute> - <ref name="tag"/> - </define> - <define name="ctl_sq"> - <attribute name="action"> - <value>set</value> - </attribute> - <attribute name="type"> - <value>query</value> - </attribute> - <ref name="tag"/> - </define> - <define name="ctl_gq"> - <attribute name="action"> - <value>get</value> - </attribute> - <attribute name="type"> - <value>query</value> - </attribute> - <ref name="tag"/> - </define> - <define name="ctl_lq"> - <attribute name="action"> - <value>list</value> - </attribute> - <attribute name="type"> - <value>query</value> - </attribute> - <ref name="tag"/> - </define> - <define name="ctl_dq"> - <attribute name="action"> - <value>destroy</value> - </attribute> - <attribute name="type"> - <value>query</value> - </attribute> - <ref name="tag"/> - </define> - <define name="ctl_cr"> - <attribute name="action"> - <value>create</value> - </attribute> - <attribute name="type"> - <value>reply</value> - </attribute> - <ref name="tag"/> - </define> - <define name="ctl_sr"> - <attribute name="action"> - <value>set</value> - </attribute> - <attribute name="type"> - <value>reply</value> - </attribute> - <ref name="tag"/> - </define> - <define name="ctl_gr"> - <attribute name="action"> - <value>get</value> - </attribute> - <attribute name="type"> - <value>reply</value> - </attribute> - <ref name="tag"/> - </define> - <define name="ctl_lr"> - <attribute name="action"> - <value>list</value> - </attribute> - <attribute name="type"> - <value>reply</value> - </attribute> - <ref name="tag"/> - </define> - <define name="ctl_dr"> - <attribute name="action"> - <value>destroy</value> - </attribute> - <attribute name="type"> - <value>reply</value> - </attribute> - <ref name="tag"/> - </define> - <!-- Base64 encoded DER stuff --> - <define name="base64"> - <data type="base64Binary"> - <param name="maxLength">512000</param> - </data> - </define> - <!-- How we wrap trust anchor elements --> - <define name="cms_ta"> - <element name="cms_ta"> - <ref name="base64"/> - </element> - </define> - <define name="https_ta"> - <element name="https_ta"> - <ref name="base64"/> - </element> - </define> - <!-- Base definition for all fields that are really just SQL primary indices --> - <define name="sql_id"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </define> - <!-- <self/> element --> - <define name="self_bool"> - <optional> - <attribute name="rekey"> - <value>yes</value> - </attribute> - </optional> - <optional> - <attribute name="reissue"> - <value>yes</value> - </attribute> - </optional> - <optional> - <attribute name="revoke"> - <value>yes</value> - </attribute> - </optional> - <optional> - <attribute name="run_now"> - <value>yes</value> - </attribute> - </optional> - <optional> - <attribute name="publish_world_now"> - <value>yes</value> - </attribute> - </optional> - <optional> - <attribute name="clear_extension_preferences"> - <value>yes</value> - </attribute> - </optional> - </define> - <define name="self_payload"> - <optional> - <attribute name="use_hsm"> - <choice> - <value>yes</value> - <value>no</value> - </choice> - </attribute> - </optional> - <optional> - <attribute name="crl_interval"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - </optional> - <zeroOrMore> - <element name="extension_preference"> - <attribute name="name"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - <data type="string"> - <param name="maxLength">512000</param> - </data> - </element> - </zeroOrMore> - </define> - <define name="self_id"> - <attribute name="self_id"> - <ref name="sql_id"/> - </attribute> - </define> - <define name="self_elt" combine="choice"> - <element name="self"> - <ref name="ctl_cq"/> - <ref name="self_bool"/> - <ref name="self_payload"/> - </element> - </define> - <define name="self_elt" combine="choice"> - <element name="self"> - <ref name="ctl_cr"/> - <ref name="self_id"/> - </element> - </define> - <define name="self_elt" combine="choice"> - <element name="self"> - <ref name="ctl_sq"/> - <ref name="self_id"/> - <ref name="self_bool"/> - <ref name="self_payload"/> - </element> - </define> - <define name="self_elt" combine="choice"> - <element name="self"> - <ref name="ctl_sr"/> - <ref name="self_id"/> - </element> - </define> - <define name="self_elt" combine="choice"> - <element name="self"> - <ref name="ctl_gq"/> - <ref name="self_id"/> - </element> - </define> - <define name="self_elt" combine="choice"> - <element name="self"> - <ref name="ctl_gr"/> - <ref name="self_id"/> - <ref name="self_payload"/> - </element> - </define> - <define name="self_elt" combine="choice"> - <element name="self"> - <ref name="ctl_lq"/> - </element> - </define> - <define name="self_elt" combine="choice"> - <element name="self"> - <ref name="ctl_lr"/> - <ref name="self_id"/> - <ref name="self_payload"/> - </element> - </define> - <define name="self_elt" combine="choice"> - <element name="self"> - <ref name="ctl_dq"/> - <ref name="self_id"/> - </element> - </define> - <define name="self_elt" combine="choice"> - <element name="self"> - <ref name="ctl_dr"/> - <ref name="self_id"/> - </element> - </define> - <!-- <bsc/> element. Key parameters hardwired for now. --> - <define name="bsc_bool"> - <optional> - <attribute name="generate_keypair"> - <value>yes</value> - </attribute> - <optional> - <attribute name="key_type"> - <value>rsa</value> - </attribute> - </optional> - <optional> - <attribute name="hash_alg"> - <value>sha256</value> - </attribute> - </optional> - <optional> - <attribute name="key_length"> - <value>2048</value> - </attribute> - </optional> - </optional> - <optional> - <attribute name="clear_signing_certs"> - <value>yes</value> - </attribute> - </optional> - </define> - <define name="bsc_id"> - <attribute name="bsc_id"> - <ref name="sql_id"/> - </attribute> - </define> - <define name="bsc_payload"> - <zeroOrMore> - <element name="signing_cert"> - <ref name="base64"/> - </element> - </zeroOrMore> - <optional> - <element name="public_key"> - <ref name="base64"/> - </element> - </optional> - </define> - <define name="bsc_pkcs10"> - <optional> - <element name="pkcs10_cert_request"> - <ref name="base64"/> - </element> - </optional> - </define> - <define name="bsc_elt" combine="choice"> - <element name="bsc"> - <ref name="ctl_cq"/> - <ref name="self_id"/> - <ref name="bsc_bool"/> - <ref name="bsc_payload"/> - </element> - </define> - <define name="bsc_elt" combine="choice"> - <element name="bsc"> - <ref name="ctl_cr"/> - <ref name="self_id"/> - <ref name="bsc_id"/> - <ref name="bsc_pkcs10"/> - </element> - </define> - <define name="bsc_elt" combine="choice"> - <element name="bsc"> - <ref name="ctl_sq"/> - <ref name="self_id"/> - <ref name="bsc_id"/> - <ref name="bsc_bool"/> - <ref name="bsc_payload"/> - </element> - </define> - <define name="bsc_elt" combine="choice"> - <element name="bsc"> - <ref name="ctl_sr"/> - <ref name="self_id"/> - <ref name="bsc_id"/> - <ref name="bsc_pkcs10"/> - </element> - </define> - <define name="bsc_elt" combine="choice"> - <element name="bsc"> - <ref name="ctl_gq"/> - <ref name="self_id"/> - <ref name="bsc_id"/> - </element> - </define> - <define name="bsc_elt" combine="choice"> - <element name="bsc"> - <ref name="ctl_gr"/> - <ref name="self_id"/> - <ref name="bsc_id"/> - <ref name="bsc_payload"/> - </element> - </define> - <define name="bsc_elt" combine="choice"> - <element name="bsc"> - <ref name="ctl_lq"/> - <ref name="self_id"/> - </element> - </define> - <define name="bsc_elt" combine="choice"> - <element name="bsc"> - <ref name="ctl_lr"/> - <ref name="self_id"/> - <ref name="bsc_id"/> - <ref name="bsc_payload"/> - </element> - </define> - <define name="bsc_elt" combine="choice"> - <element name="bsc"> - <ref name="ctl_dq"/> - <ref name="self_id"/> - <ref name="bsc_id"/> - </element> - </define> - <define name="bsc_elt" combine="choice"> - <element name="bsc"> - <ref name="ctl_dr"/> - <ref name="self_id"/> - <ref name="bsc_id"/> - </element> - </define> - <!-- <parent/> element --> - <define name="parent_id"> - <attribute name="parent_id"> - <ref name="sql_id"/> - </attribute> - </define> - <define name="parent_bool"> - <optional> - <attribute name="rekey"> - <value>yes</value> - </attribute> - </optional> - <optional> - <attribute name="reissue"> - <value>yes</value> - </attribute> - </optional> - <optional> - <attribute name="revoke"> - <value>yes</value> - </attribute> - </optional> - </define> - <define name="parent_payload"> - <optional> - <attribute name="peer_contact_uri"> - <data type="anyURI"> - <param name="maxLength">1024</param> - </data> - </attribute> - </optional> - <optional> - <attribute name="sia_base"> - <data type="anyURI"> - <param name="maxLength">1024</param> - </data> - </attribute> - </optional> - <optional> - <attribute name="bsc_id"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - </optional> - <optional> - <attribute name="repository_id"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - </optional> - <optional> - <attribute name="sender_name"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - </optional> - <optional> - <attribute name="recipient_name"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - </optional> - <optional> - <ref name="cms_ta"/> - </optional> - <optional> - <ref name="https_ta"/> - </optional> - </define> - <define name="parent_elt" combine="choice"> - <element name="parent"> - <ref name="ctl_cq"/> - <ref name="self_id"/> - <ref name="parent_bool"/> - <ref name="parent_payload"/> - </element> - </define> - <define name="parent_elt" combine="choice"> - <element name="parent"> - <ref name="ctl_cr"/> - <ref name="self_id"/> - <ref name="parent_id"/> - </element> - </define> - <define name="parent_elt" combine="choice"> - <element name="parent"> - <ref name="ctl_sq"/> - <ref name="self_id"/> - <ref name="parent_id"/> - <ref name="parent_bool"/> - <ref name="parent_payload"/> - </element> - </define> - <define name="parent_elt" combine="choice"> - <element name="parent"> - <ref name="ctl_sr"/> - <ref name="self_id"/> - <ref name="parent_id"/> - </element> - </define> - <define name="parent_elt" combine="choice"> - <element name="parent"> - <ref name="ctl_gq"/> - <ref name="self_id"/> - <ref name="parent_id"/> - </element> - </define> - <define name="parent_elt" combine="choice"> - <element name="parent"> - <ref name="ctl_gr"/> - <ref name="self_id"/> - <ref name="parent_id"/> - <ref name="parent_payload"/> - </element> - </define> - <define name="parent_elt" combine="choice"> - <element name="parent"> - <ref name="ctl_lq"/> - <ref name="self_id"/> - </element> - </define> - <define name="parent_elt" combine="choice"> - <element name="parent"> - <ref name="ctl_lr"/> - <ref name="self_id"/> - <ref name="parent_id"/> - <ref name="parent_payload"/> - </element> - </define> - <define name="parent_elt" combine="choice"> - <element name="parent"> - <ref name="ctl_dq"/> - <ref name="self_id"/> - <ref name="parent_id"/> - </element> - </define> - <define name="parent_elt" combine="choice"> - <element name="parent"> - <ref name="ctl_dr"/> - <ref name="self_id"/> - <ref name="parent_id"/> - </element> - </define> - <!-- <child/> element --> - <define name="child_id"> - <attribute name="child_id"> - <ref name="sql_id"/> - </attribute> - </define> - <define name="child_bool"> - <optional> - <attribute name="reissue"> - <value>yes</value> - </attribute> - </optional> - </define> - <define name="child_payload"> - <optional> - <attribute name="bsc_id"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - </optional> - <optional> - <ref name="cms_ta"/> - </optional> - </define> - <define name="child_elt" combine="choice"> - <element name="child"> - <ref name="ctl_cq"/> - <ref name="self_id"/> - <ref name="child_bool"/> - <ref name="child_payload"/> - </element> - </define> - <define name="child_elt" combine="choice"> - <element name="child"> - <ref name="ctl_cr"/> - <ref name="self_id"/> - <ref name="child_id"/> - </element> - </define> - <define name="child_elt" combine="choice"> - <element name="child"> - <ref name="ctl_sq"/> - <ref name="self_id"/> - <ref name="child_id"/> - <ref name="child_bool"/> - <ref name="child_payload"/> - </element> - </define> - <define name="child_elt" combine="choice"> - <element name="child"> - <ref name="ctl_sr"/> - <ref name="self_id"/> - <ref name="child_id"/> - </element> - </define> - <define name="child_elt" combine="choice"> - <element name="child"> - <ref name="ctl_gq"/> - <ref name="self_id"/> - <ref name="child_id"/> - </element> - </define> - <define name="child_elt" combine="choice"> - <element name="child"> - <ref name="ctl_gr"/> - <ref name="self_id"/> - <ref name="child_id"/> - <ref name="child_payload"/> - </element> - </define> - <define name="child_elt" combine="choice"> - <element name="child"> - <ref name="ctl_lq"/> - <ref name="self_id"/> - </element> - </define> - <define name="child_elt" combine="choice"> - <element name="child"> - <ref name="ctl_lr"/> - <ref name="self_id"/> - <ref name="child_id"/> - <ref name="child_payload"/> - </element> - </define> - <define name="child_elt" combine="choice"> - <element name="child"> - <ref name="ctl_dq"/> - <ref name="self_id"/> - <ref name="child_id"/> - </element> - </define> - <define name="child_elt" combine="choice"> - <element name="child"> - <ref name="ctl_dr"/> - <ref name="self_id"/> - <ref name="child_id"/> - </element> - </define> - <!-- <repository/> element --> - <define name="repository_id"> - <attribute name="repository_id"> - <ref name="sql_id"/> - </attribute> - </define> - <define name="repository_payload"> - <optional> - <attribute name="peer_contact_uri"> - <data type="anyURI"> - <param name="maxLength">1024</param> - </data> - </attribute> - </optional> - <optional> - <attribute name="bsc_id"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - </optional> - <optional> - <ref name="cms_ta"/> - </optional> - <optional> - <ref name="https_ta"/> - </optional> - </define> - <define name="repository_elt" combine="choice"> - <element name="repository"> - <ref name="ctl_cq"/> - <ref name="self_id"/> - <ref name="repository_payload"/> - </element> - </define> - <define name="repository_elt" combine="choice"> - <element name="repository"> - <ref name="ctl_cr"/> - <ref name="self_id"/> - <ref name="repository_id"/> - </element> - </define> - <define name="repository_elt" combine="choice"> - <element name="repository"> - <ref name="ctl_sq"/> - <ref name="self_id"/> - <ref name="repository_id"/> - <ref name="repository_payload"/> - </element> - </define> - <define name="repository_elt" combine="choice"> - <element name="repository"> - <ref name="ctl_sr"/> - <ref name="self_id"/> - <ref name="repository_id"/> - </element> - </define> - <define name="repository_elt" combine="choice"> - <element name="repository"> - <ref name="ctl_gq"/> - <ref name="self_id"/> - <ref name="repository_id"/> - </element> - </define> - <define name="repository_elt" combine="choice"> - <element name="repository"> - <ref name="ctl_gr"/> - <ref name="self_id"/> - <ref name="repository_id"/> - <ref name="repository_payload"/> - </element> - </define> - <define name="repository_elt" combine="choice"> - <element name="repository"> - <ref name="ctl_lq"/> - <ref name="self_id"/> - </element> - </define> - <define name="repository_elt" combine="choice"> - <element name="repository"> - <ref name="ctl_lr"/> - <ref name="self_id"/> - <ref name="repository_id"/> - <ref name="repository_payload"/> - </element> - </define> - <define name="repository_elt" combine="choice"> - <element name="repository"> - <ref name="ctl_dq"/> - <ref name="self_id"/> - <ref name="repository_id"/> - </element> - </define> - <define name="repository_elt" combine="choice"> - <element name="repository"> - <ref name="ctl_dr"/> - <ref name="self_id"/> - <ref name="repository_id"/> - </element> - </define> - <!-- <route_origin/> element --> - <define name="ro_id"> - <attribute name="route_origin_id"> - <ref name="sql_id"/> - </attribute> - </define> - <define name="ro_bool"> - <optional> - <attribute name="suppress_publication"> - <value>yes</value> - </attribute> - </optional> - </define> - <define name="ro_payload"> - <optional> - <attribute name="as_number"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - </optional> - <optional> - <attribute name="ipv4"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - </optional> - <optional> - <attribute name="ipv6"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - </optional> - </define> - <define name="ro_elt" combine="choice"> - <element name="route_origin"> - <ref name="ctl_cq"/> - <ref name="self_id"/> - <ref name="ro_bool"/> - <ref name="ro_payload"/> - </element> - </define> - <define name="ro_elt" combine="choice"> - <element name="route_origin"> - <ref name="ctl_cr"/> - <ref name="self_id"/> - <ref name="ro_id"/> - </element> - </define> - <define name="ro_elt" combine="choice"> - <element name="route_origin"> - <ref name="ctl_sq"/> - <ref name="self_id"/> - <ref name="ro_id"/> - <ref name="ro_bool"/> - <ref name="ro_payload"/> - </element> - </define> - <define name="ro_elt" combine="choice"> - <element name="route_origin"> - <ref name="ctl_sr"/> - <ref name="self_id"/> - <ref name="ro_id"/> - </element> - </define> - <define name="ro_elt" combine="choice"> - <element name="route_origin"> - <ref name="ctl_gq"/> - <ref name="self_id"/> - <ref name="ro_id"/> - </element> - </define> - <define name="ro_elt" combine="choice"> - <element name="route_origin"> - <ref name="ctl_gr"/> - <ref name="self_id"/> - <ref name="ro_id"/> - <ref name="ro_payload"/> - </element> - </define> - <define name="ro_elt" combine="choice"> - <element name="route_origin"> - <ref name="ctl_lq"/> - <ref name="self_id"/> - </element> - </define> - <define name="ro_elt" combine="choice"> - <element name="route_origin"> - <ref name="ctl_lr"/> - <ref name="self_id"/> - <ref name="ro_id"/> - <ref name="ro_payload"/> - </element> - </define> - <define name="ro_elt" combine="choice"> - <element name="route_origin"> - <ref name="ctl_dq"/> - <ref name="self_id"/> - <ref name="ro_id"/> - </element> - </define> - <define name="ro_elt" combine="choice"> - <element name="route_origin"> - <ref name="ctl_dr"/> - <ref name="self_id"/> - <ref name="ro_id"/> - </element> - </define> - <!-- <list_resources/> element --> - <define name="list_resources_elt"> - <element name="list_resources"> - <choice> - <group> - <attribute name="type"> - <value>query</value> - </attribute> - <ref name="tag"/> - <ref name="self_id"/> - <ref name="child_id"/> - </group> - <group> - <attribute name="type"> - <value>reply</value> - </attribute> - <ref name="tag"/> - <ref name="self_id"/> - <ref name="child_id"/> - <attribute name="valid_until"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - <optional> - <attribute name="subject_name"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - </optional> - <optional> - <attribute name="as"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - </optional> - <optional> - <attribute name="ipv4"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - </optional> - <optional> - <attribute name="ipv6"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - </optional> - </group> - </choice> - </element> - </define> - <!-- <report_error/> element --> - <define name="report_error_elt"> - <element name="report_error"> - <ref name="tag"/> - <ref name="self_id"/> - <attribute name="error_code"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - <optional> - <data type="string"> - <param name="maxLength">512000</param> - </data> - </optional> - </element> - </define> -</grammar> -''')) - -## @var up_down -## Parsed RelaxNG up_down schema -up_down = lxml.etree.RelaxNG(lxml.etree.fromstring('''<?xml version="1.0" encoding="UTF-8"?> -<!-- - $Id: up-down-schema.rng 1354 2007-12-04 06:20:10Z sra $ - - RelaxNG (Compact Syntax) Scheme for up-down protocol, extracted - from APNIC Wiki. - - libxml2 (including xmllint) only groks the XML syntax of RelaxNG, - so run this through a converter like /usr/ports/textproc/trang to get - XML syntax: - - $ trang up-down-schema.rnc up-down-schema.rng ---> -<grammar ns="http://www.apnic.net/specs/rescerts/up-down/" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> - <start> - <element name="message"> - <attribute name="version"> - <data type="positiveInteger"> - <param name="maxInclusive">1</param> - </data> - </attribute> - <attribute name="sender"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - <attribute name="recipient"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - <ref name="payload"/> - </element> - </start> - <define name="payload" combine="choice"> - <attribute name="type"> - <value>list</value> - </attribute> - <ref name="list_request"/> - </define> - <define name="payload" combine="choice"> - <attribute name="type"> - <value>list_response</value> - </attribute> - <ref name="list_response"/> - </define> - <define name="payload" combine="choice"> - <attribute name="type"> - <value>issue</value> - </attribute> - <ref name="issue_request"/> - </define> - <define name="payload" combine="choice"> - <attribute name="type"> - <value>issue_response</value> - </attribute> - <ref name="issue_response"/> - </define> - <define name="payload" combine="choice"> - <attribute name="type"> - <value>revoke</value> - </attribute> - <ref name="revoke_request"/> - </define> - <define name="payload" combine="choice"> - <attribute name="type"> - <value>revoke_response</value> - </attribute> - <ref name="revoke_response"/> - </define> - <define name="payload" combine="choice"> - <attribute name="type"> - <value>error_response</value> - </attribute> - <ref name="error_response"/> - </define> - <define name="list_request"> - <empty/> - </define> - <define name="list_response"> - <zeroOrMore> - <ref name="class"/> - </zeroOrMore> - </define> - <define name="class"> - <element name="class"> - <attribute name="class_name"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - <attribute name="cert_url"> - <data type="string"> - <param name="maxLength">4096</param> - </data> - </attribute> - <attribute name="resource_set_as"> - <data type="string"> - <param name="maxLength">512000</param> - <param name="pattern">[\-,0-9]*</param> - </data> - </attribute> - <attribute name="resource_set_ipv4"> - <data type="string"> - <param name="maxLength">512000</param> - <param name="pattern">[\-,/.0-9]*</param> - </data> - </attribute> - <attribute name="resource_set_ipv6"> - <data type="string"> - <param name="maxLength">512000</param> - <param name="pattern">[\-,/:0-9a-fA-F]*</param> - </data> - </attribute> - <optional> - <attribute name="resource_set_notafter"> - <data type="dateTime"> - <param name="pattern">.*Z</param> - </data> - </attribute> - </optional> - <optional> - <attribute name="suggested_sia_head"> - <data type="anyURI"> - <param name="maxLength">1024</param> - <param name="pattern">rsync://.+</param> - </data> - </attribute> - </optional> - <zeroOrMore> - <element name="certificate"> - <attribute name="cert_url"> - <data type="string"> - <param name="maxLength">4096</param> - </data> - </attribute> - <optional> - <attribute name="req_resource_set_as"> - <data type="string"> - <param name="maxLength">512000</param> - <param name="pattern">[\-,0-9]*</param> - </data> - </attribute> - </optional> - <optional> - <attribute name="req_resource_set_ipv4"> - <data type="string"> - <param name="maxLength">512000</param> - <param name="pattern">[\-,/.0-9]*</param> - </data> - </attribute> - </optional> - <optional> - <attribute name="req_resource_set_ipv6"> - <data type="string"> - <param name="maxLength">512000</param> - <param name="pattern">[\-,/:0-9a-fA-F]*</param> - </data> - </attribute> - </optional> - <data type="base64Binary"> - <param name="maxLength">512000</param> - </data> - </element> - </zeroOrMore> - <element name="issuer"> - <data type="base64Binary"> - <param name="maxLength">512000</param> - </data> - </element> - </element> - </define> - <define name="issue_request"> - <element name="request"> - <attribute name="class_name"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - <optional> - <attribute name="req_resource_set_as"> - <data type="string"> - <param name="maxLength">512000</param> - <param name="pattern">[\-,0-9]*</param> - </data> - </attribute> - </optional> - <optional> - <attribute name="req_resource_set_ipv4"> - <data type="string"> - <param name="maxLength">512000</param> - <param name="pattern">[\-,/.0-9]*</param> - </data> - </attribute> - </optional> - <optional> - <attribute name="req_resource_set_ipv6"> - <data type="string"> - <param name="maxLength">512000</param> - <param name="pattern">[\-,/:0-9a-fA-F]*</param> - </data> - </attribute> - </optional> - <data type="base64Binary"> - <param name="maxLength">512000</param> - </data> - </element> - </define> - <define name="issue_response"> - <ref name="class"/> - </define> - <define name="revoke_request"> - <ref name="revocation"/> - </define> - <define name="revoke_response"> - <ref name="revocation"/> - </define> - <define name="revocation"> - <element name="key"> - <attribute name="class_name"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - <attribute name="ski"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </attribute> - </element> - </define> - <define name="error_response"> - <element name="status"> - <data type="positiveInteger"> - <param name="maxInclusive">999999999999999</param> - </data> - </element> - <optional> - <element name="description"> - <attribute name="xml:lang"> - <data type="language"/> - </attribute> - <data type="string"> - <param name="maxLength">1024</param> - </data> - </element> - </optional> - </define> -</grammar> -''')) diff --git a/scripts/rpki/resource_set.py b/scripts/rpki/resource_set.py deleted file mode 100644 index 8497dad5..00000000 --- a/scripts/rpki/resource_set.py +++ /dev/null @@ -1,528 +0,0 @@ -# $Id$ - -# Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") -# -# 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 ARIN DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL ARIN 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. - -"""Classes dealing with sets of resources. - -The basic mechanics of a resource set are the same for any of the -resources we handle (ASNs, IPv4 addresses, or IPv6 addresses), so we -can provide the same operations on any of them, even though the -underlying details vary. - -We also provide some basic set operations (union, intersection, etc). -""" - -import re -import rpki.ipaddrs, rpki.oids - -inherit_token = "<inherit>" - -class resource_range(object): - """Generic resource range type. - - Assumes underlying type is some kind of integer. You probably don't - want to use this type directly. - """ - - def __init__(self, min, max): - """Initialize and sanity check a resource_range.""" - assert min <= max, "Mis-ordered range: %s before %s" % (str(min), str(max)) - self.min = min - self.max = max - - def __cmp__(self, other): - """Compare two resource_range objects.""" - c = self.min - other.min - if c == 0: c = self.max - other.max - if c < 0: c = -1 - if c > 0: c = 1 - return c - -class resource_range_as(resource_range): - """Range of Autonomous System Numbers. - - Denotes a single ASN by a range whose min and max values are identical. - """ - - datum_type = long - - def __str__(self): - """Convert a resource_range_as to string format.""" - if self.min == self.max: - return str(self.min) - else: - return str(self.min) + "-" + str(self.max) - - def to_tuple(self): - """Convert a resource_range_as to tuple format for ASN.1 encoding.""" - if self.min == self.max: - return ("id", self.min) - else: - return ("range", (self.min, self.max)) - -class resource_range_ip(resource_range): - """Range of (generic) IP addresses. - - Prefixes are converted to ranges on input, and ranges that can be - represented as prefixes are written as prefixes on output. - """ - - def _prefixlen(self): - """Determine whether a resource_range_ip can be expressed as a prefix.""" - mask = self.min ^ self.max - prefixlen = self.datum_type.bits - while mask & 1: - prefixlen -= 1 - mask >>= 1 - if mask: - return -1 - else: - return prefixlen - - def __str__(self): - """Convert a resource_range_ip to string format.""" - prefixlen = self._prefixlen() - if prefixlen < 0: - return str(self.min) + "-" + str(self.max) - else: - return str(self.min) + "/" + str(prefixlen) - - def to_tuple(self): - """Convert a resource_range_ip to tuple format for ASN.1 encoding.""" - prefixlen = self._prefixlen() - if prefixlen < 0: - return ("addressRange", (_long2bs(self.min, self.datum_type.bits, strip = 0), - _long2bs(self.max, self.datum_type.bits, strip = 1))) - else: - return ("addressPrefix", _long2bs(self.min, self.datum_type.bits, prefixlen = prefixlen)) - -class resource_range_ipv4(resource_range_ip): - """Range of IPv4 addresses.""" - - datum_type = rpki.ipaddrs.v4addr - -class resource_range_ipv6(resource_range_ip): - """Range of IPv6 addresses.""" - - datum_type = rpki.ipaddrs.v6addr - -def _rsplit(rset, that): - """Split a resource range into two resource ranges.""" - this = rset.pop(0) - cell_type = type(this.min) - assert type(this) is type(that) and type(this.max) is cell_type and \ - type(that.min) is cell_type and type(that.max) is cell_type - if this.min < that.min: - rset.insert(0, type(this)(this.min, cell_type(that.min - 1))) - rset.insert(1, type(this)(that.min, this.max)) - else: - assert this.max > that.max - rset.insert(0, type(this)(this.min, that.max)) - rset.insert(1, type(this)(cell_type(that.max + 1), this.max)) - -class resource_set(list): - """Generic resource set. - - List type containing resource ranges. You probably don't want to - use this type directly. - """ - - inherit = False - - def __init__(self, ini = None): - """Initialize a resource_set.""" - if isinstance(ini, int) or isinstance(ini, long): - ini = str(ini) - if ini == inherit_token: - self.inherit = True - elif isinstance(ini, str) and len(ini): - self.extend(map(self.parse_str, ini.split(","))) - elif isinstance(ini, tuple): - self.parse_tuple(ini) - elif isinstance(ini, list): - self.extend(ini) - else: - assert ini is None or ini == "", "Unexpected initializer: %s" % str(ini) - assert not self.inherit or not self - self.sort() - if __debug__: - for i in range(0, len(self) - 1): - assert self[i].max < self[i+1].min, "Resource overlap: %s %s" % (self[i], self[i+1]) - - def __str__(self): - """Convert a resource_set to string format.""" - if self.inherit: - return inherit_token - else: - return ",".join(map(str, self)) - - def _comm(self, other): - """Like comm(1), sort of. - - Returns a tuple of three resource sets: resources only in self, - resources only in other, and resources in both. Used (not very - efficiently) as the basis for most set operations on resource - sets. - """ - assert not self.inherit - assert type(self) is type(other), "Type mismatch %s %s" % (repr(type(self)), repr(type(other))) - set1 = self[:] - set2 = other[:] - only1, only2, both = [], [], [] - while set1 or set2: - if set1 and (not set2 or set1[0].max < set2[0].min): - only1.append(set1.pop(0)) - elif set2 and (not set1 or set2[0].max < set1[0].min): - only2.append(set2.pop(0)) - elif set1[0].min < set2[0].min: - _rsplit(set1, set2[0]) - elif set2[0].min < set1[0].min: - _rsplit(set2, set1[0]) - elif set1[0].max < set2[0].max: - _rsplit(set2, set1[0]) - elif set2[0].max < set1[0].max: - _rsplit(set1, set2[0]) - else: - assert set1[0].min == set2[0].min and set1[0].max == set2[0].max - both.append(set1.pop(0)) - set2.pop(0) - return type(self)(only1), type(self)(only2), type(self)(both) - - def union(self, other): - """Set union for resource sets.""" - assert not self.inherit - assert type(self) is type(other), "Type mismatch: %s %s" % (repr(type(self)), repr(type(other))) - set1 = self[:] - set2 = other[:] - result = [] - while set1 or set2: - if set1 and (not set2 or set1[0].max < set2[0].min): - result.append(set1.pop(0)) - elif set2 and (not set1 or set2[0].max < set1[0].min): - result.append(set2.pop(0)) - else: - this = set1.pop(0) - that = set2.pop(0) - assert type(this) is type(that) - if this.min < that.min: min = this.min - else: min = that.min - if this.max > that.max: max = this.max - else: max = that.max - result.append(type(this)(min, max)) - for i in range(len(result) - 2, -1, -1): - if result[i].max + 1 == result[i + 1].min: - result[i].max = result[i + 1].max - result.pop(i + 1) - return type(self)(result) - - def intersection(self, other): - """Set intersection for resource sets.""" - return self._comm(other)[2] - - def difference(self, other): - """Set difference for resource sets.""" - return self._comm(other)[0] - - def symmetric_difference(self, other): - """Set symmetric difference (XOR) for resource sets.""" - com = self._comm(other) - return com[0].union(com[1]) - - def contains(self, item): - """Set membership test for resource sets.""" - assert not self.inherit - for i in self: - if isinstance(item, type(i)) and i.min <= item.min and i.max >= item.max: - return True - elif isinstance(item, type(i.min)) and i.min <= item and i.max >= item: - return True - else: - assert isinstance(item, (type(i), type(i.min))) - return False - - def issubset(self, other): - """Test whether self is a subset (possibly improper) of other.""" - for i in self: - if not other.contains(i): - return False - return True - - def issuperset(self, other): - """Test whether self is a superset (possibly improper) of other.""" - return other.issubset(self) - - @classmethod - def from_sql(cls, cur, query, args = None): - """Create resource set from an SQL query. - - cur is a DB API 2.0 cursor object. - - query is an SQL query that returns a sequence of (min, max) pairs. - """ - - cur.execute(query, args) - return cls(ini = [cls.range_type(cls.range_type.datum_type(b), - cls.range_type.datum_type(e)) - for (b,e) in cur.fetchall()]) - -class resource_set_as(resource_set): - """ASN resource set.""" - - range_type = resource_range_as - - def parse_str(self, x): - """Parse AS resource sets from text (eg, XML attributes).""" - r = re.match("^([0-9]+)-([0-9]+)$", x) - if r: - return resource_range_as(long(r.group(1)), long(r.group(2))) - else: - return resource_range_as(long(x), long(x)) - - def parse_tuple(self, x): - """Parse AS resource sets from intermediate form generated by ASN.1 decoder.""" - if x[0] == "asIdsOrRanges": - for aor in x[1]: - if aor[0] == "range": - min = aor[1][0] - max = aor[1][1] - else: - min = aor[1] - max = min - self.append(resource_range_as(min, max)) - else: - assert x[0] == "inherit" - self.inherit = True - - def to_tuple(self): - """Encode AS resource set into intermediate form used by ASN.1 encoder.""" - if self: - return ("asIdsOrRanges", tuple(a.to_tuple() for a in self)) - elif self.inherit: - return ("inherit", "") - else: - return None - -class resource_set_ip(resource_set): - """(Generic) IP address resource set. - - You probably don't want to use this type directly. - """ - - def parse_str(self, x): - """Parse IP address resource sets from text (eg, XML attributes).""" - r = re.match("^([0-9:.a-fA-F]+)-([0-9:.a-fA-F]+)$", x) - if r: - return self.range_type(self.range_type.datum_type(r.group(1)), self.range_type.datum_type(r.group(2))) - r = re.match("^([0-9:.a-fA-F]+)/([0-9]+)$", x) - if r: - min = self.range_type.datum_type(r.group(1)) - prefixlen = int(r.group(2)) - mask = (1 << (self.range_type.datum_type.bits - prefixlen)) - 1 - assert (min & mask) == 0, "Resource not in canonical form: %s" % (x) - max = self.range_type.datum_type(min | mask) - return self.range_type(min, max) - raise RuntimeError, 'Bad IP resource "%s"' % (x) - - def parse_tuple(self, x): - """Parse IP address resource sets from intermediate form generated by ASN.1 decoder.""" - if x[0] == "addressesOrRanges": - for aor in x[1]: - if aor[0] == "addressRange": - min = _bs2long(aor[1][0]) << (self.range_type.datum_type.bits - len(aor[1][0])) - max = _bs2long(aor[1][1]) << (self.range_type.datum_type.bits - len(aor[1][1])) - mask = (1L << (self.range_type.datum_type.bits - len(aor[1][1]))) - 1 - else: - min = _bs2long(aor[1]) << (self.range_type.datum_type.bits - len(aor[1])) - mask = (1L << (self.range_type.datum_type.bits - len(aor[1]))) - 1 - assert (min & mask) == 0, "Resource not in canonical form: %s" % (str(x)) - max = min | mask - self.append(self.range_type(self.range_type.datum_type(min), self.range_type.datum_type(max))) - else: - assert x[0] == "inherit" - self.inherit = True - - def to_tuple(self): - """Encode IP resource set into intermediate form used by ASN.1 encoder.""" - if self: - return (self.afi, ("addressesOrRanges", tuple(a.to_tuple() for a in self))) - elif self.inherit: - return (self.afi, ("inherit", "")) - else: - return None - -class resource_set_ipv4(resource_set_ip): - """IPv4 address resource set.""" - - range_type = resource_range_ipv4 - afi = "\x00\x01" - -class resource_set_ipv6(resource_set_ip): - """IPv6 address resource set.""" - - range_type = resource_range_ipv6 - afi = "\x00\x02" - -def _bs2long(bs): - """Convert a bitstring (tuple representation) into a long.""" - return reduce(lambda x, y: (x << 1) | y, bs, 0L) - -def _long2bs(number, addrlen, prefixlen = None, strip = None): - """Convert a long into a tuple bitstring. This is a bit complicated - because it supports the fiendishly compact encoding used in RFC 3779. - """ - assert prefixlen is None or strip is None - bs = [] - while number: - bs.append(int(number & 1)) - number >>= 1 - if addrlen > len(bs): - bs.extend((0 for i in xrange(addrlen - len(bs)))) - bs.reverse() - if prefixlen is not None: - return tuple(bs[0:prefixlen]) - if strip is not None: - while bs and bs[-1] == strip: - bs.pop() - return tuple(bs) - -class resource_bag(object): - """Container to simplify passing around the usual triple of AS, - IPv4, and IPv6 resource sets. - """ - - def __init__(self, as = None, v4 = None, v6 = None, valid_until = None): - self.as = as or resource_set_as() - self.v4 = v4 or resource_set_ipv4() - self.v6 = v6 or resource_set_ipv6() - self.valid_until = valid_until - - def oversized(self, other): - """True iff self is oversized with respect to other.""" - return not self.as.issubset(other.as) or \ - not self.v4.issubset(other.v4) or \ - not self.v6.issubset(other.v6) - - def undersized(self, other): - """True iff self is undersized with respect to other.""" - return not other.as.issubset(self.as) or \ - not other.v4.issubset(self.v4) or \ - not other.v6.issubset(self.v6) - - @classmethod - def from_asn1_tuples(cls, exts): - """Build a resource_bag from intermediate form returned by ASN.1 decoder.""" - as = None - v4 = None - v6 = None - for x in exts: - if x[0] == rpki.oids.name2oid["sbgp-autonomousSysNum"]: # - assert len(x[2]) == 1 or x[2][1] is None, "RDI not implemented: %s" % (str(x)) - assert as is None - as = resource_set_as(x[2][0]) - if x[0] == rpki.oids.name2oid["sbgp-ipAddrBlock"]: - for fam in x[2]: - if fam[0] == resource_set_ipv4.afi: - assert v4 is None - v4 = resource_set_ipv4(fam[1]) - if fam[0] == resource_set_ipv6.afi: - assert v6 is None - v6 = resource_set_ipv6(fam[1]) - return cls(as, v4, v6) - - def empty(self): - """Return True iff all resource sets in this bag are empty.""" - return not self.as and not self.v4 and not self.v6 - - def __eq__(self, other): - return self.as == other.as and \ - self.v4 == other.v4 and \ - self.v6 == other.v6 and \ - self.valid_until == other.valid_until - - def __ne__(self, other): - return not (self == other) - - def intersection(self, other): - """Compute intersection with another resource_bag. - valid_until attribute (if any) inherits from self. - """ - return self.__class__(self.as.intersection(other.as), - self.v4.intersection(other.v4), - self.v6.intersection(other.v6), - self.valid_until) - - def union(self, other): - """Compute union with another resource_bag. - valid_until attribute (if any) inherits from self. - """ - return self.__class__(self.as.union(other.as), - self.v4.union(other.v4), - self.v6.union(other.v6), - self.valid_until) - - def __str__(self): - s = "" - if self.as: - s += "AS: %s" % self.as - if self.v4: - if s: - s += ", " - s += "V4: %s" % self.v4 - if self.v6: - if s: - s += ", " - s += "V6: %s" % self.v6 - return s - -# Test suite for set operations. This will probably go away eventually - -if __name__ == "__main__": - - def test(t, s1, s2): - print - r1 = t(s1) - r2 = t(s2) - print "x: ", r1 - print "y: ", r2 - v1 = r1._comm(r2) - v2 = r2._comm(r1) - assert v1[0] == v2[1] and v1[1] == v2[0] and v1[2] == v2[2] - for i in r1: assert r1.contains(i) and r1.contains(i.min) and r1.contains(i.max) - for i in r2: assert r2.contains(i) and r2.contains(i.min) and r2.contains(i.max) - for i in v1[0]: assert r1.contains(i) and not r2.contains(i) - for i in v1[1]: assert not r1.contains(i) and r2.contains(i) - for i in v1[2]: assert r1.contains(i) and r2.contains(i) - v1 = r1.union(r2) - v2 = r2.union(r1) - assert v1 == v2 - print "x|y:", v1 - v1 = r1.difference(r2) - v2 = r2.difference(r1) - print "x-y:", v1 - print "y-x:", v2 - v1 = r1.symmetric_difference(r2) - v2 = r2.symmetric_difference(r1) - assert v1 == v2 - print "x^y:", v1 - v1 = r1.intersection(r2) - v2 = r2.intersection(r1) - assert v1 == v2 - print "x&y:", v1 - - print "Testing set operations on resource sets" - test(resource_set_as, "1,2,3,4,5,6,11,12,13,14,15", "1,2,3,4,5,6,111,121,131,141,151") - test(resource_set_ipv4, "10.0.0.44/32,10.6.0.2/32", "10.3.0.0/24,10.0.0.77/32") - test(resource_set_ipv4, "10.0.0.44/32,10.6.0.2/32", "10.0.0.0/24") - test(resource_set_ipv4, "10.0.0.0/24", "10.3.0.0/24,10.0.0.77/32") diff --git a/scripts/rpki/roa.py b/scripts/rpki/roa.py deleted file mode 100644 index 15d1c6eb..00000000 --- a/scripts/rpki/roa.py +++ /dev/null @@ -1,49 +0,0 @@ -# $Id$ - -# Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") -# -# 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 ARIN DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL ARIN 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. - -""" ROA (Route Origin Authorization). - -At the moment this is just the ASN.1 encoder. - -This corresponds to draft-ietf-sidr-roa-format-01, which is a work in -progress, so this may need updating later. -""" - -from POW._der import * - -class IPAddresses(SequenceOf): - def __init__(self, optional=0, default=''): - SequenceOf.__init__(self, BitString, optional, default) - -class ROAIPAddressFamily(Sequence): - def __init__(self, optional=0, default=''): - self.addressFamily = OctetString() - self.addresses = IPAddresses() - contents = [ self.addressFamily, self.addresses ] - Sequence.__init__(self, contents, optional, default) - -class ROAIPAddrBlocks(SequenceOf): - def __init__(self, optional=0, default=''): - SequenceOf.__init__(self, ROAIPAddressFamily, optional, default) - -class RouteOriginAttestation(Sequence): - def __init__(self, optional=0, default=''): - self.version = Integer(0, chr(0x00)) - self.asID = Integer() - self.exactMatch = Boolean() - self.ipAddrBlocks = ROAIPAddrBlocks() - contents = [ self.version, self.asID, self.exactMatch, self.ipAddrBlocks ] - Sequence.__init__(self, contents, optional, default) diff --git a/scripts/rpki/sax_utils.py b/scripts/rpki/sax_utils.py deleted file mode 100644 index a472bee9..00000000 --- a/scripts/rpki/sax_utils.py +++ /dev/null @@ -1,93 +0,0 @@ -# $Id$ - -# Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") -# -# 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 ARIN DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL ARIN 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. - -"""SAX utilities.""" - -import xml.sax, lxml.sax - -class handler(xml.sax.handler.ContentHandler): - """SAX handler for RPKI protocols. - - This class provides some basic amenities for parsing protocol XML of - the kind we use in the RPKI protocols, including whacking all the - protocol element text into US-ASCII, simplifying accumulation of - text fields, and hiding some of the fun relating to XML namespaces. - - General assumption: by the time this parsing code gets invoked, the - XML has already passed RelaxNG validation, so we only have to check - for errors that the schema can't catch, and we don't have to play as - many XML namespace games. - """ - - def __init__(self): - """Initialize SAX handler.""" - self.text = "" - self.stack = [] - - def startElementNS(self, name, qname, attrs): - """Redirect startElementNS() events to startElement().""" - return self.startElement(name[1], attrs) - - def endElementNS(self, name, qname): - """Redirect endElementNS() events to endElement().""" - return self.endElement(name[1]) - - def characters(self, content): - """Accumulate a chuck of element content (text).""" - self.text += content - - def startElement(self, name, attrs): - """Handle startElement() events. - - We maintain a stack of nested elements under construction so that - we can feed events directly to the current element rather than - having to pass them through all the nesting elements. - - If the stack is empty, this event is for the outermost element, so - we call a virtual method to create the corresponding object and - that's the object we'll be returning as our final result. - """ - a = dict() - for k,v in attrs.items(): - if isinstance(k, tuple): - if k == ("http://www.w3.org/XML/1998/namespace", "lang"): - k = "xml:lang" - else: - assert k[0] is None - k = k[1] - a[k.encode("ascii")] = v.encode("ascii") - if len(self.stack) == 0: - assert not hasattr(self, "result") - self.result = self.create_top_level(name, a) - self.stack.append(self.result) - self.stack[-1].startElement(self.stack, name, a) - - def endElement(self, name): - """Handle endElement() events. - - Mostly this means handling any accumulated element text. - """ - text = self.text.encode("ascii").strip() - self.text = "" - self.stack[-1].endElement(self.stack, name, text) - - @classmethod - def saxify(cls, elt): - """Create a one-off SAX parser, parse an ETree, return the result. - """ - self = cls() - lxml.sax.saxify(elt, self) - return self.result diff --git a/scripts/rpki/sql.py b/scripts/rpki/sql.py deleted file mode 100644 index 022e4dd5..00000000 --- a/scripts/rpki/sql.py +++ /dev/null @@ -1,801 +0,0 @@ -# $Id$ - -# Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") -# -# 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 ARIN DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL ARIN 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. - -import MySQLdb, time -import rpki.x509, rpki.resource_set, rpki.sundial - -def connect(cfg): - """Connect to a MySQL database using connection parameters from an - rpki.config.parser object. - """ - return MySQLdb.connect(user = cfg.get("sql-username"), - db = cfg.get("sql-database"), - passwd = cfg.get("sql-password")) - -class template(object): - """SQL template generator.""" - def __init__(self, table_name, index_column, *data_columns): - """Build a SQL template.""" - type_map = dict((x[0],x[1]) for x in data_columns if isinstance(x, tuple)) - data_columns = tuple(isinstance(x, tuple) and x[0] or x for x in data_columns) - columns = (index_column,) + data_columns - self.table = table_name - self.index = index_column - self.columns = columns - self.map = type_map - self.select = "SELECT %s FROM %s" % (", ".join(columns), table_name) - self.insert = "INSERT %s (%s) VALUES (%s)" % (table_name, ", ".join(data_columns), - ", ".join("%(" + s + ")s" for s in data_columns)) - self.update = "UPDATE %s SET %s WHERE %s = %%(%s)s" % \ - (table_name, ", ".join(s + " = %(" + s + ")s" for s in data_columns), - index_column, index_column) - self.delete = "DELETE FROM %s WHERE %s = %%s" % (table_name, index_column) - -## @var sql_cache -# Cache of objects pulled from SQL. - -sql_cache = {} - -## @var sql_dirty -# Set of objects that need to be written back to SQL. - -sql_dirty = set() - -def sql_cache_clear(): - """Clear the object cache.""" - sql_cache.clear() - -def sql_assert_pristine(): - """Assert that there are no dirty objects in the cache.""" - assert not sql_dirty, "Dirty objects in SQL cache: %s" % sql_dirty - -def sql_sweep(gctx): - """Write any dirty objects out to SQL.""" - for s in sql_dirty.copy(): - rpki.log.debug("Sweeping %s" % repr(s)) - s.sql_store(gctx) - sql_assert_pristine() - -class sql_persistant(object): - """Mixin for persistant class that needs to be stored in SQL. - """ - - ## @var sql_in_db - # Whether this object is already in SQL or not. - sql_in_db = False - - @classmethod - def sql_fetch(cls, gctx, id): - """Fetch one object from SQL, based on its primary key. Since in - this one case we know that the primary index is also the cache - key, we check for a cache hit directly in the hope of bypassing the - SQL lookup entirely. - """ - key = (cls, id) - if key in sql_cache: - return sql_cache[key] - else: - return cls.sql_fetch_where1(gctx, "%s = %s", (cls.sql_template.index, id)) - - @classmethod - def sql_fetch_where1(cls, gctx, where, args = None): - """Fetch one object from SQL, based on an arbitrary SQL WHERE expression.""" - results = cls.sql_fetch_where(gctx, where, args) - if len(results) == 0: - return None - elif len(results) == 1: - return results[0] - else: - raise rpki.exceptions.DBConsistancyError, \ - "Database contained multiple matches for %s where %s" % \ - (cls.__name__, where % tuple(repr(a) for a in args)) - - @classmethod - def sql_fetch_all(cls, gctx): - """Fetch all objects of this type from SQL.""" - return cls.sql_fetch_where(gctx, None) - - @classmethod - def sql_fetch_where(cls, gctx, where, args = None): - """Fetch objects of this type matching an arbitrary SQL WHERE expression.""" - if where is None: - gctx.cur.execute(cls.sql_template.select) - else: - gctx.cur.execute(cls.sql_template.select + " WHERE " + where, args) - results = [] - for row in gctx.cur.fetchall(): - key = (cls, row[0]) - if key in sql_cache: - results.append(sql_cache[key]) - else: - results.append(cls.sql_init(gctx, row, key)) - return results - - @classmethod - def sql_init(cls, gctx, row, key): - """Initialize one Python object from the result of a SQL query.""" - self = cls() - self.sql_decode(dict(zip(cls.sql_template.columns, row))) - sql_cache[key] = self - self.sql_in_db = True - self.sql_fetch_hook(gctx) - return self - - def sql_mark_dirty(self): - """Mark this object as needing to be written back to SQL.""" - sql_dirty.add(self) - - def sql_mark_clean(self): - """Mark this object as not needing to be written back to SQL.""" - sql_dirty.discard(self) - - def sql_is_dirty(self): - """Query whether this object needs to be written back to SQL.""" - return self in sql_dirty - - def sql_store(self, gctx): - """Store this object to SQL.""" - if not self.sql_in_db: - gctx.cur.execute(self.sql_template.insert, self.sql_encode()) - setattr(self, self.sql_template.index, gctx.cur.lastrowid) - sql_cache[(self.__class__, gctx.cur.lastrowid)] = self - self.sql_insert_hook(gctx) - else: - gctx.cur.execute(self.sql_template.update, self.sql_encode()) - self.sql_update_hook(gctx) - key = (self.__class__, getattr(self, self.sql_template.index)) - assert key in sql_cache and sql_cache[key] == self - self.sql_mark_clean() - self.sql_in_db = True - - def sql_delete(self, gctx): - """Delete this object from SQL.""" - if self.sql_in_db: - id = getattr(self, self.sql_template.index) - gctx.cur.execute(self.sql_template.delete, id) - self.sql_delete_hook(gctx) - key = (self.__class__, id) - if sql_cache.get(key) == self: - del sql_cache[key] - self.sql_in_db = False - self.sql_mark_clean() - - def sql_encode(self): - """Convert object attributes into a dict for use with canned SQL - queries. This is a default version that assumes a one-to-one - mapping between column names in SQL and attribute names in Python. - If you need something fancier, override this. - """ - d = dict((a, getattr(self, a, None)) for a in self.sql_template.columns) - for i in self.sql_template.map: - if d.get(i) is not None: - d[i] = self.sql_template.map[i].to_sql(d[i]) - return d - - def sql_decode(self, vals): - """Initialize an object with values returned by self.sql_fetch(). - This is a default version that assumes a one-to-one mapping - between column names in SQL and attribute names in Python. If you - need something fancier, override this. - """ - for a in self.sql_template.columns: - if vals.get(a) is not None and a in self.sql_template.map: - setattr(self, a, self.sql_template.map[a].from_sql(vals[a])) - else: - setattr(self, a, vals[a]) - - def sql_fetch_hook(self, gctx): - """Customization hook.""" - pass - - def sql_insert_hook(self, gctx): - """Customization hook.""" - pass - - def sql_update_hook(self, gctx): - """Customization hook.""" - self.sql_delete_hook(gctx) - self.sql_insert_hook(gctx) - - def sql_delete_hook(self, gctx): - """Customization hook.""" - pass - -# Some persistant objects are defined in rpki.left_right, since -# they're also left-right PDUs. The rest are defined below, for now. - -class ca_obj(sql_persistant): - """Internal CA object.""" - - sql_template = template( - "ca", "ca_id", "last_crl_sn", - ("next_crl_update", rpki.sundial.datetime), - "last_issued_sn", "last_manifest_sn", - ("next_manifest_update", rpki.sundial.datetime), - "sia_uri", "parent_id", "parent_resource_class") - - last_crl_sn = 0 - last_issued_sn = 0 - last_manifest_sn = 0 - - def parent(self, gctx): - """Fetch parent object to which this CA object links.""" - return rpki.left_right.parent_elt.sql_fetch(gctx, self.parent_id) - - def ca_details(self, gctx): - """Fetch all ca_detail objects that link to this CA object.""" - return ca_detail_obj.sql_fetch_where(gctx, "ca_id = %s", (self.ca_id,)) - - def fetch_pending(self, gctx): - """Fetch the pending ca_details for this CA, if any.""" - return ca_detail_obj.sql_fetch_where(gctx, "ca_id = %s AND state = 'pending'", (self.ca_id,)) - - def fetch_active(self, gctx): - """Fetch the active ca_detail for this CA, if any.""" - return ca_detail_obj.sql_fetch_where1(gctx, "ca_id = %s AND state = 'active'", (self.ca_id,)) - - def fetch_deprecated(self, gctx): - """Fetch deprecated ca_details for this CA, if any.""" - return ca_detail_obj.sql_fetch_where(gctx, "ca_id = %s AND state = 'deprecated'", (self.ca_id,)) - - def fetch_revoked(self, gctx): - """Fetch revoked ca_details for this CA, if any.""" - return ca_detail_obj.sql_fetch_where(gctx, "ca_id = %s AND state = 'revoked'", (self.ca_id,)) - - def construct_sia_uri(self, gctx, parent, rc): - """Construct the sia_uri value for this CA given configured - information and the parent's up-down protocol list_response PDU. - """ - - repository = parent.repository(gctx) - sia_uri = rc.suggested_sia_head and rc.suggested_sia_head.rsync() - if not sia_uri or not sia_uri.startswith(parent.sia_base): - sia_uri = parent.sia_base - elif not sia_uri.endswith("/"): - raise rpki.exceptions.BadURISyntax, "SIA URI must end with a slash: %s" % sia_uri - return sia_uri + str(self.ca_id) + "/" - - def check_for_updates(self, gctx, parent, rc): - """Parent has signaled continued existance of a resource class we - already knew about, so we need to check for an updated - certificate, changes in resource coverage, revocation and reissue - with the same key, etc. - """ - - sia_uri = self.construct_sia_uri(gctx, parent, rc) - sia_uri_changed = self.sia_uri != sia_uri - if sia_uri_changed: - self.sia_uri = sia_uri - self.sql_mark_dirty() - - rc_resources = rc.to_resource_bag() - cert_map = dict((c.cert.get_SKI(), c) for c in rc.certs) - - for ca_detail in ca_detail_obj.sql_fetch_where(gctx, "ca_id = %s AND latest_ca_cert IS NOT NULL AND state != 'revoked'", (self.ca_id,)): - ski = ca_detail.latest_ca_cert.get_SKI() - if ca_detail.state in ("pending", "active"): - current_resources = ca_detail.latest_ca_cert.get_3779resources() - if sia_uri_changed or \ - ca_detail.latest_ca_cert != cert_map[ski].cert or \ - current_resources.undersized(rc_resources) or \ - current_resources.oversized(rc_resources): - ca_detail.update( - gctx = gctx, - parent = parent, - ca = self, - rc = rc, - sia_uri_changed = sia_uri_changed, - old_resources = current_resources) - del cert_map[ski] - assert not cert_map, "Certificates in list_response missing from our database, SKIs %s" % ", ".join(c.cert.hSKI() for c in cert_map.values()) - - @classmethod - def create(cls, gctx, parent, rc): - """Parent has signaled existance of a new resource class, so we - need to create and set up a corresponding CA object. - """ - - self = cls() - self.parent_id = parent.parent_id - self.parent_resource_class = rc.class_name - self.sql_store(gctx) - self.sia_uri = self.construct_sia_uri(gctx, parent, rc) - ca_detail = ca_detail_obj.create(gctx, self) - - # This will need a callback when we go event-driven - issue_response = rpki.up_down.issue_pdu.query(gctx, parent, self, ca_detail) - - ca_detail.activate( - gctx = gctx, - ca = self, - cert = issue_response.payload.classes[0].certs[0].cert, - uri = issue_response.payload.classes[0].certs[0].cert_url) - - def delete(self, gctx, parent): - """The list of current resource classes received from parent does - not include the class corresponding to this CA, so we need to - delete it (and its little dog too...). - - All certs published by this CA are now invalid, so need to - withdraw them, the CRL, and the manifest from the repository, - delete all child_cert and ca_detail records associated with this - CA, then finally delete this CA itself. - """ - - repository = parent.repository(gctx) - for ca_detail in self.ca_details(gctx): - ca_detail.delete(gctx, ca, repository) - self.sql_delete(gctx) - - def next_serial_number(self): - """Allocate a certificate serial number.""" - self.last_issued_sn += 1 - self.sql_mark_dirty() - return self.last_issued_sn - - def next_manifest_number(self): - """Allocate a manifest serial number.""" - self.last_manifest_sn += 1 - self.sql_mark_dirty() - return self.last_manifest_sn - - def next_crl_number(self): - """Allocate a CRL serial number.""" - self.last_crl_sn += 1 - self.sql_mark_dirty() - return self.last_crl_sn - - def rekey(self, gctx): - """Initiate a rekey operation for this ca. - - Tasks: - - - Generate a new keypair. - - - Request cert from parent using new keypair. - - - Mark result as our active ca_detail. - - - Reissue all child certs issued by this ca using the new ca_detail. - """ - - rpki.log.trace() - - parent = self.parent(gctx) - old_detail = self.fetch_active(gctx) - new_detail = ca_detail_obj.create(gctx, self) - - # This will need a callback when we go event-driven - issue_response = rpki.up_down.issue_pdu.query(gctx, parent, self, new_detail) - - new_detail.activate( - gctx = gctx, - ca = self, - cert = issue_response.payload.classes[0].certs[0].cert, - uri = issue_response.payload.classes[0].certs[0].cert_url, - predecessor = old_detail) - - def revoke(self, gctx): - """Revoke deprecated ca_detail objects associated with this ca.""" - - rpki.log.trace() - - for ca_detail in self.fetch_deprecated(gctx): - ca_detail.revoke(gctx) - -class ca_detail_obj(sql_persistant): - """Internal CA detail object.""" - - sql_template = template( - "ca_detail", - "ca_detail_id", - ("private_key_id", rpki.x509.RSA), - ("public_key", rpki.x509.RSApublic), - ("latest_ca_cert", rpki.x509.X509), - ("manifest_private_key_id", rpki.x509.RSA), - ("manifest_public_key", rpki.x509.RSApublic), - ("latest_manifest_cert", rpki.x509.X509), - ("latest_manifest", rpki.x509.SignedManifest), - ("latest_crl", rpki.x509.CRL), - "state", - "ca_cert_uri", - "ca_id") - - def sql_decode(self, vals): - """Extra assertions for SQL decode of a ca_detail_obj.""" - sql_persistant.sql_decode(self, vals) - assert (self.public_key is None and self.private_key_id is None) or \ - self.public_key.get_DER() == self.private_key_id.get_public_DER() - assert (self.manifest_public_key is None and self.manifest_private_key_id is None) or \ - self.manifest_public_key.get_DER() == self.manifest_private_key_id.get_public_DER() - - def ca(self, gctx): - """Fetch CA object to which this ca_detail links.""" - return ca_obj.sql_fetch(gctx, self.ca_id) - - def child_certs(self, gctx, child = None, ski = None, revoked = False, unique = False): - """Fetch all child_cert objects that link to this ca_detail.""" - return rpki.sql.child_cert_obj.fetch(gctx, child, self, ski, revoked, unique) - - def route_origins(self, gctx): - """Fetch all route_origin objects that link to this ca_detail.""" - return rpki.left_right.route_origin_elt.sql_fetch_where(gctx, "ca_detail_id = %s", (self.ca_detail_id,)) - - def crl_uri(self, ca): - """Return publication URI for this ca_detail's CRL.""" - return ca.sia_uri + self.public_key.gSKI() + ".crl" - - def manifest_uri(self, ca): - """Return publication URI for this ca_detail's manifest.""" - return ca.sia_uri + self.public_key.gSKI() + ".mnf" - - def activate(self, gctx, ca, cert, uri, predecessor = None): - """Activate this ca_detail.""" - - self.latest_ca_cert = cert - self.ca_cert_uri = uri.rsync() - self.generate_manifest_cert(ca) - self.generate_crl(gctx) - self.generate_manifest(gctx) - self.state = "active" - self.sql_mark_dirty() - - if predecessor is not None: - predecessor.state = "deprecated" - predecessor.sql_mark_dirty() - for child_cert in predecessor.child_certs(gctx): - child_cert.reissue(gctx, self) - - def delete(self, gctx, ca, repository): - """Delete this ca_detail and all of its associated child_cert objects.""" - - for child_cert in self.child_certs(gctx): - repository.withdraw(gctx, child_cert.cert, child_cert.uri(ca)) - child_cert.sql_delete(gctx) - for child_cert in self.child_certs(gctx, revoked = True): - child_cert.sql_delete(gctx) - repository.withdraw(gctx, self.latest_manifest, self.manifest_uri(ca)) - repository.withdraw(gctx, self.latest_crl, self.crl_uri()) - self.sql_delete(gctx) - - def revoke(self, gctx): - """Request revocation of all certificates whose SKI matches the key for this ca_detail. - - Tasks: - - - Request revocation of old keypair by parent. - - - Revoke all child certs issued by the old keypair. - - - Generate a final CRL, signed with the old keypair, listing all - the revoked certs, with a next CRL time after the last cert or - CRL signed by the old keypair will have expired. - - - Destroy old keypair (and manifest keypair). - - - Leave final CRL in place until its next CRL time has passed. - """ - - # This will need a callback when we go event-driven - r_msg = rpki.up_down.revoke_pdu.query(gctx, self) - - if r_msg.payload.ski != self.latest_ca_cert.gSKI(): - raise rpki.exceptions.SKIMismatch - - ca = self.ca(gctx) - parent = ca.parent(gctx) - crl_interval = rpki.sundial.timedelta(seconds = parent.self(gctx).crl_interval) - - nextUpdate = rpki.sundial.datetime.utcnow() - - if self.latest_manifest is not None: - nextUpdate = nextUpdate.later(self.latest_manifest.getNextUpdate()) - - if self.latest_crl is not None: - nextUpdate = nextUpdate.later(self.latest_crl.getNextUpdate()) - - for child_cert in self.child_certs(gctx): - nextUpdate = nextUpdate.later(child_cert.cert.getNotAfter()) - child_cert.revoke(gctx) - - nextUpdate += crl_interval - - self.generate_crl(gctx, nextUpdate) - self.generate_manifest(gctx, nextUpdate) - - self.private_key_id = None - self.manifest_private_key_id = None - self.manifest_public_key = None - self.latest_manifest_cert = None - self.state = "revoked" - self.sql_mark_dirty() - - def update(self, gctx, parent, ca, rc, sia_uri_changed, old_resources): - """Need to get a new certificate for this ca_detail and perhaps - frob children of this ca_detail. - """ - - # This will need a callback when we go event-driven - issue_response = rpki.up_down.issue_pdu.query(gctx, parent, ca, self) - - self.latest_ca_cert = issue_response.payload.classes[0].certs[0].cert - new_resources = self.latest_ca_cert.get_3779resources() - - if sia_uri_changed or old_resources.oversized(new_resources): - for child_cert in self.child_certs(gctx): - child_resources = child_cert.cert.get_3779resources() - if sia_uri_changed or child_resources.oversized(new_resources): - child_cert.reissue( - gctx = gctx, - ca_detail = self, - resources = child_resources.intersection(new_resources)) - - @classmethod - def create(cls, gctx, ca): - """Create a new ca_detail object for a specified CA.""" - self = cls() - self.ca_id = ca.ca_id - self.state = "pending" - - self.private_key_id = rpki.x509.RSA() - self.private_key_id.generate() - self.public_key = self.private_key_id.get_RSApublic() - - self.manifest_private_key_id = rpki.x509.RSA() - self.manifest_private_key_id.generate() - self.manifest_public_key = self.manifest_private_key_id.get_RSApublic() - - self.sql_store(gctx) - return self - - def generate_manifest_cert(self, ca): - """Generate a new manifest certificate for this ca_detail.""" - - resources = rpki.resource_set.resource_bag( - as = rpki.resource_set.resource_set_as("<inherit>"), - v4 = rpki.resource_set.resource_set_ipv4("<inherit>"), - v6 = rpki.resource_set.resource_set_ipv6("<inherit>")) - - self.latest_manifest_cert = self.latest_ca_cert.issue( - keypair = self.private_key_id, - subject_key = self.manifest_public_key, - serial = ca.next_manifest_number(), - sia = None, - aia = self.ca_cert_uri, - crldp = self.crl_uri(ca), - resources = resources, - notAfter = self.latest_ca_cert.getNotAfter(), - is_ca = False) - - def issue(self, gctx, ca, child, subject_key, sia, resources, child_cert = None): - """Issue a new certificate to a child. Optional child_cert - argument specifies an existing child_cert object to update in - place; if not specified, we create a new one. Returns the - child_cert object containing the newly issued cert. - """ - - assert child_cert is None or (child_cert.child_id == child.child_id and - child_cert.ca_detail_id == self.ca_detail_id) - - cert = self.latest_ca_cert.issue( - keypair = self.private_key_id, - subject_key = subject_key, - serial = ca.next_serial_number(), - aia = self.ca_cert_uri, - crldp = self.crl_uri(ca), - sia = sia, - resources = resources, - notAfter = resources.valid_until) - - if child_cert is None: - child_cert = rpki.sql.child_cert_obj( - child_id = child.child_id, - ca_detail_id = self.ca_detail_id, - cert = cert) - rpki.log.debug("Created new child_cert %s" % repr(child_cert)) - else: - child_cert.cert = cert - rpki.log.debug("Reusing existing child_cert %s" % repr(child_cert)) - - child_cert.ski = cert.get_SKI() - - child_cert.sql_store(gctx) - - ca.parent(gctx).repository(gctx).publish(gctx, child_cert.cert, child_cert.uri(ca)) - - self.generate_manifest(gctx) - - return child_cert - - def generate_crl(self, gctx, nextUpdate = None): - """Generate a new CRL for this ca_detail. At the moment this is - unconditional, that is, it is up to the caller to decide whether a - new CRL is needed. - """ - - ca = self.ca(gctx) - parent = ca.parent(gctx) - repository = parent.repository(gctx) - crl_interval = rpki.sundial.timedelta(seconds = parent.self(gctx).crl_interval) - now = rpki.sundial.datetime.utcnow() - - if nextUpdate is None: - nextUpdate = now + crl_interval - - certlist = [] - for child_cert in self.child_certs(gctx, revoked = True): - if now > child_cert.cert.getNotAfter() + crl_interval: - child_cert.sql_delete() - else: - certlist.append((child_cert.cert.getSerial(), child_cert.revoked.toASN1tuple(), ())) - certlist.sort() - - self.latest_crl = rpki.x509.CRL.generate( - keypair = self.private_key_id, - issuer = self.latest_ca_cert, - serial = ca.next_crl_number(), - thisUpdate = now, - nextUpdate = nextUpdate, - revokedCertificates = certlist) - - repository.publish(gctx, self.latest_crl, self.crl_uri(ca)) - - def generate_manifest(self, gctx, nextUpdate = None): - """Generate a new manifest for this ca_detail.""" - - ca = self.ca(gctx) - parent = ca.parent(gctx) - repository = parent.repository(gctx) - crl_interval = rpki.sundial.timedelta(seconds = parent.self(gctx).crl_interval) - now = rpki.sundial.datetime.utcnow() - - if nextUpdate is None: - nextUpdate = now + crl_interval - - certs = self.child_certs(gctx) - - m = rpki.x509.SignedManifest() - m.build( - serial = ca.next_manifest_number(), - thisUpdate = now, - nextUpdate = nextUpdate, - names_and_objs = [(c.uri_tail(), c.cert) for c in certs], - keypair = self.manifest_private_key_id, - certs = rpki.x509.X509_chain(self.latest_manifest_cert)) - self.latest_manifest = m - - repository.publish(gctx, self.latest_manifest, self.manifest_uri(ca)) - -class child_cert_obj(sql_persistant): - """Certificate that has been issued to a child.""" - - sql_template = template("child_cert", "child_cert_id", ("cert", rpki.x509.X509), "child_id", "ca_detail_id", "ski", ("revoked", rpki.sundial.datetime)) - - def __init__(self, child_id = None, ca_detail_id = None, cert = None): - """Initialize a child_cert_obj.""" - self.child_id = child_id - self.ca_detail_id = ca_detail_id - self.cert = cert - self.revoked = None - if child_id or ca_detail_id or cert: - self.sql_mark_dirty() - - def child(self, gctx): - """Fetch child object to which this child_cert object links.""" - return rpki.left_right.child_elt.sql_fetch(gctx, self.child_id) - - def ca_detail(self, gctx): - """Fetch ca_detail object to which this child_cert object links.""" - return ca_detail_obj.sql_fetch(gctx, self.ca_detail_id) - - def uri_tail(self): - """Return the tail (filename) portion of the URI for this child_cert.""" - return self.cert.gSKI() + ".cer" - - def uri(self, ca): - """Return the publication URI for this child_cert.""" - return ca.sia_uri + self.uri_tail() - - def revoke(self, gctx): - """Mark a child cert as revoked.""" - if self.revoked is None: - rpki.log.debug("Revoking %s" % repr(self)) - self.revoked = rpki.sundial.datetime.utcnow() - ca = self.ca_detail(gctx).ca(gctx) - repository = ca.parent(gctx).repository(gctx) - repository.withdraw(gctx, self.cert, self.uri(ca)) - self.sql_mark_dirty() - - def reissue(self, gctx, ca_detail, resources = None, sia = None): - """Reissue an existing cert, reusing the public key. If the cert - we would generate is identical to the one we already have, we just - return the one we already have. If we have to revoke the old - certificate when generating the new one, we have to generate a new - child_cert_obj, so calling code that needs the updated - child_cert_obj must use the return value from this method. - """ - - ca = ca_detail.ca(gctx) - child = self.child(gctx) - - old_resources = self.cert.get_3779resources() - old_sia = self.cert.get_SIA() - old_ca_detail = self.ca_detail(gctx) - - if resources is None: - resources = old_resources - - if sia is None: - sia = old_sia - - assert resources.valid_until is not None and old_resources.valid_until is not None - - if resources == old_resources and sia == old_sia and ca_detail == old_ca_detail: - return self - - must_revoke = old_resources.oversized(resources) or old_resources.valid_until > resources.valid_until - new_issuer = ca_detail != old_ca_detail - - if resources.valid_until != old_resources.valid_until: - rpki.log.debug("Validity changed: %s %s" % ( old_resources.valid_until, resources.valid_until)) - - if must_revoke or new_issuer: - child_cert = None - else: - child_cert = self - - child_cert = ca_detail.issue( - gctx = gctx, - ca = ca, - child = child, - subject_key = self.cert.getPublicKey(), - sia = sia, - resources = resources, - child_cert = child_cert) - - if must_revoke: - for cert in child.child_certs(gctx = gctx, ca_detail = ca_detail, ski = self.ski): - if cert is not child_cert: - cert.revoke(gctx) - - return child_cert - - @classmethod - def fetch(cls, gctx, child = None, ca_detail = None, ski = None, revoked = False, unique = False): - """Fetch all child_cert objects matching a particular set of - parameters. This is a wrapper to consolidate various queries that - would otherwise be inline SQL WHERE expressions. In most cases - code calls this indirectly, through methods in other classes. - """ - - args = [] - where = "revoked IS" - if revoked: - where += " NOT" - where += " NULL" - if child: - where += " AND child_id = %s" - args.append(child.child_id) - if ca_detail: - where += " AND ca_detail_id = %s" - args.append(ca_detail.ca_detail_id) - if ski: - where += " AND ski = %s" - args.append(ski) - if unique: - return cls.sql_fetch_where1(gctx, where, args) - else: - return cls.sql_fetch_where(gctx, where, args) diff --git a/scripts/rpki/sundial.py b/scripts/rpki/sundial.py deleted file mode 100644 index a1ffde62..00000000 --- a/scripts/rpki/sundial.py +++ /dev/null @@ -1,147 +0,0 @@ -# $Id$ - -# Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") -# -# 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 ARIN DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL ARIN 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. - -"""Unified RPKI date/time handling, based on the standard Python datetime module. - -Module name chosen to sidestep a nightmare of import-related errors -that occur with the more obvious module names. -""" - -import datetime as pydatetime - -class datetime(pydatetime.datetime): - """RPKI extensions to standard datetime.datetime class. All work - here is in UTC, so we use naive datetime objects. - """ - - def totimestamp(self): - """Convert to seconds from epoch (like time.time()). Conversion - method is a bit silly, but avoids time module timezone whackiness. - """ - return int(self.strftime("%s")) - - @classmethod - def fromUTCTime(cls, x): - """Convert from ASN.1 UTCTime.""" - return cls.strptime(x, "%y%m%d%H%M%SZ") - - def toUTCTime(self): - """Convert to ASN.1 UTCTime.""" - return self.strftime("%y%m%d%H%M%SZ") - - @classmethod - def fromGeneralizedTime(cls, x): - """Convert from ASN.1 GeneralizedTime.""" - return cls.strptime(x, "%Y%m%d%H%M%SZ") - - def toGeneralizedTime(self): - """Convert to ASN.1 GeneralizedTime.""" - return self.strftime("%Y%m%d%H%M%SZ") - - @classmethod - def fromASN1tuple(cls, x): - """Convert from ASN.1 tuple representation.""" - assert isinstance(x, tuple) and len(x) == 2 and x[0] in ("utcTime", "generalTime") - if x[0] == "utcTime": - return cls.fromUTCTime(x[1]) - else: - return cls.fromGeneralizedTime(x[1]) - - ## @var PKIX_threshhold - # Threshold specified in RFC 3280 for switchover from UTCTime to GeneralizedTime. - - PKIX_threshhold = pydatetime.datetime(2050, 1, 1) - - def toASN1tuple(self): - """Convert to ASN.1 tuple representation.""" - if self < self.PKIX_threshhold: - return "utcTime", self.toUTCTime() - else: - return "generalTime", self.toGeneralizedTime() - - @classmethod - def fromXMLtime(cls, x): - """Convert from XML time representation.""" - if x is None: - return None - else: - return cls.strptime(x, "%Y-%m-%dT%H:%M:%SZ") - - def toXMLtime(self): - """Convert to XML time representation.""" - return self.strftime("%Y-%m-%dT%H:%M:%SZ") - - def __str__(self): - return self.toXMLtime() - - @classmethod - def fromdatetime(cls, x): - """Convert a datetime.datetime object into this subclass. - This is whacky due to the weird constructors for datetime. - """ - return cls.combine(x.date(), x.time()) - - def __add__(self, other): - """Force correct class for timedelta results.""" - return self.fromdatetime(pydatetime.datetime.__add__(self, other)) - - def __sub__(self, other): - """Force correct class for timedelta results.""" - return self.fromdatetime(pydatetime.datetime.__sub__(self, other)) - - @classmethod - def from_sql(cls, x): - """Convert from SQL storage format.""" - return cls.fromdatetime(x) - - def to_sql(self): - """Convert to SQL storage format.""" - return self - - def later(self, other): - """Return the later of two timestamps.""" - return other if other > self else self - - def earlier(self, other): - """Return the earlier of two timestamps.""" - return other if other < self else self - -# Alias to simplify imports for callers - -timedelta = pydatetime.timedelta - -if __name__ == "__main__": - - now = datetime.utcnow() - print now - print repr(now) - print now.strftime("%s") - print now.toUTCTime() - print now.toGeneralizedTime() - print now.toASN1tuple() - print now.toXMLtime() - - print - - then = now - then += timedelta(days = 30) - print then - print repr(then) - print then.strftime("%s") - print then.toUTCTime() - print then.toGeneralizedTime() - print then.toASN1tuple() - print then.toXMLtime() diff --git a/scripts/rpki/up_down.py b/scripts/rpki/up_down.py deleted file mode 100644 index f902d86c..00000000 --- a/scripts/rpki/up_down.py +++ /dev/null @@ -1,518 +0,0 @@ -# $Id$ - -# Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") -# -# 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 ARIN DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL ARIN 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. - -"""RPKI "up-down" protocol.""" - -import base64, lxml.etree, time -import rpki.sax_utils, rpki.resource_set, rpki.x509, rpki.exceptions - -xmlns="http://www.apnic.net/specs/rescerts/up-down/" - -nsmap = { None : xmlns } - -class base_elt(object): - """Generic PDU object. - - Virtual class, just provides some default methods. - """ - - def startElement(self, stack, name, attrs): - """Ignore startElement() if there's no specific handler. - - Some elements have no attributes and we only care about their - text content. - """ - pass - - def endElement(self, stack, name, text): - """Ignore endElement() if there's no specific handler. - - If we don't need to do anything else, just pop the stack. - """ - stack.pop() - - def make_elt(self, name, *attrs): - """Construct a element, copying over a set of attributes.""" - elt = lxml.etree.Element("{%s}%s" % (xmlns, name), nsmap=nsmap) - for key in attrs: - val = getattr(self, key, None) - if val is not None: - elt.set(key, str(val)) - return elt - - def make_b64elt(self, elt, name, value=None): - """Construct a sub-element with Base64 text content.""" - if value is None: - value = getattr(self, name, None) - if value is not None: - lxml.etree.SubElement(elt, "{%s}%s" % (xmlns, name), nsmap=nsmap).text = base64.b64encode(value) - - def serve_pdu(self, gctx, q_msg, r_msg, child): - """Default PDU handler to catch unexpected types.""" - raise rpki.exceptions.BadQuery, "Unexpected query type %s" % q_msg.type - - def check_response(self): - """Placeholder for response checking.""" - pass - -class multi_uri(list): - """Container for a set of URIs.""" - - def __init__(self, ini): - """Initialize a set of URIs, which includes basic some syntax checking.""" - if isinstance(ini, (list, tuple)): - self[:] = ini - elif isinstance(ini, str): - self[:] = ini.split(",") - for s in self: - if s.strip() != s or s.find("://") < 0: - raise rpki.exceptions.BadURISyntax, "Bad URI \"%s\"" % s - else: - raise TypeError - - def __str__(self): - """Convert a multi_uri back to a string representation.""" - return ",".join(self) - - def rsync(self): - """Find first rsync://... URI in self.""" - for s in self: - if s.startswith("rsync://"): - return s - return None - -class certificate_elt(base_elt): - """Up-Down protocol representation of an issued certificate.""" - - def startElement(self, stack, name, attrs): - """Handle attributes of <certificate/> element.""" - assert name == "certificate", "Unexpected name %s, stack %s" % (name, stack) - self.cert_url = multi_uri(attrs["cert_url"]) - self.req_resource_set_as = rpki.resource_set.resource_set_as(attrs.get("req_resource_set_as")) - self.req_resource_set_ipv4 = rpki.resource_set.resource_set_ipv4(attrs.get("req_resource_set_ipv4")) - self.req_resource_set_ipv6 = rpki.resource_set.resource_set_ipv6(attrs.get("req_resource_set_ipv6")) - - def endElement(self, stack, name, text): - """Handle text content of a <certificate/> element.""" - assert name == "certificate", "Unexpected name %s, stack %s" % (name, stack) - self.cert = rpki.x509.X509(Base64=text) - stack.pop() - - def toXML(self): - """Generate a <certificate/> element.""" - elt = self.make_elt("certificate", "cert_url", - "req_resource_set_as", "req_resource_set_ipv4", "req_resource_set_ipv6") - elt.text = self.cert.get_Base64() - return elt - -class class_elt(base_elt): - """Up-Down protocol representation of a resource class.""" - - issuer = None - - def __init__(self): - """Initialize class_elt.""" - self.certs = [] - - def startElement(self, stack, name, attrs): - """Handle <class/> elements and their children.""" - if name == "certificate": - cert = certificate_elt() - self.certs.append(cert) - stack.append(cert) - cert.startElement(stack, name, attrs) - elif name != "issuer": - assert name == "class", "Unexpected name %s, stack %s" % (name, stack) - self.class_name = attrs["class_name"] - self.cert_url = multi_uri(attrs["cert_url"]) - self.suggested_sia_head = attrs.get("suggested_sia_head") - self.resource_set_as = rpki.resource_set.resource_set_as(attrs["resource_set_as"]) - self.resource_set_ipv4 = rpki.resource_set.resource_set_ipv4(attrs["resource_set_ipv4"]) - self.resource_set_ipv6 = rpki.resource_set.resource_set_ipv6(attrs["resource_set_ipv6"]) - self.resource_set_notafter = rpki.sundial.datetime.fromXMLtime(attrs.get("resource_set_notafter")) - - def endElement(self, stack, name, text): - """Handle <class/> elements and their children.""" - if name == "issuer": - self.issuer = rpki.x509.X509(Base64=text) - else: - assert name == "class", "Unexpected name %s, stack %s" % (name, stack) - stack.pop() - - def toXML(self): - """Generate a <class/> element.""" - elt = self.make_elt("class", "class_name", "cert_url", "resource_set_as", - "resource_set_ipv4", "resource_set_ipv6", - "resource_set_notafter", "suggested_sia_head") - elt.extend([i.toXML() for i in self.certs]) - if self.issuer is not None: - self.make_b64elt(elt, "issuer", self.issuer.get_DER()) - return elt - - def to_resource_bag(self): - """Build a resource_bag from from this <class/> element.""" - return rpki.resource_set.resource_bag(self.resource_set_as, - self.resource_set_ipv4, - self.resource_set_ipv6, - self.resource_set_notafter) - - def from_resource_bag(self, bag): - """Set resources of this class element from a resource_bag.""" - self.resource_set_as = bag.as - self.resource_set_ipv4 = bag.v4 - self.resource_set_ipv6 = bag.v6 - self.resource_set_notafter = bag.valid_until - -class list_pdu(base_elt): - """Up-Down protocol "list" PDU.""" - - def toXML(self): - """Generate (empty) payload of "list" PDU.""" - return [] - - def serve_pdu(self, gctx, q_msg, r_msg, child): - """Serve one "list" PDU.""" - r_msg.payload = list_response_pdu() - - # This will require a callback when we go event-driven - irdb_resources = rpki.left_right.irdb_query(gctx, child.self_id, child.child_id) - - for parent in child.parents(gctx): - for ca in parent.cas(gctx): - ca_detail = ca.fetch_active(gctx) - if not ca_detail: - continue - resources = ca_detail.latest_ca_cert.get_3779resources().intersection(irdb_resources) - if resources.empty(): - continue - rc = class_elt() - rc.class_name = str(ca.ca_id) - rc.cert_url = multi_uri(ca_detail.ca_cert_uri) - rc.from_resource_bag(resources) - for child_cert in child.child_certs(gctx, ca_detail = ca_detail): - c = certificate_elt() - c.cert_url = multi_uri(child_cert.uri(ca)) - c.cert = child_cert.cert - rc.certs.append(c) - rc.issuer = ca_detail.latest_ca_cert - r_msg.payload.classes.append(rc) - - @classmethod - def query(cls, gctx, parent): - """Send a "list" query to parent.""" - return parent.query_up_down(gctx, cls()) - -class class_response_syntax(base_elt): - """Syntax for Up-Down protocol "list_response" and "issue_response" PDUs.""" - - def __init__(self): - """Initialize class_response_syntax.""" - self.classes = [] - - def startElement(self, stack, name, attrs): - """Handle "list_response" and "issue_response" PDUs.""" - assert name == "class", "Unexpected name %s, stack %s" % (name, stack) - c = class_elt() - self.classes.append(c) - stack.append(c) - c.startElement(stack, name, attrs) - - def toXML(self): - """Generate payload of "list_response" and "issue_response" PDUs.""" - return [c.toXML() for c in self.classes] - -class list_response_pdu(class_response_syntax): - """Up-Down protocol "list_response" PDU.""" - - pass - -class issue_pdu(base_elt): - """Up-Down protocol "issue" PDU.""" - - def startElement(self, stack, name, attrs): - """Handle "issue" PDU.""" - assert name == "request", "Unexpected name %s, stack %s" % (name, stack) - self.class_name = attrs["class_name"] - self.req_resource_set_as = rpki.resource_set.resource_set_as(attrs.get("req_resource_set_as")) - self.req_resource_set_ipv4 = rpki.resource_set.resource_set_ipv4(attrs.get("req_resource_set_ipv4")) - self.req_resource_set_ipv6 = rpki.resource_set.resource_set_ipv6(attrs.get("req_resource_set_ipv6")) - - def endElement(self, stack, name, text): - """Handle "issue" PDU.""" - assert name == "request", "Unexpected name %s, stack %s" % (name, stack) - self.pkcs10 = rpki.x509.PKCS10(Base64=text) - stack.pop() - - def toXML(self): - """Generate payload of "issue" PDU.""" - elt = self.make_elt("request", "class_name", "req_resource_set_as", - "req_resource_set_ipv4", "req_resource_set_ipv6") - elt.text = self.pkcs10.get_Base64() - return [elt] - - def serve_pdu(self, gctx, q_msg, r_msg, child): - """Serve one issue request PDU.""" - - # Check the request - ca = child.ca_from_class_name(gctx, self.class_name) - ca_detail = ca.fetch_active(gctx) - self.pkcs10.check_valid_rpki() - - # Check current cert, if any - - # This will require a callback when we go event-driven - irdb_resources = rpki.left_right.irdb_query(gctx, child.self_id, child.child_id) - - resources = irdb_resources.intersection(ca_detail.latest_ca_cert.get_3779resources()) - req_key = self.pkcs10.getPublicKey() - req_sia = self.pkcs10.get_SIA() - child_cert = child.child_certs(gctx, ca_detail = ca_detail, ski = req_key.get_SKI(), unique = True) - - # Generate new cert or regenerate old one if necessary - - if child_cert is None: - child_cert = ca_detail.issue( - gctx = gctx, - ca = ca, - child = child, - subject_key = req_key, - sia = req_sia, - resources = resources) - else: - child_cert = child_cert.reissue( - gctx = gctx, - ca_detail = ca_detail, - sia = req_sia, - resources = resources) - - # Save anything we modified and generate response - rpki.sql.sql_sweep(gctx) - assert child_cert and child_cert.sql_in_db - c = certificate_elt() - c.cert_url = multi_uri(child_cert.uri(ca)) - c.cert = child_cert.cert - rc = class_elt() - rc.class_name = self.class_name - rc.cert_url = multi_uri(ca_detail.ca_cert_uri) - rc.from_resource_bag(resources) - rc.certs.append(c) - rc.issuer = ca_detail.latest_ca_cert - r_msg.payload = issue_response_pdu() - r_msg.payload.classes.append(rc) - - @classmethod - def query(cls, gctx, parent, ca, ca_detail): - """Send an "issue" request to parent associated with ca.""" - assert ca_detail is not None and ca_detail.state in ("pending", "active") - sia = ((rpki.oids.name2oid["id-ad-caRepository"], ("uri", ca.sia_uri)), - (rpki.oids.name2oid["id-ad-rpkiManifest"], ("uri", ca_detail.manifest_uri(ca)))) - self = cls() - self.class_name = ca.parent_resource_class - self.pkcs10 = rpki.x509.PKCS10.create_ca(ca_detail.private_key_id, sia) - return parent.query_up_down(gctx, self) - -class issue_response_pdu(class_response_syntax): - """Up-Down protocol "issue_response" PDU.""" - - def check_response(self): - """Check whether this looks like a reasonable issue_response PDU. - XML schema should be tighter for this response. - """ - if len(self.classes) != 1 or len(self.classes[0].certs) != 1: - raise rpki.exceptions.BadIssueResponse - -class revoke_syntax(base_elt): - """Syntax for Up-Down protocol "revoke" and "revoke_response" PDUs.""" - - def startElement(self, stack, name, attrs): - """Handle "revoke" PDU.""" - self.class_name = attrs["class_name"] - self.ski = attrs["ski"] - - def toXML(self): - """Generate payload of "revoke" PDU.""" - return [self.make_elt("key", "class_name", "ski")] - -class revoke_pdu(revoke_syntax): - """Up-Down protocol "revoke" PDU.""" - - def get_SKI(self): - """Convert g(SKI) encoding from PDU back to raw SKI.""" - return base64.urlsafe_b64decode(self.ski + "=") - - def serve_pdu(self, gctx, q_msg, r_msg, child): - """Serve one revoke request PDU.""" - for ca_detail in child.ca_from_class_name(gctx, self.class_name).ca_details(gctx): - for child_cert in child.child_certs(gctx, ca_detail = ca_detail, ski = self.get_SKI()): - child_cert.revoke(gctx) - rpki.sql.sql_sweep(gctx) - r_msg.payload = revoke_response_pdu() - r_msg.payload.class_name = self.class_name - r_msg.payload.ski = self.ski - - @classmethod - def query(cls, gctx, ca_detail): - """Send a "revoke" request to parent associated with ca_detail.""" - ca = ca_detail.ca(gctx) - parent = ca.parent(gctx) - self = cls() - self.class_name = ca.parent_resource_class - self.ski = ca_detail.latest_ca_cert.gSKI() - return parent.query_up_down(gctx, self) - -class revoke_response_pdu(revoke_syntax): - """Up-Down protocol "revoke_response" PDU.""" - - pass - -class error_response_pdu(base_elt): - """Up-Down protocol "error_response" PDU.""" - - codes = { - 1101 : "Already processing request", - 1102 : "Version number error", - 1103 : "Unrecognised request type", - 1201 : "Request - no such resource class", - 1202 : "Request - no resources allocated in resource class", - 1203 : "Request - badly formed certificate request", - 1301 : "Revoke - no such resource class", - 1302 : "Revoke - no such key", - 2001 : "Internal Server Error - Request not performed" } - - exceptions = {} - - def __init__(self, exception = None): - """Initialize an error_response PDU from an exception object.""" - if exception is not None: - if exception in self.exceptions: - self.status = exceptions[exception] - else: - self.status = 2001 - self.description = str(exception) - - def endElement(self, stack, name, text): - """Handle "error_response" PDU.""" - if name == "status": - code = int(text) - if code not in self.codes: - raise rpki.exceptions.BadStatusCode, "%s is not a known status code" - self.status = code - elif name == "description": - self.description = text - else: - assert name == "message", "Unexpected name %s, stack %s" % (name, stack) - stack.pop() - stack[-1].endElement(stack, name, text) - - def toXML(self): - """Generate payload of "error_response" PDU.""" - assert self.status in self.codes - elt = self.make_elt("status") - elt.text = str(self.status) - payload = [elt] - if self.description: - elt = self.make_elt("description") - elt.text = str(self.description) - elt.set("{http://www.w3.org/XML/1998/namespace}lang", "en-US") - payload.append(elt) - return payload - - def check_response(self): - """Handle an error response. For now, just raise an exception, - perhaps figure out something more clever to do later. - """ - raise rpki.exceptions.UpstreamError, self.codes[self.status] - -class message_pdu(base_elt): - """Up-Down protocol message wrapper PDU.""" - - version = 1 - - name2type = { - "list" : list_pdu, - "list_response" : list_response_pdu, - "issue" : issue_pdu, - "issue_response" : issue_response_pdu, - "revoke" : revoke_pdu, - "revoke_response" : revoke_response_pdu, - "error_response" : error_response_pdu } - - type2name = dict((v,k) for k,v in name2type.items()) - - def toXML(self): - """Generate payload of message PDU.""" - elt = self.make_elt("message", "version", "sender", "recipient", "type") - elt.extend(self.payload.toXML()) - return elt - - def startElement(self, stack, name, attrs): - """Handle message PDU. - - Payload of the <message/> element varies depending on the "type" - attribute, so after some basic checks we have to instantiate the - right class object to handle whatever kind of PDU this is. - """ - assert name == "message", "Unexpected name %s, stack %s" % (name, stack) - assert self.version == int(attrs["version"]) - self.sender = attrs["sender"] - self.recipient = attrs["recipient"] - self.type = attrs["type"] - self.payload = self.name2type[attrs["type"]]() - stack.append(self.payload) - - def __str__(self): - """Convert a message PDU to a string.""" - lxml.etree.tostring(self.toXML(), pretty_print = True, encoding = "UTF-8") - - def serve_top_level(self, gctx, child): - """Serve one message request PDU.""" - r_msg = message_pdu() - r_msg.sender = self.recipient - r_msg.recipient = self.sender - self.payload.serve_pdu(gctx, self, r_msg, child) - r_msg.type = self.type2name[type(r_msg.payload)] - return r_msg - - def serve_error(self, exception): - """Generate an error_response message PDU.""" - r_msg = message_pdu() - r_msg.sender = self.recipient - r_msg.recipient = self.sender - r_msg.payload = error_response_pdu(exception) - r_msg.type = self.type2name[type(r_msg.payload)] - return r_msg - - @classmethod - def make_query(cls, payload, sender, recipient): - """Construct one message PDU.""" - assert not cls.type2name[type(payload)].endswith("_response") - if sender is None: - sender = "tweedledee" - if recipient is None: - recipient = "tweedledum" - self = cls() - self.sender = sender - self.recipient = recipient - self.payload = payload - self.type = self.type2name[type(payload)] - return self - -class sax_handler(rpki.sax_utils.handler): - """SAX handler for Up-Down protocol.""" - - def create_top_level(self, name, attrs): - """Top-level PDU for this protocol is <message/>.""" - return message_pdu() diff --git a/scripts/rpki/x509.py b/scripts/rpki/x509.py deleted file mode 100644 index c029e5f3..00000000 --- a/scripts/rpki/x509.py +++ /dev/null @@ -1,700 +0,0 @@ -# $Id$ - -# Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") -# -# 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 ARIN DISCLAIMS ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -# AND FITNESS. IN NO EVENT SHALL ARIN 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. - -"""One X.509 implementation to rule them all... - -...and in the darkness hide the twisty maze of partially overlapping -X.509 support packages in Python. - -There are several existing packages, none of which do quite what I -need, due to age, lack of documentation, specialization, or lack of -foresight on somebody's part (perhaps mine). This module attempts to -bring together the functionality I need in a way that hides at least -some of the nasty details. This involves a lot of format conversion. -""" - -import POW, tlslite.api, POW.pkix, base64, time -import rpki.exceptions, rpki.resource_set, rpki.manifest, rpki.cms, rpki.oids, rpki.sundial - -def calculate_SKI(public_key_der): - """Calculate the SKI value given the DER representation of a public - key, which requires first peeling the ASN.1 wrapper off the key. - """ - k = POW.pkix.SubjectPublicKeyInfo() - k.fromString(public_key_der) - d = POW.Digest(POW.SHA1_DIGEST) - d.update(k.subjectPublicKey.get()) - return d.digest() - -class PEM_converter(object): - """Convert between DER and PEM encodings for various kinds of ASN.1 data.""" - - def __init__(self, kind): # "CERTIFICATE", "RSA PRIVATE KEY", ... - """Initialize PEM_converter.""" - self.b = "-----BEGIN %s-----" % kind - self.e = "-----END %s-----" % kind - - def looks_like_PEM(self, text): - """Guess whether text looks like a PEM encoding.""" - b = text.find(self.b) - return b >= 0 and text.find(self.e) > b + len(self.b) - - def to_DER(self, pem): - """Convert from PEM to DER.""" - lines = [line.strip() for line in pem.splitlines(0)] - while lines and lines.pop(0) != self.b: - pass - while lines and lines.pop(-1) != self.e: - pass - assert lines - return base64.b64decode("".join(lines)) - - def to_PEM(self, der): - """Convert from DER to PEM.""" - b64 = base64.b64encode(der) - pem = self.b + "\n" - while len(b64) > 64: - pem += b64[0:64] + "\n" - b64 = b64[64:] - return pem + b64 + "\n" + self.e + "\n" - -class DER_object(object): - """Virtual class to hold a generic DER object.""" - - ## Formats supported in this object - formats = ("DER",) - - ## PEM converter for this object - pem_converter = None - - ## Other attributes that self.clear() should whack - other_clear = () - - ## @var DER - ## DER value of this object - - def empty(self): - """Test whether this object is empty.""" - for a in self.formats: - if getattr(self, a, None) is not None: - return False - return True - - def clear(self): - """Make this object empty.""" - for a in self.formats + self.other_clear: - setattr(self, a, None) - - def __init__(self, **kw): - """Initialize a DER_object.""" - self.clear() - if len(kw): - self.set(**kw) - - def set(self, **kw): - """Set this object by setting one of its known formats. - - This method only allows one to set one format at a time. - Subsequent calls will clear the object first. The point of all - this is to let the object's internal converters handle mustering - the object into whatever format you need at the moment. - """ - if len(kw) == 1: - name = kw.keys()[0] - if name in self.formats: - self.clear() - setattr(self, name, kw[name]) - return - if name == "PEM": - self.clear() - self.DER = self.pem_converter.to_DER(kw[name]) - return - if name == "Base64": - self.clear() - self.DER = base64.b64decode(kw[name]) - return - if name in ("PEM_file", "DER_file", "Auto_file"): - f = open(kw[name], "rb") - value = f.read() - f.close() - if name == "PEM_file" or (name == "Auto_file" and self.pem_converter.looks_like_PEM(value)): - value = self.pem_converter.to_DER(value) - self.clear() - self.DER = value - return - raise rpki.exceptions.DERObjectConversionError, "Can't honor conversion request %s" % repr(kw) - - def get_DER(self): - """Get the DER value of this object. - - Subclasses will almost certainly override this method. - """ - assert not self.empty() - if self.DER: - return self.DER - raise rpki.exceptions.DERObjectConversionError, "No conversion path to DER available" - - def get_Base64(self): - """Get the Base64 encoding of the DER value of this object.""" - return base64.b64encode(self.get_DER()) - - def get_PEM(self): - """Get the PEM representation of this object.""" - return self.pem_converter.to_PEM(self.get_DER()) - - def __cmp__(self, other): - """Compare two DER-encoded objects.""" - return cmp(self.get_DER(), other.get_DER()) - - def hSKI(self): - """Return hexadecimal string representation of SKI for this - object. Only work for subclasses that implement get_SKI(). - """ - return ":".join(("%02X" % ord(i) for i in self.get_SKI())) - - def gSKI(self): - """Calculate g(SKI) for this object. Only work for subclasses - that implement get_SKI(). - """ - return base64.urlsafe_b64encode(self.get_SKI()).rstrip("=") - - def get_AKI(self): - """Get the AKI extension from this object. Only works for subclasses that support getExtension().""" - return (self.get_POWpkix().getExtension(rpki.oids.name2oid["authorityKeyIdentifier"]) or ((), 0, None))[2] - - def get_SKI(self): - """Get the SKI extension from this object. Only works for subclasses that support getExtension().""" - return (self.get_POWpkix().getExtension(rpki.oids.name2oid["subjectKeyIdentifier"]) or ((), 0, None))[2] - - def get_SIA(self): - """Get the SIA extension from this object. Only works for subclasses that support getExtension().""" - return (self.get_POWpkix().getExtension(rpki.oids.name2oid["subjectInfoAccess"]) or ((), 0, None))[2] - - def get_AIA(self): - """Get the SIA extension from this object. Only works for subclasses that support getExtension().""" - return (self.get_POWpkix().getExtension(rpki.oids.name2oid["subjectInfoAccess"]) or ((), 0, None))[2] - - def get_3779resources(self): - """Get RFC 3779 resources as rpki.resource_set objects. - Only works for subclasses that support getExtensions(). - """ - resources = rpki.resource_set.resource_bag.from_asn1_tuples(self.get_POWpkix().getExtensions()) - try: - resources.valid_until = self.getNotAfter() - except AttributeError: - pass - return resources - - @classmethod - def from_sql(cls, x): - """Convert from SQL storage format.""" - return cls(DER = x) - - def to_sql(self): - """Convert to SQL storage format.""" - return self.get_DER() - -class X509(DER_object): - """X.509 certificates. - - This class is designed to hold all the different representations of - X.509 certs we're using and convert between them. X.509 support in - Python a nasty maze of half-cooked stuff (except perhaps for - cryptlib, which is just different). Users of this module should not - have to care about this implementation nightmare. - """ - - formats = ("DER", "POW", "POWpkix", "tlslite") - pem_converter = PEM_converter("CERTIFICATE") - - def get_DER(self): - """Get the DER value of this certificate.""" - assert not self.empty() - if self.DER: - return self.DER - if self.POW: - self.DER = self.POW.derWrite() - return self.get_DER() - if self.POWpkix: - self.DER = self.POWpkix.toString() - return self.get_DER() - raise rpki.exceptions.DERObjectConversionError, "No conversion path to DER available" - - def get_POW(self): - """Get the POW value of this certificate.""" - assert not self.empty() - if not self.POW: - self.POW = POW.derRead(POW.X509_CERTIFICATE, self.get_DER()) - return self.POW - - def get_POWpkix(self): - """Get the POW.pkix value of this certificate.""" - assert not self.empty() - if not self.POWpkix: - cert = POW.pkix.Certificate() - cert.fromString(self.get_DER()) - self.POWpkix = cert - return self.POWpkix - - def get_tlslite(self): - """Get the tlslite value of this certificate.""" - assert not self.empty() - if not self.tlslite: - cert = tlslite.api.X509() - cert.parseBinary(self.get_DER()) - self.tlslite = cert - return self.tlslite - - def getIssuer(self): - """Get the issuer of this certificate.""" - return self.get_POW().getIssuer() - - def getSubject(self): - """Get the subject of this certificate.""" - return self.get_POW().getSubject() - - def getNotBefore(self): - """Get the inception time of this certificate.""" - return rpki.sundial.datetime.fromASN1tuple(self.get_POWpkix().tbs.validity.notBefore.get()) - - def getNotAfter(self): - """Get the expiration time of this certificate.""" - return rpki.sundial.datetime.fromASN1tuple(self.get_POWpkix().tbs.validity.notAfter.get()) - - def getSerial(self): - """Get the serial number of this certificate.""" - return self.get_POW().getSerial() - - def getPublicKey(self): - """Extract the public key from this certificate.""" - return RSApublic(DER = self.get_POWpkix().tbs.subjectPublicKeyInfo.toString()) - - def issue(self, keypair, subject_key, serial, sia, aia, crldp, notAfter, - cn = None, resources = None, is_ca = True): - """Issue a certificate.""" - - now = rpki.sundial.datetime.utcnow() - aki = self.get_SKI() - ski = subject_key.get_SKI() - - if cn is None: - cn = "".join(("%02X" % ord(i) for i in ski)) - - # if notAfter is None: notAfter = now + rpki.sundial.timedelta(days = 30) - - cert = POW.pkix.Certificate() - cert.setVersion(2) - cert.setSerial(serial) - cert.setIssuer(self.get_POWpkix().getSubject()) - cert.setSubject((((rpki.oids.name2oid["commonName"], ("printableString", cn)),),)) - cert.setNotBefore(now.toASN1tuple()) - cert.setNotAfter(notAfter.toASN1tuple()) - cert.tbs.subjectPublicKeyInfo.fromString(subject_key.get_DER()) - - exts = [ ["subjectKeyIdentifier", False, ski], - ["authorityKeyIdentifier", False, (aki, (), None)], - ["cRLDistributionPoints", False, ((("fullName", (("uri", crldp),)), None, ()),)], - ["authorityInfoAccess", False, ((rpki.oids.name2oid["id-ad-caIssuers"], ("uri", aia)),)], - ["certificatePolicies", True, ((rpki.oids.name2oid["id-cp-ipAddr-asNumber"], ()),)] ] - - if is_ca: - exts.append(["basicConstraints", True, (1, None)]) - exts.append(["keyUsage", True, (0, 0, 0, 0, 0, 1, 1)]) - else: - exts.append(["keyUsage", True, (1,)]) - - if sia is not None: - exts.append(["subjectInfoAccess", False, sia]) - else: - assert not is_ca - - if resources is not None and resources.as: - exts.append(["sbgp-autonomousSysNum", True, (resources.as.to_tuple(), None)]) - - if resources is not None and (resources.v4 or resources.v6): - exts.append(["sbgp-ipAddrBlock", True, [x for x in (resources.v4.to_tuple(), resources.v6.to_tuple()) if x is not None]]) - - for x in exts: - x[0] = rpki.oids.name2oid[x[0]] - cert.setExtensions(exts) - - cert.sign(keypair.get_POW(), POW.SHA256_DIGEST) - - return X509(POWpkix = cert) - -class X509_chain(list): - """Collections of certs. - - This class provides sorting and conversion functions for various - packages. - """ - - def __init__(self, *args, **kw): - """Initialize an X509_chain.""" - if args: - self[:] = args - elif "PEM_files" in kw: - self.load_from_PEM(kw["PEM_files"]) - elif "DER_files" in kw: - self.load_from_DER(kw["DER_files"]) - elif "Auto_files" in kw: - self.load_from_Auto(kw["Auto_files"]) - elif kw: - raise TypeError - - def chainsort(self): - """Sort a bag of certs into a chain, leaf first. - - Various other routines want their certs presented in this order. - """ - if len(self) > 1: - bag = self[:] - issuer_names = [x.getIssuer() for x in bag] - subject_map = dict([(x.getSubject(), x) for x in bag]) - chain = [] - for subject in subject_map: - if subject not in issuer_names: - cert = subject_map[subject] - chain.append(cert) - bag.remove(cert) - if len(chain) != 1: - raise rpki.exceptions.NotACertificateChain, "Certificates in bag don't form a proper chain" - while bag: - cert = subject_map[chain[-1].getIssuer()] - chain.append(cert) - bag.remove(cert) - self[:] = chain - - def tlslite_certChain(self): - """Return a certChain in the format tlslite likes.""" - self.chainsort() - return tlslite.api.X509CertChain([x.get_tlslite() for x in self]) - - def tlslite_trustList(self): - """Return a trustList in the format tlslite likes.""" - return [x.get_tlslite() for x in self] - - def clear(self): - """Drop all certs from this bag onto the floor.""" - self[:] = [] - - def load_from_PEM(self, files): - """Load a set of certs from a list of PEM files.""" - self.extend([X509(PEM_file=f) for f in files]) - - def load_from_DER(self, files): - """Load a set of certs from a list of DER files.""" - self.extend([X509(DER_file=f) for f in files]) - - def load_from_Auto(self, files): - """Load a set of certs from a list of DER or PEM files (guessing).""" - self.extend([X509(Auto_file=f) for f in files]) - -class PKCS10(DER_object): - """Class to hold a PKCS #10 request.""" - - formats = ("DER", "POWpkix") - pem_converter = PEM_converter("CERTIFICATE REQUEST") - - def get_DER(self): - """Get the DER value of this certification request.""" - assert not self.empty() - if self.DER: - return self.DER - if self.POWpkix: - self.DER = self.POWpkix.toString() - return self.get_DER() - raise rpki.exceptions.DERObjectConversionError, "No conversion path to DER available" - - def get_POWpkix(self): - """Get the POW.pkix value of this certification request.""" - assert not self.empty() - if not self.POWpkix: - req = POW.pkix.CertificationRequest() - req.fromString(self.get_DER()) - self.POWpkix = req - return self.POWpkix - - def getPublicKey(self): - """Extract the public key from this certification request.""" - return RSApublic(DER = self.get_POWpkix().certificationRequestInfo.subjectPublicKeyInfo.toString()) - - def check_valid_rpki(self): - """Check this certification request to see whether it's a valid - request for an RPKI certificate. This is broken out of the - up-down protocol code because it's somewhat involved and the - up-down code doesn't need to know the details. - - Throws an exception if the request isn't valid, so if this method - returns at all, the request is ok. - """ - - if not self.get_POWpkix().verify(): - raise rpki.exceptions.BadPKCS10, "Signature check failed" - - if self.get_POWpkix().certificationRequestInfo.version.get() != 0: - raise rpki.exceptions.BadPKCS10, \ - "Bad version number %s" % self.get_POWpkix().certificationRequestInfo.version - - if rpki.oids.oid2name.get(self.get_POWpkix().signatureAlgorithm.algorithm.get()) \ - not in ("sha256WithRSAEncryption", "sha384WithRSAEncryption", "sha512WithRSAEncryption"): - raise rpki.exceptions.BadPKCS10, "Bad signature algorithm %s" % self.get_POWpkix().signatureAlgorithm - - exts = self.get_POWpkix().getExtensions() - for oid, critical, value in exts: - if rpki.oids.oid2name.get(oid) not in ("basicConstraints", "keyUsage", "subjectInfoAccess"): - raise rpki.exceptions.BadExtension, "Forbidden extension %s" % oid - req_exts = dict((rpki.oids.oid2name[oid], value) for (oid, critical, value) in exts) - - if "basicConstraints" not in req_exts or not req_exts["basicConstraints"][0]: - raise rpki.exceptions.BadPKCS10, "request for EE cert not allowed here" - - if req_exts["basicConstraints"][1] is not None: - raise rpki.exceptions.BadPKCS10, "basicConstraints must not specify Path Length" - - if "keyUsage" in req_exts and (not req_exts["keyUsage"][5] or not req_exts["keyUsage"][6]): - raise rpki.exceptions.BadPKCS10, "keyUsage doesn't match basicConstraints" - - for method, location in req_exts.get("subjectInfoAccess", ()): - if rpki.oids.oid2name.get(method) == "id-ad-caRepository" and \ - (location[0] != "uri" or (location[1].startswith("rsync://") and not location[1].endswith("/"))): - raise rpki.exceptions.BadPKCS10, "Certificate request includes bad SIA component: %s" % repr(location) - - # This one is an implementation restriction. I don't yet - # understand what the spec is telling me to do in this case. - assert "subjectInfoAccess" in req_exts, "Can't (yet) handle PKCS #10 without an SIA extension" - - @classmethod - def create_ca(cls, keypair, sia = None): - """Create a new request for a given keypair, including given SIA value.""" - exts = [["basicConstraints", True, (1, None)], - ["keyUsage", True, (0, 0, 0, 0, 0, 1, 1)]] - if sia is not None: - exts.append(["subjectInfoAccess", False, sia]) - for x in exts: - x[0] = rpki.oids.name2oid[x[0]] - return cls.create(keypair, exts) - - @classmethod - def create(cls, keypair, exts = None): - """Create a new request for a given keypair, including given extensions.""" - cn = "".join(("%02X" % ord(i) for i in keypair.get_SKI())) - req = POW.pkix.CertificationRequest() - req.certificationRequestInfo.version.set(0) - req.certificationRequestInfo.subject.set((((rpki.oids.name2oid["commonName"], - ("printableString", cn)),),)) - if exts is not None: - req.setExtensions(exts) - req.sign(keypair.get_POW(), POW.SHA256_DIGEST) - return cls(POWpkix = req) - -class RSA(DER_object): - """Class to hold an RSA key pair.""" - - formats = ("DER", "POW", "tlslite") - pem_converter = PEM_converter("RSA PRIVATE KEY") - - def get_DER(self): - """Get the DER value of this keypair.""" - assert not self.empty() - if self.DER: - return self.DER - if self.POW: - self.DER = self.POW.derWrite(POW.RSA_PRIVATE_KEY) - return self.get_DER() - raise rpki.exceptions.DERObjectConversionError, "No conversion path to DER available" - - def get_POW(self): - """Get the POW value of this keypair.""" - assert not self.empty() - if not self.POW: - self.POW = POW.derRead(POW.RSA_PRIVATE_KEY, self.get_DER()) - return self.POW - - def get_tlslite(self): - """Get the tlslite value of this keypair.""" - assert not self.empty() - if not self.tlslite: - self.tlslite = tlslite.api.parsePEMKey(self.get_PEM(), private=True) - return self.tlslite - - def generate(self, keylength = 2048): - """Generate a new keypair.""" - self.clear() - self.set(POW=POW.Asymmetric(POW.RSA_CIPHER, keylength)) - - def get_public_DER(self): - """Get the DER encoding of the public key from this keypair.""" - return self.get_POW().derWrite(POW.RSA_PUBLIC_KEY) - - def get_SKI(self): - """Calculate the SKI of this keypair.""" - return calculate_SKI(self.get_public_DER()) - - def get_RSApublic(self): - """Convert the public key of this keypair into a RSApublic object.""" - return RSApublic(DER = self.get_public_DER()) - -class RSApublic(DER_object): - """Class to hold an RSA public key.""" - - formats = ("DER", "POW") - pem_converter = PEM_converter("RSA PUBLIC KEY") - - def get_DER(self): - """Get the DER value of this public key.""" - assert not self.empty() - if self.DER: - return self.DER - if self.POW: - self.DER = self.POW.derWrite(POW.RSA_PUBLIC_KEY) - return self.get_DER() - raise rpki.exceptions.DERObjectConversionError, "No conversion path to DER available" - - def get_POW(self): - """Get the POW value of this public key.""" - assert not self.empty() - if not self.POW: - self.POW = POW.derRead(POW.RSA_PUBLIC_KEY, self.get_DER()) - return self.POW - - def get_SKI(self): - """Calculate the SKI of this public key.""" - return calculate_SKI(self.get_DER()) - -class SignedManifest(DER_object): - """Class to hold a signed manifest. - - Signed manifests are a little different from the other DER_object - types because the signed object is CMS wrapping inner content that's - also ASN.1, and due to our current minimal support for CMS we can't - just handle this as a pretty composite object. So, for now anyway, - this SignedManifest object refers to the outer CMS wrapped manifest - so that the usual DER and PEM operations do the obvious things, and - the inner content is handle via separate methods using rpki.manifest. - """ - - formats = ("DER",) - other_clear = ("content",) - pem_converter = PEM_converter("RPKI MANIFEST") - - def get_DER(self): - """Get the DER value of this manifest.""" - assert not self.empty() - if self.DER: - return self.DER - raise rpki.exceptions.DERObjectConversionError, "No conversion path to DER available" - - def get_content(self): - """Get the inner content of this manifest.""" - assert self.content is not None - return self.content - - def set_content(self, content): - """Set the (inner) content of this manifest, clearing the wrapper.""" - self.clear() - self.content = content - - def getThisUpdate(self): - """Get thisUpdate value from this manifest.""" - return rpki.sundial.datetime.fromGeneralizedTime(self.get_content().thisUpdate.get()) - - def getNextUpdate(self): - """Get nextUpdate value from this manifest.""" - return rpki.sundial.datetime.fromGeneralizedTime(self.get_content().nextUpdate.get()) - - def verify(self, ta): - """Verify this manifest.""" - m = rpki.manifest.Manifest() - s = rpki.cms.verify(self.get_DER(), ta) - m.fromString(s) - self.content = m - - def build(self, serial, thisUpdate, nextUpdate, names_and_objs, keypair, certs, version = 0): - """Build the inner content of this manifest and sign it with CMS.""" - filelist = [] - for name, obj in names_and_objs: - d = POW.Digest(POW.SHA256_DIGEST) - d.update(obj.get_DER()) - filelist.append((name.rpartition("/")[2], d.digest())) - filelist.sort(key = lambda x: x[0]) - m = rpki.manifest.Manifest() - m.version.set(version) - m.manifestNumber.set(serial) - m.thisUpdate.set(thisUpdate.toGeneralizedTime()) - m.nextUpdate.set(nextUpdate.toGeneralizedTime()) - m.fileHashAlg.set((2, 16, 840, 1, 101, 3, 4, 2, 1)) # id-sha256 - m.fileList.set(filelist) - self.set_content(m) - self.DER = rpki.cms.sign(m.toString(), keypair, certs) - -class CRL(DER_object): - """Class to hold a Certificate Revocation List.""" - - formats = ("DER", "POW", "POWpkix") - pem_converter = PEM_converter("X509 CRL") - - def get_DER(self): - """Get the DER value of this CRL.""" - assert not self.empty() - if self.DER: - return self.DER - if self.POW: - self.DER = self.POW.derWrite() - return self.get_DER() - if self.POWpkix: - self.DER = self.POWpkix.toString() - return self.get_DER() - raise rpki.exceptions.DERObjectConversionError, "No conversion path to DER available" - - def get_POW(self): - """Get the POW value of this CRL.""" - assert not self.empty() - if not self.POW: - self.POW = POW.derRead(POW.X509_CRL, self.get_DER()) - return self.POW - - def get_POWpkix(self): - """Get the POW.pkix value of this CRL.""" - assert not self.empty() - if not self.POWpkix: - crl = POW.pkix.CertificateList() - crl.fromString(self.get_DER()) - self.POWpkix = crl - return self.POWpkix - - def getThisUpdate(self): - """Get thisUpdate value from this CRL.""" - return rpki.sundial.datetime.fromASN1tuple(self.get_POWpkix().getThisUpdate()) - - def getNextUpdate(self): - """Get nextUpdate value from this CRL.""" - return rpki.sundial.datetime.fromASN1tuple(self.get_POWpkix().getNextUpdate()) - - @classmethod - def generate(cls, keypair, issuer, serial, thisUpdate, nextUpdate, revokedCertificates, version = 1, digestType = "sha256WithRSAEncryption"): - crl = POW.pkix.CertificateList() - crl.setVersion(version) - crl.setIssuer(issuer.get_POWpkix().getSubject()) - crl.setThisUpdate(thisUpdate.toASN1tuple()) - crl.setNextUpdate(nextUpdate.toASN1tuple()) - if revokedCertificates: - crl.setRevokedCertificates(revokedCertificates) - crl.setExtensions( - ((rpki.oids.name2oid["authorityKeyIdentifier"], False, (issuer.get_SKI(), (), None)), - (rpki.oids.name2oid["cRLNumber"], False, serial))) - crl.sign(keypair.get_POW(), digestType) - return cls(POWpkix = crl) |