aboutsummaryrefslogtreecommitdiff
path: root/scripts/rpki
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/rpki')
-rw-r--r--scripts/rpki/Doxyfile1269
-rw-r--r--scripts/rpki/__init__.py42
-rw-r--r--scripts/rpki/cms.py120
-rw-r--r--scripts/rpki/config.py57
-rw-r--r--scripts/rpki/exceptions.py86
-rw-r--r--scripts/rpki/https.py146
-rw-r--r--scripts/rpki/ipaddrs.py70
-rw-r--r--scripts/rpki/left_right.py1002
-rw-r--r--scripts/rpki/log.py54
-rw-r--r--scripts/rpki/manifest.py53
-rw-r--r--scripts/rpki/oids.py49
-rw-r--r--scripts/rpki/pkcs10.py62
-rw-r--r--scripts/rpki/relaxng.py1208
-rw-r--r--scripts/rpki/resource_set.py528
-rw-r--r--scripts/rpki/roa.py49
-rw-r--r--scripts/rpki/sax_utils.py93
-rw-r--r--scripts/rpki/sql.py801
-rw-r--r--scripts/rpki/sundial.py147
-rw-r--r--scripts/rpki/up_down.py518
-rw-r--r--scripts/rpki/x509.py700
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)