mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1119049 - Keyboard shortcuts should work in MediaDocuments without explicitly focusing the media element. r=bz (46be3d5343)
- fix (3ade1708af)
- Bug 967982 - Show findbar after unsuccessful Find Again [r=mikedeboer] (8f228f14a1)
- Bug 1071631 - fix findbar re-filling in last character, r=mikedeboer (1dcea48088)
- Bug 1214249 - Set MOZ_FLOAT_ABI in armv6 case r=glandium (8c53df59f6)
- Bug 1223093 - Bump required rustc version to 1.4. r=mshal (2e116f0dc6)
- Bug 1208566 - require Rust 1.5 for --enable-rust builds; r=mshal (091c824772)
- bump gcc version to 4.4 and use e.g. MacPorts gcc for safety (1af814d7bd)
- reorder and fix (c74b24dfbf)
- Bug 1043112 - Allow b2g to core dump when signal permits. r=jld (f5afeb0051)
- Bug 1190965 - Restrict syscalls in nsProfileLock to Linux. r=jld (9ac892b4eb)
- Bug 1227569 - Remove unsupported OpenVMS code. r=mccr8 (ea080668c9)
- Bug 1227248 - Part 1: Allow extending StrictOrderingOnAppendListWithFlags. r=gps (52260fd46d)
- Bug 1163358 - Add "psm" tag to PSM xpcshell and mochitest manifests. r=dkeeler (aa31fa4e2f)
- Bug 1167254 - Convert test_bug234856.html mochitest to an xpcshell test. r=keeler (1f20c9f997)
- Bug 1169195 - Convert test_bug644006.html mochitest to an xpcshell test. r=keeler (f391df2ed5)
- bug 1181376 - convert test_bug480619.html to an xpcshell test r=mgoodwin (3bb1a3b762)
- Bug 1167866 - Add result strings to PSM test_cert* xpcshell tests. r=keeler (74743ab236)
- Bug 1171819 - Convert test_cert_eku-*.js to generate certificates at build time. r=keeler (9aea62b0dc)
- bug 1203312 - split tlsserver certificates into ocsp_certs and bad_certs r=mgoodwin (599437ece7)
- bug 1209695 - fold mochitest test_bug413909.html into xpcshell test_cert_overrides.js r=mgoodwin (cd5769201b)
- bug 1187029 - convert test_bug480509.html to an xpcshell test r=jcj (966cb02692)
- bug 1174292 - convert test_cert_version.js to generate certificates at build time r=Cykesiopka (7acb99f5ee)
- bug 1173565 - convert test_pinning_dynamic.js to generate certificates at build time r=Cykesiopka (cf5844376a)
- bug 1178988 - convert test_ocsp_url to generate certificates at build time r=Cykesiopka (de5554cb7b)
- bug 1189427 - convert test_ocsp_fetch_method.js to generate certificates at build time r=mgoodwin (9955a340fa)
- bug 1194013 - convert test_name_constraints.js to generate certificates at build time r=Cykesiopka,mgoodwin (0060e4232f)
- bug 1196853 - convert test_cert_signatures.js to generate certificat s at build time r=jcj (ce0ab9e63a)
- bug 1190603 - convert test_keysize.js to generate certificates at build time r=Cykesiopka (3dd9972c8f)
- Bug 1228794 - Convert test_getchain.js to generate certificates at build time. r=keeler (cf6b4d3c47)
- Bug 901698 - Some tests for OCSP-must-staple; r=keeler (4f51b34bee)
- Bug 1179678 - Add result strings to misc PSM xpcshell tests. r=keeler (a2142e0ca1)
- Bug 1205962 - Address some pylint complaints about pycert.py and pykey.py, r=keeler (190cdb0e4a)
- Bug 1218999 - Back out changeset 5f32b2bcfa43 (bug 1188468) in favor of a more efficient solution. r=glandium (195e060c30)
- Bug 1222903 - Reject EV status for EV EE certs that are valid for longer than 27 months as well. r=keeler (811b0bcc46)
- Bug 1231315 - Build CONFIGURE_DEFINE_FILES at build time instead of during configure. r=gps (5242734649)
- gradle remove (b745c7b2e4)
- Bug 1232421 - force matching the start of the line for comments, r=glandium (de93f61f91)
- Bug 1232421 - followup: fix test to not use 'inline comments' which are not supported elsewhere, rs=bustage on a CLOSED TREE (9e34a9d721)
- Bug 1172645 - Make mozbuild's setup.py work; r=glandium (b73b656574)
- bug 1166976 - add pyasn1-modules python library r=ted,gerv (24c7f3253f)
- bug 1166976 - add Python-RSA python library r=ted,gerv (9628d1583f)
- bug 1166976 - generate some PSM xpcshell test certificates at build time r=Cykesiopka,mgoodwin,froydnj (af4744b19d)
- Bug 1224478 - Replace do_check_* calls with their Assert.jsm equivalents in PSM xpcshell tests. r=keeler (6846617e65)
- bug 975763 - move test_certificate_overrides.html to test_cert_override_bits_mismatches.js r=mgoodwin (4ba930e064)
- Bug 1171820 - Convert test_bug483440.html mochitest to an xpcshell test. r=keeler (d41a63cd13)
- Bug 1147726: Disable test_keysize_ev.js on slow B2G Emulator debug builds. r=dkeeler (df54c1bbc8)
- Bug 1147725 - Disable test_ocsp_fetch_method.js and test_ocsp_url.js on slow B2G Emulator debug builds. r=keeler (56e71d8d7f)
- bug 1081128 - test_pinning.js takes ~300 seconds on b2g debug emulator - request a longer timeout for it r=Cykesiopka (20ecf7ca8b)
- Bug 1145679 - Part 2 - Tests. r=keeler (046b88cd37)
- Bug 1227248 - Part 2: Add GeneratedTest{Certificate,Key} mozbuild templates. r=gps (810848b3bc)
- Bug 1227248 - Part 3: Make GeneratedTest{Certificate,Key} no-op when --disable-compile-environment. r=gps (563c26d64b)
- Bug 1130413 - Remove unused nsITokenPasswordDialogs::GetPassword() function. r=jjones (0cff903788)
- Bug 1157515 - CipherSuiteChangeObserver should clean itself up. r=keeler (e9175e8f89)
- Bug 1215779 - Remove broken (non-EC) DSA keygen code. r=keeler (98a09304c1)
- bug 1215270 - remove some unused functions from nsNSSShutDown.h r=Cykesiopka (ea0e9566f2)
- bug 1215690 - remove nsPSMUITracker r=Cykesiopka r=mgoodwin (98ea9b8481)
- bug 1205767 - prevent memory leak when generating an EC key with <keygen> r=ttaubert (3be4b5f545)
- Bug 488480 - Correct documentation about the function hasMatchingOverride() in nsICertOverrideService.idl. Original patch by Johnathan Nightingale. r=keeler (bf2b16f2c0)
- Bug 629558 - Pref to make Intermediate Cert Store memory-only. r=keeler (19632e2fd6)
- typo (86093804e3)
- Bug 278689 - Multiple Certificates with the same subject are not shown in the digital signature select cert combo (only one is shown) r=dkeeler (c5984b6857)
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from buildconfig import topobjdir
|
||||
from mozbuild.backend.configenvironment import ConfigEnvironment
|
||||
from mozbuild.util import FileAvoidWrite
|
||||
import mozpack.path as mozpath
|
||||
|
||||
|
||||
def process_define_file(output, input):
|
||||
'''Creates the given config header. A config header is generated by
|
||||
taking the corresponding source file and replacing some #define/#undef
|
||||
occurences:
|
||||
"#undef NAME" is turned into "#define NAME VALUE"
|
||||
"#define NAME" is unchanged
|
||||
"#define NAME ORIGINAL_VALUE" is turned into "#define NAME VALUE"
|
||||
"#undef UNKNOWN_NAME" is turned into "/* #undef UNKNOWN_NAME */"
|
||||
Whitespaces are preserved.
|
||||
|
||||
As a special rule, "#undef ALLDEFINES" is turned into "#define NAME
|
||||
VALUE" for all the defined variables.
|
||||
'''
|
||||
|
||||
path = os.path.abspath(input)
|
||||
|
||||
config = ConfigEnvironment.from_config_status(
|
||||
mozpath.join(topobjdir, 'config.status'))
|
||||
|
||||
if mozpath.basedir(path,
|
||||
[mozpath.join(config.topsrcdir, 'js/src')]) and \
|
||||
not config.substs.get('JS_STANDALONE'):
|
||||
config = ConfigEnvironment.from_config_status(
|
||||
mozpath.join(topobjdir, 'js', 'src', 'config.status'))
|
||||
|
||||
with open(path, 'rU') as input:
|
||||
r = re.compile('^\s*#\s*(?P<cmd>[a-z]+)(?:\s+(?P<name>\S+)(?:\s+(?P<value>\S+))?)?', re.U)
|
||||
for l in input:
|
||||
m = r.match(l)
|
||||
if m:
|
||||
cmd = m.group('cmd')
|
||||
name = m.group('name')
|
||||
value = m.group('value')
|
||||
if name:
|
||||
if name == 'ALLDEFINES':
|
||||
if cmd == 'define':
|
||||
raise Exception(
|
||||
'`#define ALLDEFINES` is not allowed in a '
|
||||
'CONFIGURE_DEFINE_FILE')
|
||||
defines = '\n'.join(sorted(
|
||||
'#define %s %s' % (name, val)
|
||||
for name, val in config.defines.iteritems()
|
||||
if name not in config.non_global_defines))
|
||||
l = l[:m.start('cmd') - 1] \
|
||||
+ defines + l[m.end('name'):]
|
||||
elif name in config.defines:
|
||||
if cmd == 'define' and value:
|
||||
l = l[:m.start('value')] \
|
||||
+ str(config.defines[name]) \
|
||||
+ l[m.end('value'):]
|
||||
elif cmd == 'undef':
|
||||
l = l[:m.start('cmd')] \
|
||||
+ 'define' \
|
||||
+ l[m.end('cmd'):m.end('name')] \
|
||||
+ ' ' \
|
||||
+ str(config.defines[name]) \
|
||||
+ l[m.end('name'):]
|
||||
elif cmd == 'undef':
|
||||
l = '/* ' + l[:m.end('name')] + ' */' + l[m.end('name'):]
|
||||
|
||||
output.write(l)
|
||||
|
||||
return {config.source}
|
||||
|
||||
|
||||
def main(argv):
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Process define files.')
|
||||
|
||||
parser.add_argument('input', help='Input define file.')
|
||||
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
return process_define_file(sys.stdout, args.input)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv[1:]))
|
||||
@@ -17,7 +17,6 @@ from .base import BuildBackend
|
||||
from ..frontend.data import (
|
||||
ConfigFileSubstitution,
|
||||
ExampleWebIDLInterface,
|
||||
HeaderFileSubstitution,
|
||||
IPDLFile,
|
||||
GeneratedEventWebIDLFile,
|
||||
GeneratedWebIDLFile,
|
||||
@@ -211,10 +210,6 @@ class CommonBackend(BuildBackend):
|
||||
pp.do_include(obj.input_path)
|
||||
self.backend_input_files.add(obj.input_path)
|
||||
|
||||
elif isinstance(obj, HeaderFileSubstitution):
|
||||
self._create_config_header(obj)
|
||||
self.backend_input_files.add(obj.input_path)
|
||||
|
||||
# We should consider aggregating WebIDL types in emitter.py.
|
||||
elif isinstance(obj, WebIDLFile):
|
||||
self._webidls.sources.add(mozpath.join(obj.srcdir, obj.basename))
|
||||
@@ -372,54 +367,3 @@ class CommonBackend(BuildBackend):
|
||||
for unified_file, source_filenames in unified_source_mapping:
|
||||
self._write_unified_file(unified_file, source_filenames,
|
||||
output_directory, poison_windows_h)
|
||||
|
||||
def _create_config_header(self, obj):
|
||||
'''Creates the given config header. A config header is generated by
|
||||
taking the corresponding source file and replacing some #define/#undef
|
||||
occurences:
|
||||
"#undef NAME" is turned into "#define NAME VALUE"
|
||||
"#define NAME" is unchanged
|
||||
"#define NAME ORIGINAL_VALUE" is turned into "#define NAME VALUE"
|
||||
"#undef UNKNOWN_NAME" is turned into "/* #undef UNKNOWN_NAME */"
|
||||
Whitespaces are preserved.
|
||||
|
||||
As a special rule, "#undef ALLDEFINES" is turned into "#define NAME
|
||||
VALUE" for all the defined variables.
|
||||
'''
|
||||
with self._write_file(obj.output_path) as fh, \
|
||||
open(obj.input_path, 'rU') as input:
|
||||
r = re.compile('^\s*#\s*(?P<cmd>[a-z]+)(?:\s+(?P<name>\S+)(?:\s+(?P<value>\S+))?)?', re.U)
|
||||
for l in input:
|
||||
m = r.match(l)
|
||||
if m:
|
||||
cmd = m.group('cmd')
|
||||
name = m.group('name')
|
||||
value = m.group('value')
|
||||
if name:
|
||||
if name == 'ALLDEFINES':
|
||||
if cmd == 'define':
|
||||
raise Exception(
|
||||
'`#define ALLDEFINES` is not allowed in a '
|
||||
'CONFIGURE_DEFINE_FILE')
|
||||
defines = '\n'.join(sorted(
|
||||
'#define %s %s' % (name, val)
|
||||
for name, val in obj.config.defines.iteritems()
|
||||
if name not in obj.config.non_global_defines))
|
||||
l = l[:m.start('cmd') - 1] \
|
||||
+ defines + l[m.end('name'):]
|
||||
elif name in obj.config.defines:
|
||||
if cmd == 'define' and value:
|
||||
l = l[:m.start('value')] \
|
||||
+ str(obj.config.defines[name]) \
|
||||
+ l[m.end('value'):]
|
||||
elif cmd == 'undef':
|
||||
l = l[:m.start('cmd')] \
|
||||
+ 'define' \
|
||||
+ l[m.end('cmd'):m.end('name')] \
|
||||
+ ' ' \
|
||||
+ str(obj.config.defines[name]) \
|
||||
+ l[m.end('name'):]
|
||||
elif cmd == 'undef':
|
||||
l = '/* ' + l[:m.end('name')] + ' */' + l[m.end('name'):]
|
||||
|
||||
fh.write(l)
|
||||
|
||||
@@ -32,10 +32,11 @@ ANDROID_IDE_ADVERTISEMENT = '''
|
||||
=============
|
||||
ADVERTISEMENT
|
||||
|
||||
You are building Firefox for Android. After your build completes, you
|
||||
should run `mach gradle-install` to prepare Gradle and IntelliJ/Android Studio
|
||||
integration. Then import the Gradle project at $OBJDIR/mobile/android/gradle
|
||||
into the IDE of your choice.
|
||||
You are building Firefox for Android. After your build completes, you can open
|
||||
the top source directory in IntelliJ or Android Studio directly and build using
|
||||
Gradle. See the documentation at
|
||||
|
||||
https://developer.mozilla.org/en-US/docs/Simple_Firefox_for_Android_build
|
||||
|
||||
PLEASE BE AWARE THAT GRADLE AND INTELLIJ/ANDROID STUDIO SUPPORT IS EXPERIMENTAL.
|
||||
You should verify any changes using |mach build|.
|
||||
|
||||
@@ -127,10 +127,6 @@ class ConfigFileSubstitution(BaseConfigSubstitution):
|
||||
"""Describes a config file that will be generated using substitutions."""
|
||||
|
||||
|
||||
class HeaderFileSubstitution(BaseConfigSubstitution):
|
||||
"""Describes a header file that will be generated using substitutions."""
|
||||
|
||||
|
||||
class VariablePassthru(ContextDerived):
|
||||
"""A dict of variables to pass through to backend.mk unaltered.
|
||||
|
||||
|
||||
@@ -43,7 +43,6 @@ from .data import (
|
||||
ExampleWebIDLInterface,
|
||||
ExternalStaticLibrary,
|
||||
ExternalSharedLibrary,
|
||||
HeaderFileSubstitution,
|
||||
HostDefines,
|
||||
HostLibrary,
|
||||
HostProgram,
|
||||
@@ -542,8 +541,10 @@ class TreeMetadataEmitter(LoggingMixin):
|
||||
path)
|
||||
|
||||
for path in context['CONFIGURE_DEFINE_FILES']:
|
||||
yield self._create_substitution(HeaderFileSubstitution, context,
|
||||
path)
|
||||
script = mozpath.join(mozpath.dirname(mozpath.dirname(__file__)),
|
||||
'action', 'process_define_files.py')
|
||||
yield GeneratedFile(context, script, 'process_define_file', path,
|
||||
[mozpath.join(context.srcdir, path + '.in')])
|
||||
|
||||
for obj in self._process_xpidl(context):
|
||||
yield obj
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
/* Comment */
|
||||
#define foo
|
||||
#define foo 42
|
||||
#undef foo
|
||||
#define bar
|
||||
#define bar 42
|
||||
#undef bar
|
||||
|
||||
# undef baz
|
||||
|
||||
#ifdef foo
|
||||
# undef foo
|
||||
# define foo 42
|
||||
# define foo 42
|
||||
#endif
|
||||
@@ -1,6 +1,3 @@
|
||||
CONFIGURE_SUBST_FILES = [
|
||||
'file',
|
||||
]
|
||||
CONFIGURE_DEFINE_FILES = [
|
||||
'file.h',
|
||||
]
|
||||
|
||||
@@ -681,8 +681,7 @@ class TestRecursiveMakeBackend(BackendTester):
|
||||
self.assertEqual(found, expected)
|
||||
|
||||
def test_config(self):
|
||||
"""Test that CONFIGURE_SUBST_FILES and CONFIGURE_DEFINE_FILES are
|
||||
properly handled."""
|
||||
"""Test that CONFIGURE_SUBST_FILES are properly handled."""
|
||||
env = self._consume('test_config', RecursiveMakeBackend)
|
||||
|
||||
self.assertEqual(
|
||||
@@ -692,25 +691,6 @@ class TestRecursiveMakeBackend(BackendTester):
|
||||
'@bar@\n',
|
||||
])
|
||||
|
||||
self.assertEqual(
|
||||
open(os.path.join(env.topobjdir, 'file.h'), 'r').readlines(), [
|
||||
'/* Comment */\n',
|
||||
'#define foo\n',
|
||||
'#define foo baz qux\n',
|
||||
'#define foo baz qux\n',
|
||||
'#define bar\n',
|
||||
'#define bar 42\n',
|
||||
'/* #undef bar */\n',
|
||||
'\n',
|
||||
'# define baz 1\n',
|
||||
'\n',
|
||||
'#ifdef foo\n',
|
||||
'# define foo baz qux\n',
|
||||
'# define foo baz qux\n',
|
||||
' # define foo baz qux \n',
|
||||
'#endif\n',
|
||||
])
|
||||
|
||||
def test_jar_manifests(self):
|
||||
env = self._consume('jar-manifests', RecursiveMakeBackend)
|
||||
|
||||
|
||||
@@ -412,6 +412,64 @@ class TestStrictOrderingOnAppendListWithFlagsFactory(unittest.TestCase):
|
||||
with self.assertRaises(AttributeError):
|
||||
l['b'].update(xyz=1)
|
||||
|
||||
def test_strict_ordering_on_append_list_with_flags_factory_extend(self):
|
||||
FooList = StrictOrderingOnAppendListWithFlagsFactory({
|
||||
'foo': bool, 'bar': unicode
|
||||
})
|
||||
foo = FooList(['a', 'b', 'c'])
|
||||
foo['a'].foo = True
|
||||
foo['b'].bar = 'bar'
|
||||
|
||||
# Don't allow extending lists with different flag definitions.
|
||||
BarList = StrictOrderingOnAppendListWithFlagsFactory({
|
||||
'foo': unicode, 'baz': bool
|
||||
})
|
||||
bar = BarList(['d', 'e', 'f'])
|
||||
bar['d'].foo = 'foo'
|
||||
bar['e'].baz = True
|
||||
with self.assertRaises(ValueError):
|
||||
foo + bar
|
||||
with self.assertRaises(ValueError):
|
||||
bar + foo
|
||||
|
||||
# It's not obvious what to do with duplicate list items with possibly
|
||||
# different flag values, so don't allow that case.
|
||||
with self.assertRaises(ValueError):
|
||||
foo + foo
|
||||
|
||||
def assertExtended(l):
|
||||
self.assertEqual(len(l), 6)
|
||||
self.assertEqual(l['a'].foo, True)
|
||||
self.assertEqual(l['b'].bar, 'bar')
|
||||
self.assertTrue('c' in l)
|
||||
self.assertEqual(l['d'].foo, True)
|
||||
self.assertEqual(l['e'].bar, 'bar')
|
||||
self.assertTrue('f' in l)
|
||||
|
||||
# Test extend.
|
||||
zot = FooList(['d', 'e', 'f'])
|
||||
zot['d'].foo = True
|
||||
zot['e'].bar = 'bar'
|
||||
zot.extend(foo)
|
||||
assertExtended(zot)
|
||||
|
||||
# Test __add__.
|
||||
zot = FooList(['d', 'e', 'f'])
|
||||
zot['d'].foo = True
|
||||
zot['e'].bar = 'bar'
|
||||
assertExtended(foo + zot)
|
||||
assertExtended(zot + foo)
|
||||
|
||||
# Test __iadd__.
|
||||
foo += zot
|
||||
assertExtended(foo)
|
||||
|
||||
# Test __setslice__.
|
||||
foo[3:] = []
|
||||
self.assertEqual(len(foo), 3)
|
||||
foo[3:] = zot
|
||||
assertExtended(foo)
|
||||
|
||||
|
||||
class TestHierarchicalStringListWithFlagsFactory(unittest.TestCase):
|
||||
def test_hierarchical_string_list_with_flags_factory(self):
|
||||
|
||||
@@ -426,6 +426,14 @@ def FlagsFactory(flags):
|
||||
return Flags
|
||||
|
||||
|
||||
class StrictOrderingOnAppendListWithFlags(StrictOrderingOnAppendList):
|
||||
"""A list with flags specialized for moz.build environments.
|
||||
|
||||
Each subclass has a set of typed flags; this class lets us use `isinstance`
|
||||
for natural testing.
|
||||
"""
|
||||
|
||||
|
||||
def StrictOrderingOnAppendListWithFlagsFactory(flags):
|
||||
"""Returns a StrictOrderingOnAppendList-like object, with optional
|
||||
flags on each item.
|
||||
@@ -441,9 +449,9 @@ def StrictOrderingOnAppendListWithFlagsFactory(flags):
|
||||
foo['a'].foo = True
|
||||
foo['b'].bar = 'bar'
|
||||
"""
|
||||
class StrictOrderingOnAppendListWithFlags(StrictOrderingOnAppendList):
|
||||
class StrictOrderingOnAppendListWithFlagsSpecialization(StrictOrderingOnAppendListWithFlags):
|
||||
def __init__(self, iterable=[]):
|
||||
StrictOrderingOnAppendList.__init__(self, iterable)
|
||||
StrictOrderingOnAppendListWithFlags.__init__(self, iterable)
|
||||
self._flags_type = FlagsFactory(flags)
|
||||
self._flags = dict()
|
||||
|
||||
@@ -458,7 +466,50 @@ def StrictOrderingOnAppendListWithFlagsFactory(flags):
|
||||
raise TypeError("'%s' object does not support item assignment" %
|
||||
self.__class__.__name__)
|
||||
|
||||
return StrictOrderingOnAppendListWithFlags
|
||||
def _update_flags(self, other):
|
||||
if self._flags_type._flags != other._flags_type._flags:
|
||||
raise ValueError('Expected a list of strings with flags like %s, not like %s' %
|
||||
(self._flags_type._flags, other._flags_type._flags))
|
||||
intersection = set(self._flags.keys()) & set(other._flags.keys())
|
||||
if intersection:
|
||||
raise ValueError('Cannot update flags: both lists of strings with flags configure %s' %
|
||||
intersection)
|
||||
self._flags.update(other._flags)
|
||||
|
||||
def extend(self, l):
|
||||
result = super(StrictOrderingOnAppendList, self).extend(l)
|
||||
if isinstance(l, StrictOrderingOnAppendListWithFlags):
|
||||
self._update_flags(l)
|
||||
return result
|
||||
|
||||
def __setslice__(self, i, j, sequence):
|
||||
result = super(StrictOrderingOnAppendList, self).__setslice__(i, j, sequence)
|
||||
# We may have removed items.
|
||||
for name in set(self._flags.keys()) - set(self):
|
||||
del self._flags[name]
|
||||
if isinstance(sequence, StrictOrderingOnAppendListWithFlags):
|
||||
self._update_flags(sequence)
|
||||
return result
|
||||
|
||||
def __add__(self, other):
|
||||
result = super(StrictOrderingOnAppendList, self).__add__(other)
|
||||
if isinstance(other, StrictOrderingOnAppendListWithFlags):
|
||||
# Result has flags from other but not from self, since
|
||||
# internally we duplicate self and then extend with other, and
|
||||
# only extend knows about flags. Since we don't allow updating
|
||||
# when the set of flag keys intersect, which we instance we pass
|
||||
# to _update_flags here matters. This needs to be correct but
|
||||
# is an implementation detail.
|
||||
result._update_flags(self)
|
||||
return result
|
||||
|
||||
def __iadd__(self, other):
|
||||
result = super(StrictOrderingOnAppendList, self).__iadd__(other)
|
||||
if isinstance(other, StrictOrderingOnAppendListWithFlags):
|
||||
self._update_flags(other)
|
||||
return result
|
||||
|
||||
return StrictOrderingOnAppendListWithFlagsSpecialization
|
||||
|
||||
|
||||
class HierarchicalStringList(object):
|
||||
|
||||
@@ -325,7 +325,7 @@ MANIFESTS_TYPES = dict([(c.type, c) for c in globals().values()
|
||||
if type(c) == type and issubclass(c, ManifestEntry)
|
||||
and hasattr(c, 'type') and c.type])
|
||||
|
||||
MANIFEST_RE = re.compile(r'\s*#.*$')
|
||||
MANIFEST_RE = re.compile(r'^#.*$')
|
||||
|
||||
|
||||
def parse_manifest_line(base, line):
|
||||
|
||||
@@ -46,7 +46,7 @@ class TestManifest(unittest.TestCase):
|
||||
'component {b2bba4df-057d-41ea-b6b1-94a10a8ede68} foo.js',
|
||||
'contract @mozilla.org/foo;1' +
|
||||
' {b2bba4df-057d-41ea-b6b1-94a10a8ede68}',
|
||||
'interfaces foo.xpt # Inline comment',
|
||||
'interfaces foo.xpt',
|
||||
'binary-component bar.so',
|
||||
'category command-line-handler m-browser' +
|
||||
' @mozilla.org/browser/clh;1' +
|
||||
|
||||
@@ -1,15 +1,29 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
from setuptools import setup
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
VERSION = '0.1'
|
||||
VERSION = '0.2'
|
||||
|
||||
setup(
|
||||
author='Mozilla Foundation',
|
||||
author_email='dev-builds@lists.mozilla.org',
|
||||
name='mozbuild',
|
||||
description='Mozilla build system functionality.',
|
||||
license='MPL 2.0',
|
||||
packages=['mach', 'mozbuild', 'mozpack'],
|
||||
version=VERSION
|
||||
packages=find_packages(),
|
||||
version=VERSION,
|
||||
install_requires=[
|
||||
'jsmin',
|
||||
'mozfile',
|
||||
],
|
||||
classifiers=[
|
||||
'Development Status :: 3 - Alpha',
|
||||
'Topic :: Software Development :: Build Tools',
|
||||
'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: Implementation :: CPython',
|
||||
],
|
||||
keywords='mozilla build',
|
||||
)
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
Revision 0.0.5
|
||||
--------------
|
||||
|
||||
- License updated to vanilla BSD 2-Clause to ease package use
|
||||
(http://opensource.org/licenses/BSD-2-Clause).
|
||||
|
||||
Revision 0.0.4
|
||||
--------------
|
||||
|
||||
- CMP structures (RFC4210), cmpdump.py tool and test case added.
|
||||
- SNMPv2c Message syntax (RFC1901) properly defined.
|
||||
- Package version established in form of __init__.__version__
|
||||
which is in-sync with distutils.
|
||||
- Package meta information and classifiers updated.
|
||||
|
||||
Revision 0.0.3
|
||||
--------------
|
||||
|
||||
- Text cases implemented
|
||||
- X.509 CRMF structures (RFC2511) and crmfdump.py tool added
|
||||
- X.509 CRL structures and crldump.py tool added
|
||||
- PKCS#10 structures and pkcs10dump.py tool added
|
||||
- PKCS#8 structures and pkcs8dump.py tool added
|
||||
- PKCS#1 (rfc3447) structures added
|
||||
- OCSP request & response dumping tool added
|
||||
- SNMPv2c & SNMPv3/USM structures added
|
||||
- keydump.py moved into pkcs1dump.py
|
||||
- PEM files read function generalized to be used more universally.
|
||||
- complete PKIX1 '88 code implemented at rfc2459.py
|
||||
|
||||
|
||||
Revision 0.0.2
|
||||
--------------
|
||||
|
||||
- Require pyasn1 >= 0.1.1
|
||||
- Fixes towards Py3K compatibility
|
||||
+ use either of existing urllib module
|
||||
+ adopt to the new bytes type
|
||||
+ print operator is now a function
|
||||
+ new exception syntax
|
||||
|
||||
Revision 0.0.1a
|
||||
---------------
|
||||
|
||||
- Initial revision, most code carried from pyasn1 examples.
|
||||
@@ -0,0 +1,24 @@
|
||||
Copyright (c) 2005-2013, Ilya Etingof <ilya@glas.net>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,3 @@
|
||||
include CHANGES README LICENSE
|
||||
recursive-include tools *.py
|
||||
recursive-include test *.sh
|
||||
@@ -0,0 +1,26 @@
|
||||
Metadata-Version: 1.0
|
||||
Name: pyasn1-modules
|
||||
Version: 0.0.5
|
||||
Summary: A collection of ASN.1-based protocols modules.
|
||||
Home-page: http://sourceforge.net/projects/pyasn1/
|
||||
Author: Ilya Etingof <ilya@glas.net>
|
||||
Author-email: ilya@glas.net
|
||||
License: BSD
|
||||
Description: A collection of ASN.1 modules expressed in form of pyasn1 classes. Includes protocols PDUs definition (SNMP, LDAP etc.) and various data structures (X.509, PKCS etc.).
|
||||
Platform: any
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Environment :: Console
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Intended Audience :: Education
|
||||
Classifier: Intended Audience :: Information Technology
|
||||
Classifier: Intended Audience :: Science/Research
|
||||
Classifier: Intended Audience :: System Administrators
|
||||
Classifier: Intended Audience :: Telecommunications Industry
|
||||
Classifier: License :: OSI Approved :: BSD License
|
||||
Classifier: Natural Language :: English
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Topic :: Communications
|
||||
Classifier: Topic :: Security :: Cryptography
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
ASN.1 modules for Python
|
||||
------------------------
|
||||
|
||||
This is a small but growing collection of ASN.1 data structures
|
||||
[1] expressed in Python terms using pyasn1 [2] data model.
|
||||
|
||||
It's thought to be useful to protocol developers and testers.
|
||||
|
||||
All modules are py2k/py3k-compliant.
|
||||
|
||||
If you happen to convert some ASN.1 module into pyasn1 that is not
|
||||
yet present in this collection and wish to contribute - please send
|
||||
it to me.
|
||||
|
||||
=-=-=
|
||||
mailto: ilya@glas.net
|
||||
@@ -0,0 +1,26 @@
|
||||
Metadata-Version: 1.0
|
||||
Name: pyasn1-modules
|
||||
Version: 0.0.5
|
||||
Summary: A collection of ASN.1-based protocols modules.
|
||||
Home-page: http://sourceforge.net/projects/pyasn1/
|
||||
Author: Ilya Etingof <ilya@glas.net>
|
||||
Author-email: ilya@glas.net
|
||||
License: BSD
|
||||
Description: A collection of ASN.1 modules expressed in form of pyasn1 classes. Includes protocols PDUs definition (SNMP, LDAP etc.) and various data structures (X.509, PKCS etc.).
|
||||
Platform: any
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Environment :: Console
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Intended Audience :: Education
|
||||
Classifier: Intended Audience :: Information Technology
|
||||
Classifier: Intended Audience :: Science/Research
|
||||
Classifier: Intended Audience :: System Administrators
|
||||
Classifier: Intended Audience :: Telecommunications Industry
|
||||
Classifier: License :: OSI Approved :: BSD License
|
||||
Classifier: Natural Language :: English
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Topic :: Communications
|
||||
Classifier: Topic :: Security :: Cryptography
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
@@ -0,0 +1,54 @@
|
||||
CHANGES
|
||||
LICENSE
|
||||
MANIFEST.in
|
||||
README
|
||||
setup.py
|
||||
pyasn1_modules/__init__.py
|
||||
pyasn1_modules/pem.py
|
||||
pyasn1_modules/pkcs12.py
|
||||
pyasn1_modules/rfc1155.py
|
||||
pyasn1_modules/rfc1157.py
|
||||
pyasn1_modules/rfc1901.py
|
||||
pyasn1_modules/rfc1902.py
|
||||
pyasn1_modules/rfc1905.py
|
||||
pyasn1_modules/rfc2251.py
|
||||
pyasn1_modules/rfc2314.py
|
||||
pyasn1_modules/rfc2315.py
|
||||
pyasn1_modules/rfc2437.py
|
||||
pyasn1_modules/rfc2459.py
|
||||
pyasn1_modules/rfc2511.py
|
||||
pyasn1_modules/rfc2560.py
|
||||
pyasn1_modules/rfc3412.py
|
||||
pyasn1_modules/rfc3414.py
|
||||
pyasn1_modules/rfc3447.py
|
||||
pyasn1_modules/rfc4210.py
|
||||
pyasn1_modules/rfc5208.py
|
||||
pyasn1_modules.egg-info/PKG-INFO
|
||||
pyasn1_modules.egg-info/SOURCES.txt
|
||||
pyasn1_modules.egg-info/dependency_links.txt
|
||||
pyasn1_modules.egg-info/requires.txt
|
||||
pyasn1_modules.egg-info/top_level.txt
|
||||
pyasn1_modules.egg-info/zip-safe
|
||||
test/cmp.sh
|
||||
test/crl.sh
|
||||
test/crmf.sh
|
||||
test/ocspreq.sh
|
||||
test/ocsprsp.sh
|
||||
test/pkcs1.sh
|
||||
test/pkcs10.sh
|
||||
test/pkcs7.sh
|
||||
test/pkcs8.sh
|
||||
test/x509dump.sh
|
||||
tools/cmpdump.py
|
||||
tools/crldump.py
|
||||
tools/crmfdump.py
|
||||
tools/ocspclient.py
|
||||
tools/ocspreqdump.py
|
||||
tools/ocsprspdump.py
|
||||
tools/ocspserver.py
|
||||
tools/pkcs10dump.py
|
||||
tools/pkcs1dump.py
|
||||
tools/pkcs7dump.py
|
||||
tools/pkcs8dump.py
|
||||
tools/snmpget.py
|
||||
tools/x509dump.py
|
||||
@@ -0,0 +1 @@
|
||||
pyasn1>=0.1.4
|
||||
@@ -0,0 +1 @@
|
||||
pyasn1_modules
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# http://www.python.org/dev/peps/pep-0396/
|
||||
__version__ = '0.0.5'
|
||||
@@ -0,0 +1,51 @@
|
||||
import base64, sys
|
||||
|
||||
stSpam, stHam, stDump = 0, 1, 2
|
||||
|
||||
# The markers parameters is in form ('start1', 'stop1'), ('start2', 'stop2')...
|
||||
# Return is (marker-index, substrate)
|
||||
def readPemBlocksFromFile(fileObj, *markers):
|
||||
startMarkers = dict(map(lambda x: (x[1],x[0]),
|
||||
enumerate(map(lambda x: x[0], markers))))
|
||||
stopMarkers = dict(map(lambda x: (x[1],x[0]),
|
||||
enumerate(map(lambda x: x[1], markers))))
|
||||
idx = -1; substrate = ''
|
||||
state = stSpam
|
||||
while 1:
|
||||
certLine = fileObj.readline()
|
||||
if not certLine:
|
||||
break
|
||||
certLine = certLine.strip()
|
||||
if state == stSpam:
|
||||
if certLine in startMarkers:
|
||||
certLines = []
|
||||
idx = startMarkers[certLine]
|
||||
state = stHam
|
||||
continue
|
||||
if state == stHam:
|
||||
if certLine in stopMarkers and stopMarkers[certLine] == idx:
|
||||
state = stDump
|
||||
else:
|
||||
certLines.append(certLine)
|
||||
if state == stDump:
|
||||
if sys.version_info[0] <= 2:
|
||||
substrate = ''.join([ base64.b64decode(x) for x in certLines ])
|
||||
else:
|
||||
substrate = ''.encode().join([ base64.b64decode(x.encode()) for x in certLines ])
|
||||
break
|
||||
return idx, substrate
|
||||
|
||||
# Backward compatibility routine
|
||||
def readPemFromFile(fileObj,
|
||||
startMarker='-----BEGIN CERTIFICATE-----',
|
||||
endMarker='-----END CERTIFICATE-----'):
|
||||
idx, substrate = readPemBlocksFromFile(fileObj, (startMarker, endMarker))
|
||||
return substrate
|
||||
|
||||
def readBase64FromFile(fileObj):
|
||||
if sys.version_info[0] <= 2:
|
||||
return ''.join([ base64.b64decode(x) for x in fileObj.readlines() ])
|
||||
else:
|
||||
return ''.encode().join(
|
||||
[ base64.b64decode(x.encode()) for x in fileObj.readlines() ]
|
||||
)
|
||||
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# PKCS#12 syntax
|
||||
#
|
||||
# ASN.1 source from:
|
||||
# ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12.asn
|
||||
#
|
||||
# Sample captures could be obtained with "openssl pkcs12" command
|
||||
#
|
||||
from pyasn1.type import tag, namedtype, namedval, univ, constraint
|
||||
from pyasn1_modules.rfc2459 import *
|
||||
from pyasn1_modules import rfc2251
|
||||
|
||||
class Attributes(univ.SetOf):
|
||||
componentType = rfc2251.Attribute()
|
||||
|
||||
class Version(univ.Integer): pass
|
||||
|
||||
class CertificationRequestInfo(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('version', Version()),
|
||||
namedtype.NamedType('subject', Name()),
|
||||
namedtype.NamedType('subjectPublicKeyInfo', SubjectPublicKeyInfo()),
|
||||
namedtype.NamedType('attributes', Attributes().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
|
||||
)
|
||||
|
||||
class Signature(univ.BitString): pass
|
||||
class SignatureAlgorithmIdentifier(AlgorithmIdentifier): pass
|
||||
|
||||
class CertificationRequest(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('certificationRequestInfo', CertificationRequestInfo()),
|
||||
namedtype.NamedType('signatureAlgorithm', SignatureAlgorithmIdentifier()),
|
||||
namedtype.NamedType('signature', Signature())
|
||||
)
|
||||
@@ -0,0 +1,73 @@
|
||||
#
|
||||
# SNMPv1 message syntax
|
||||
#
|
||||
# ASN.1 source from:
|
||||
# http://www.ietf.org/rfc/rfc1155.txt
|
||||
#
|
||||
# Sample captures from:
|
||||
# http://wiki.wireshark.org/SampleCaptures/
|
||||
#
|
||||
from pyasn1.type import univ, namedtype, namedval, tag, constraint
|
||||
|
||||
class ObjectName(univ.ObjectIdentifier): pass
|
||||
|
||||
class SimpleSyntax(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('number', univ.Integer()),
|
||||
namedtype.NamedType('string', univ.OctetString()),
|
||||
namedtype.NamedType('object', univ.ObjectIdentifier()),
|
||||
namedtype.NamedType('empty', univ.Null())
|
||||
)
|
||||
|
||||
class IpAddress(univ.OctetString):
|
||||
tagSet = univ.OctetString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 0)
|
||||
)
|
||||
subtypeSpec = univ.Integer.subtypeSpec + constraint.ValueSizeConstraint(
|
||||
4, 4
|
||||
)
|
||||
class NetworkAddress(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('internet', IpAddress())
|
||||
)
|
||||
|
||||
class Counter(univ.Integer):
|
||||
tagSet = univ.Integer.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 1)
|
||||
)
|
||||
subtypeSpec = univ.Integer.subtypeSpec + constraint.ValueRangeConstraint(
|
||||
0, 4294967295
|
||||
)
|
||||
class Gauge(univ.Integer):
|
||||
tagSet = univ.Integer.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 2)
|
||||
)
|
||||
subtypeSpec = univ.Integer.subtypeSpec + constraint.ValueRangeConstraint(
|
||||
0, 4294967295
|
||||
)
|
||||
class TimeTicks(univ.Integer):
|
||||
tagSet = univ.Integer.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 3)
|
||||
)
|
||||
subtypeSpec = univ.Integer.subtypeSpec + constraint.ValueRangeConstraint(
|
||||
0, 4294967295
|
||||
)
|
||||
class Opaque(univ.OctetString):
|
||||
tagSet = univ.OctetString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 4)
|
||||
)
|
||||
|
||||
class ApplicationSyntax(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('address', NetworkAddress()),
|
||||
namedtype.NamedType('counter', Counter()),
|
||||
namedtype.NamedType('gauge', Gauge()),
|
||||
namedtype.NamedType('ticks', TimeTicks()),
|
||||
namedtype.NamedType('arbitrary', Opaque())
|
||||
)
|
||||
|
||||
class ObjectSyntax(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('simple', SimpleSyntax()),
|
||||
namedtype.NamedType('application-wide', ApplicationSyntax())
|
||||
)
|
||||
@@ -0,0 +1,90 @@
|
||||
#
|
||||
# SNMPv1 message syntax
|
||||
#
|
||||
# ASN.1 source from:
|
||||
# http://www.ietf.org/rfc/rfc1157.txt
|
||||
#
|
||||
# Sample captures from:
|
||||
# http://wiki.wireshark.org/SampleCaptures/
|
||||
#
|
||||
from pyasn1.type import univ, namedtype, namedval, tag, constraint
|
||||
from pyasn1_modules import rfc1155
|
||||
|
||||
class Version(univ.Integer):
|
||||
namedValues = namedval.NamedValues(
|
||||
('version-1', 0)
|
||||
)
|
||||
defaultValue = 0
|
||||
|
||||
class Community(univ.OctetString): pass
|
||||
|
||||
class RequestID(univ.Integer): pass
|
||||
class ErrorStatus(univ.Integer):
|
||||
namedValues = namedval.NamedValues(
|
||||
('noError', 0),
|
||||
('tooBig', 1),
|
||||
('noSuchName', 2),
|
||||
('badValue', 3),
|
||||
('readOnly', 4),
|
||||
('genErr', 5)
|
||||
)
|
||||
class ErrorIndex(univ.Integer): pass
|
||||
|
||||
class VarBind(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('name', rfc1155.ObjectName()),
|
||||
namedtype.NamedType('value', rfc1155.ObjectSyntax())
|
||||
)
|
||||
class VarBindList(univ.SequenceOf):
|
||||
componentType = VarBind()
|
||||
|
||||
class _RequestBase(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('request-id', RequestID()),
|
||||
namedtype.NamedType('error-status', ErrorStatus()),
|
||||
namedtype.NamedType('error-index', ErrorIndex()),
|
||||
namedtype.NamedType('variable-bindings', VarBindList())
|
||||
)
|
||||
|
||||
class GetRequestPDU(_RequestBase):
|
||||
tagSet = _RequestBase.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)
|
||||
)
|
||||
class GetNextRequestPDU(_RequestBase):
|
||||
tagSet = _RequestBase.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)
|
||||
)
|
||||
class GetResponsePDU(_RequestBase):
|
||||
tagSet = _RequestBase.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2)
|
||||
)
|
||||
class SetRequestPDU(_RequestBase):
|
||||
tagSet = _RequestBase.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3)
|
||||
)
|
||||
|
||||
class TrapPDU(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('enterprise', univ.ObjectIdentifier()),
|
||||
namedtype.NamedType('agent-addr', rfc1155.NetworkAddress()),
|
||||
namedtype.NamedType('generic-trap', univ.Integer().clone(namedValues=namedval.NamedValues(('coldStart', 0), ('warmStart', 1), ('linkDown', 2), ('linkUp', 3), ('authenticationFailure', 4), ('egpNeighborLoss', 5), ('enterpriseSpecific', 6)))),
|
||||
namedtype.NamedType('specific-trap', univ.Integer()),
|
||||
namedtype.NamedType('time-stamp', rfc1155.TimeTicks()),
|
||||
namedtype.NamedType('variable-bindings', VarBindList())
|
||||
)
|
||||
|
||||
class Pdus(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('get-request', GetRequestPDU()),
|
||||
namedtype.NamedType('get-next-request', GetNextRequestPDU()),
|
||||
namedtype.NamedType('get-response', GetResponsePDU()),
|
||||
namedtype.NamedType('set-request', SetRequestPDU()),
|
||||
namedtype.NamedType('trap', TrapPDU())
|
||||
)
|
||||
|
||||
class Message(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('version', Version()),
|
||||
namedtype.NamedType('community', Community()),
|
||||
namedtype.NamedType('data', Pdus())
|
||||
)
|
||||
@@ -0,0 +1,15 @@
|
||||
#
|
||||
# SNMPv2c message syntax
|
||||
#
|
||||
# ASN.1 source from:
|
||||
# http://www.ietf.org/rfc/rfc1901.txt
|
||||
#
|
||||
from pyasn1.type import univ, namedtype, namedval
|
||||
|
||||
class Message(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('version', univ.Integer(namedValues = namedval.NamedValues(('version-2c', 1)))),
|
||||
namedtype.NamedType('community', univ.OctetString()),
|
||||
namedtype.NamedType('data', univ.Any())
|
||||
)
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
#
|
||||
# SNMPv2c message syntax
|
||||
#
|
||||
# ASN.1 source from:
|
||||
# http://www.ietf.org/rfc/rfc1902.txt
|
||||
#
|
||||
from pyasn1.type import univ, namedtype, namedval, tag, constraint
|
||||
|
||||
class Integer(univ.Integer):
|
||||
subtypeSpec = univ.Integer.subtypeSpec+constraint.ValueRangeConstraint(
|
||||
-2147483648, 2147483647
|
||||
)
|
||||
|
||||
class Integer32(univ.Integer):
|
||||
subtypeSpec = univ.Integer.subtypeSpec+constraint.ValueRangeConstraint(
|
||||
-2147483648, 2147483647
|
||||
)
|
||||
|
||||
class OctetString(univ.OctetString):
|
||||
subtypeSpec = univ.Integer.subtypeSpec+constraint.ValueSizeConstraint(
|
||||
0, 65535
|
||||
)
|
||||
|
||||
class IpAddress(univ.OctetString):
|
||||
tagSet = univ.OctetString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 0x00)
|
||||
)
|
||||
subtypeSpec = univ.OctetString.subtypeSpec+constraint.ValueSizeConstraint(
|
||||
4, 4
|
||||
)
|
||||
|
||||
class Counter32(univ.Integer):
|
||||
tagSet = univ.Integer.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 0x01)
|
||||
)
|
||||
subtypeSpec = univ.Integer.subtypeSpec+constraint.ValueRangeConstraint(
|
||||
0, 4294967295
|
||||
)
|
||||
|
||||
class Gauge32(univ.Integer):
|
||||
tagSet = univ.Integer.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 0x02)
|
||||
)
|
||||
subtypeSpec = univ.Integer.subtypeSpec+constraint.ValueRangeConstraint(
|
||||
0, 4294967295
|
||||
)
|
||||
|
||||
class Unsigned32(univ.Integer):
|
||||
tagSet = univ.Integer.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 0x02)
|
||||
)
|
||||
subtypeSpec = univ.Integer.subtypeSpec+constraint.ValueRangeConstraint(
|
||||
0, 4294967295
|
||||
)
|
||||
|
||||
class TimeTicks(univ.Integer):
|
||||
tagSet = univ.Integer.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 0x03)
|
||||
)
|
||||
subtypeSpec = univ.Integer.subtypeSpec+constraint.ValueRangeConstraint(
|
||||
0, 4294967295
|
||||
)
|
||||
|
||||
class Opaque(univ.OctetString):
|
||||
tagSet = univ.OctetString.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 0x04)
|
||||
)
|
||||
|
||||
class Counter64(univ.Integer):
|
||||
tagSet = univ.Integer.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 0x06)
|
||||
)
|
||||
subtypeSpec = univ.Integer.subtypeSpec+constraint.ValueRangeConstraint(
|
||||
0, 18446744073709551615
|
||||
)
|
||||
|
||||
class Bits(univ.OctetString): pass
|
||||
|
||||
class ObjectName(univ.ObjectIdentifier): pass
|
||||
|
||||
class SimpleSyntax(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('integer-value', Integer()),
|
||||
namedtype.NamedType('string-value', OctetString()),
|
||||
namedtype.NamedType('objectID-value', univ.ObjectIdentifier())
|
||||
)
|
||||
|
||||
class ApplicationSyntax(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('ipAddress-value', IpAddress()),
|
||||
namedtype.NamedType('counter-value', Counter32()),
|
||||
namedtype.NamedType('timeticks-value', TimeTicks()),
|
||||
namedtype.NamedType('arbitrary-value', Opaque()),
|
||||
namedtype.NamedType('big-counter-value', Counter64()),
|
||||
# This conflicts with Counter32
|
||||
# namedtype.NamedType('unsigned-integer-value', Unsigned32()),
|
||||
namedtype.NamedType('gauge32-value', Gauge32())
|
||||
) # BITS misplaced?
|
||||
|
||||
class ObjectSyntax(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('simple', SimpleSyntax()),
|
||||
namedtype.NamedType('application-wide', ApplicationSyntax())
|
||||
)
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
#
|
||||
# SNMPv2c PDU syntax
|
||||
#
|
||||
# ASN.1 source from:
|
||||
# http://www.ietf.org/rfc/rfc1905.txt
|
||||
#
|
||||
from pyasn1.type import univ, namedtype, namedval, tag, constraint
|
||||
from pyasn1_modules import rfc1902
|
||||
|
||||
max_bindings = rfc1902.Integer(2147483647)
|
||||
|
||||
class _BindValue(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('value', rfc1902.ObjectSyntax()),
|
||||
namedtype.NamedType('unSpecified', univ.Null()),
|
||||
namedtype.NamedType('noSuchObject', univ.Null().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.NamedType('noSuchInstance', univ.Null().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
|
||||
namedtype.NamedType('endOfMibView', univ.Null().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2)))
|
||||
)
|
||||
|
||||
class VarBind(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('name', rfc1902.ObjectName()),
|
||||
namedtype.NamedType('', _BindValue())
|
||||
)
|
||||
|
||||
class VarBindList(univ.SequenceOf):
|
||||
componentType = VarBind()
|
||||
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(
|
||||
0, max_bindings
|
||||
)
|
||||
|
||||
class PDU(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('request-id', rfc1902.Integer32()),
|
||||
namedtype.NamedType('error-status', univ.Integer(namedValues=namedval.NamedValues(('noError', 0), ('tooBig', 1), ('noSuchName', 2), ('badValue', 3), ('readOnly', 4), ('genErr', 5), ('noAccess', 6), ('wrongType', 7), ('wrongLength', 8), ('wrongEncoding', 9), ('wrongValue', 10), ('noCreation', 11), ('inconsistentValue', 12), ('resourceUnavailable', 13), ('commitFailed', 14), ('undoFailed', 15), ('authorizationError', 16), ('notWritable', 17), ('inconsistentName', 18)))),
|
||||
namedtype.NamedType('error-index', univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, max_bindings))),
|
||||
namedtype.NamedType('variable-bindings', VarBindList())
|
||||
)
|
||||
|
||||
class BulkPDU(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('request-id', rfc1902.Integer32()),
|
||||
namedtype.NamedType('non-repeaters', univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, max_bindings))),
|
||||
namedtype.NamedType('max-repetitions', univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, max_bindings))),
|
||||
namedtype.NamedType('variable-bindings', VarBindList())
|
||||
)
|
||||
|
||||
class GetRequestPDU(PDU):
|
||||
tagSet = PDU.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)
|
||||
)
|
||||
|
||||
class GetNextRequestPDU(PDU):
|
||||
tagSet = PDU.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)
|
||||
)
|
||||
|
||||
class ResponsePDU(PDU):
|
||||
tagSet = PDU.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2)
|
||||
)
|
||||
|
||||
class SetRequestPDU(PDU):
|
||||
tagSet = PDU.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3)
|
||||
)
|
||||
|
||||
class GetBulkRequestPDU(BulkPDU):
|
||||
tagSet = PDU.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 5)
|
||||
)
|
||||
|
||||
class InformRequestPDU(PDU):
|
||||
tagSet = PDU.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 6)
|
||||
)
|
||||
|
||||
class SNMPv2TrapPDU(PDU):
|
||||
tagSet = PDU.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 7)
|
||||
)
|
||||
|
||||
class ReportPDU(PDU):
|
||||
tagSet = PDU.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 8)
|
||||
)
|
||||
|
||||
class PDUs(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('get-request', GetRequestPDU()),
|
||||
namedtype.NamedType('get-next-request', GetNextRequestPDU()),
|
||||
namedtype.NamedType('get-bulk-request', GetBulkRequestPDU()),
|
||||
namedtype.NamedType('response', ResponsePDU()),
|
||||
namedtype.NamedType('set-request', SetRequestPDU()),
|
||||
namedtype.NamedType('inform-request', InformRequestPDU()),
|
||||
namedtype.NamedType('snmpV2-trap', SNMPv2TrapPDU()),
|
||||
namedtype.NamedType('report', ReportPDU())
|
||||
)
|
||||
|
||||
@@ -0,0 +1,319 @@
|
||||
#
|
||||
# LDAP message syntax
|
||||
#
|
||||
# ASN.1 source from:
|
||||
# http://www.trl.ibm.com/projects/xml/xss4j/data/asn1/grammars/ldap.asn
|
||||
#
|
||||
# Sample captures from:
|
||||
# http://wiki.wireshark.org/SampleCaptures/
|
||||
#
|
||||
from pyasn1.type import tag, namedtype, namedval, univ, constraint,char,useful
|
||||
from pyasn1.codec.der import decoder, encoder
|
||||
|
||||
maxInt = univ.Integer(2147483647)
|
||||
|
||||
class LDAPString(univ.OctetString): pass
|
||||
class LDAPOID(univ.OctetString): pass
|
||||
|
||||
class LDAPDN(LDAPString): pass
|
||||
class RelativeLDAPDN(LDAPString): pass
|
||||
class AttributeType(LDAPString): pass
|
||||
class AttributeDescription(LDAPString): pass
|
||||
|
||||
class AttributeDescriptionList(univ.SequenceOf):
|
||||
componentType = AttributeDescription()
|
||||
|
||||
class AttributeValue(univ.OctetString): pass
|
||||
|
||||
class AssertionValue(univ.OctetString): pass
|
||||
|
||||
class AttributeValueAssertion(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('attributeDesc', AttributeDescription()),
|
||||
namedtype.NamedType('assertionValue', AssertionValue())
|
||||
)
|
||||
|
||||
class Attribute(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('type', AttributeDescription()),
|
||||
namedtype.NamedType('vals', univ.SetOf(componentType=AttributeValue()))
|
||||
)
|
||||
|
||||
class MatchingRuleId(LDAPString): pass
|
||||
|
||||
class Control(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('controlType', LDAPOID()),
|
||||
namedtype.DefaultedNamedType('criticality', univ.Boolean('False')),
|
||||
namedtype.OptionalNamedType('controlValue', univ.OctetString())
|
||||
)
|
||||
|
||||
class Controls(univ.SequenceOf):
|
||||
componentType = Control()
|
||||
|
||||
class LDAPURL(LDAPString): pass
|
||||
|
||||
class Referral(univ.SequenceOf):
|
||||
componentType = LDAPURL()
|
||||
|
||||
class SaslCredentials(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('mechanism', LDAPString()),
|
||||
namedtype.OptionalNamedType('credentials', univ.OctetString())
|
||||
)
|
||||
|
||||
class AuthenticationChoice(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('simple', univ.OctetString().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.NamedType('reserved-1', univ.OctetString().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
|
||||
namedtype.NamedType('reserved-2', univ.OctetString().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
|
||||
namedtype.NamedType('sasl', SaslCredentials().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3)))
|
||||
)
|
||||
|
||||
class BindRequest(univ.Sequence):
|
||||
tagSet = univ.Sequence.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 0)
|
||||
)
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('version', univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(1, 127))),
|
||||
namedtype.NamedType('name', LDAPDN()),
|
||||
namedtype.NamedType('authentication', AuthenticationChoice())
|
||||
)
|
||||
|
||||
class PartialAttributeList(univ.SequenceOf):
|
||||
componentType = univ.Sequence(componentType=namedtype.NamedTypes(namedtype.NamedType('type', AttributeDescription()), namedtype.NamedType('vals', univ.SetOf(componentType=AttributeValue()))))
|
||||
|
||||
class SearchResultEntry(univ.Sequence):
|
||||
tagSet = univ.Sequence.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 4)
|
||||
)
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('objectName', LDAPDN()),
|
||||
namedtype.NamedType('attributes', PartialAttributeList())
|
||||
)
|
||||
|
||||
class MatchingRuleAssertion(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.OptionalNamedType('matchingRule', MatchingRuleId().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
|
||||
namedtype.OptionalNamedType('type', AttributeDescription().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
|
||||
namedtype.NamedType('matchValue', AssertionValue().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))),
|
||||
namedtype.DefaultedNamedType('dnAttributes', univ.Boolean('False').subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4)))
|
||||
)
|
||||
|
||||
class SubstringFilter(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('type', AttributeDescription()),
|
||||
namedtype.NamedType('substrings', univ.SequenceOf(componentType=univ.Choice(componentType=namedtype.NamedTypes(namedtype.NamedType('initial', LDAPString().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))), namedtype.NamedType('any', LDAPString().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))), namedtype.NamedType('final', LDAPString().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2)))))))
|
||||
)
|
||||
|
||||
# Ugly hack to handle recursive Filter reference (up to 3-levels deep).
|
||||
|
||||
class Filter3(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('equalityMatch', AttributeValueAssertion().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3))),
|
||||
namedtype.NamedType('substrings', SubstringFilter().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 4))),
|
||||
namedtype.NamedType('greaterOrEqual', AttributeValueAssertion().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 5))),
|
||||
namedtype.NamedType('lessOrEqual', AttributeValueAssertion().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 6))),
|
||||
namedtype.NamedType('present', AttributeDescription().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 7))),
|
||||
namedtype.NamedType('approxMatch', AttributeValueAssertion().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 8))),
|
||||
namedtype.NamedType('extensibleMatch', MatchingRuleAssertion().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 9)))
|
||||
)
|
||||
|
||||
class Filter2(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('and', univ.SetOf(componentType=Filter3()).subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
|
||||
namedtype.NamedType('or', univ.SetOf(componentType=Filter3()).subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))),
|
||||
namedtype.NamedType('not', Filter3().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2))),
|
||||
namedtype.NamedType('equalityMatch', AttributeValueAssertion().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3))),
|
||||
namedtype.NamedType('substrings', SubstringFilter().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 4))),
|
||||
namedtype.NamedType('greaterOrEqual', AttributeValueAssertion().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 5))),
|
||||
namedtype.NamedType('lessOrEqual', AttributeValueAssertion().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 6))),
|
||||
namedtype.NamedType('present', AttributeDescription().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 7))),
|
||||
namedtype.NamedType('approxMatch', AttributeValueAssertion().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 8))),
|
||||
namedtype.NamedType('extensibleMatch', MatchingRuleAssertion().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 9)))
|
||||
)
|
||||
|
||||
class Filter(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('and', univ.SetOf(componentType=Filter2()).subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
|
||||
namedtype.NamedType('or', univ.SetOf(componentType=Filter2()).subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))),
|
||||
namedtype.NamedType('not', Filter2().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2))),
|
||||
namedtype.NamedType('equalityMatch', AttributeValueAssertion().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3))),
|
||||
namedtype.NamedType('substrings', SubstringFilter().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 4))),
|
||||
namedtype.NamedType('greaterOrEqual', AttributeValueAssertion().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 5))),
|
||||
namedtype.NamedType('lessOrEqual', AttributeValueAssertion().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 6))),
|
||||
namedtype.NamedType('present', AttributeDescription().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 7))),
|
||||
namedtype.NamedType('approxMatch', AttributeValueAssertion().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 8))),
|
||||
namedtype.NamedType('extensibleMatch', MatchingRuleAssertion().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 9)))
|
||||
)
|
||||
|
||||
# End of Filter hack
|
||||
|
||||
class SearchRequest(univ.Sequence):
|
||||
tagSet = univ.Sequence.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 3)
|
||||
)
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('baseObject', LDAPDN()),
|
||||
namedtype.NamedType('scope', univ.Enumerated(namedValues=namedval.NamedValues(('baseObject', 0), ('singleLevel', 1), ('wholeSubtree', 2)))),
|
||||
namedtype.NamedType('derefAliases', univ.Enumerated(namedValues=namedval.NamedValues(('neverDerefAliases', 0), ('derefInSearching', 1), ('derefFindingBaseObj', 2), ('derefAlways', 3)))),
|
||||
namedtype.NamedType('sizeLimit', univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, maxInt))),
|
||||
namedtype.NamedType('timeLimit', univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, maxInt))),
|
||||
namedtype.NamedType('typesOnly', univ.Boolean()),
|
||||
namedtype.NamedType('filter', Filter()),
|
||||
namedtype.NamedType('attributes', AttributeDescriptionList())
|
||||
)
|
||||
|
||||
class UnbindRequest(univ.Null):
|
||||
tagSet = univ.Sequence.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 2)
|
||||
)
|
||||
|
||||
class BindResponse(univ.Sequence):
|
||||
tagSet = univ.Sequence.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 1)
|
||||
)
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('resultCode', univ.Enumerated(namedValues=namedval.NamedValues(('success', 0), ('operationsError', 1), ('protocolError', 2), ('timeLimitExceeded', 3), ('sizeLimitExceeded', 4), ('compareFalse', 5), ('compareTrue', 6), ('authMethodNotSupported', 7), ('strongAuthRequired', 8), ('reserved-9', 9), ('referral', 10), ('adminLimitExceeded', 11), ('unavailableCriticalExtension', 12), ('confidentialityRequired', 13), ('saslBindInProgress', 14), ('noSuchAttribute', 16), ('undefinedAttributeType', 17), ('inappropriateMatching', 18), ('constraintViolation', 19), ('attributeOrValueExists', 20), ('invalidAttributeSyntax', 21), ('noSuchObject', 32), ('aliasProblem', 33), ('invalidDNSyntax', 34), ('reserved-35', 35), ('aliasDereferencingProblem', 36), ('inappropriateAuthentication', 48), ('invalidCredentials', 49), ('insufficientAccessRights', 50), ('busy', 51), ('unavailable', 52), ('unwillingToPerform', 53), ('loopDetect', 54), ('namingViolation', 64), ('objectClassViolation', 65), ('notAllowedOnNonLeaf', 66), ('notAllowedOnRDN', 67), ('entryAlreadyExists', 68), ('objectClassModsProhibited', 69), ('reserved-70', 70), ('affectsMultipleDSAs', 71), ('other', 80), ('reserved-81', 81), ('reserved-82', 82), ('reserved-83', 83), ('reserved-84', 84), ('reserved-85', 85), ('reserved-86', 86), ('reserved-87', 87), ('reserved-88', 88), ('reserved-89', 89), ('reserved-90', 90)))),
|
||||
namedtype.NamedType('matchedDN', LDAPDN()),
|
||||
namedtype.NamedType('errorMessage', LDAPString()),
|
||||
namedtype.OptionalNamedType('referral', Referral().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3))),
|
||||
namedtype.OptionalNamedType('serverSaslCreds', univ.OctetString().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 7)))
|
||||
)
|
||||
|
||||
class LDAPResult(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('resultCode', univ.Enumerated(namedValues=namedval.NamedValues(('success', 0), ('operationsError', 1), ('protocolError', 2), ('timeLimitExceeded', 3), ('sizeLimitExceeded', 4), ('compareFalse', 5), ('compareTrue', 6), ('authMethodNotSupported', 7), ('strongAuthRequired', 8), ('reserved-9', 9), ('referral', 10), ('adminLimitExceeded', 11), ('unavailableCriticalExtension', 12), ('confidentialityRequired', 13), ('saslBindInProgress', 14), ('noSuchAttribute', 16), ('undefinedAttributeType', 17), ('inappropriateMatching', 18), ('constraintViolation', 19), ('attributeOrValueExists', 20), ('invalidAttributeSyntax', 21), ('noSuchObject', 32), ('aliasProblem', 33), ('invalidDNSyntax', 34), ('reserved-35', 35), ('aliasDereferencingProblem', 36), ('inappropriateAuthentication', 48), ('invalidCredentials', 49), ('insufficientAccessRights', 50), ('busy', 51), ('unavailable', 52), ('unwillingToPerform', 53), ('loopDetect', 54), ('namingViolation', 64), ('objectClassViolation', 65), ('notAllowedOnNonLeaf', 66), ('notAllowedOnRDN', 67), ('entryAlreadyExists', 68), ('objectClassModsProhibited', 69), ('reserved-70', 70), ('affectsMultipleDSAs', 71), ('other', 80), ('reserved-81', 81), ('reserved-82', 82), ('reserved-83', 83), ('reserved-84', 84), ('reserved-85', 85), ('reserved-86', 86), ('reserved-87', 87), ('reserved-88', 88), ('reserved-89', 89), ('reserved-90', 90)))),
|
||||
namedtype.NamedType('matchedDN', LDAPDN()),
|
||||
namedtype.NamedType('errorMessage', LDAPString()),
|
||||
namedtype.OptionalNamedType('referral', Referral().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3)))
|
||||
)
|
||||
|
||||
class SearchResultReference(univ.SequenceOf):
|
||||
tagSet = univ.Sequence.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 19)
|
||||
)
|
||||
componentType = LDAPURL()
|
||||
|
||||
class SearchResultDone(LDAPResult):
|
||||
tagSet = univ.Sequence.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 5)
|
||||
)
|
||||
|
||||
class AttributeTypeAndValues(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('type', AttributeDescription()),
|
||||
namedtype.NamedType('vals', univ.SetOf(componentType=AttributeValue()))
|
||||
)
|
||||
|
||||
class ModifyRequest(univ.Sequence):
|
||||
tagSet = univ.Sequence.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 6)
|
||||
)
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('object', LDAPDN()),
|
||||
namedtype.NamedType('modification', univ.SequenceOf(componentType=univ.Sequence(componentType=namedtype.NamedTypes(namedtype.NamedType('operation', univ.Enumerated(namedValues=namedval.NamedValues(('add', 0), ('delete', 1), ('replace', 2)))), namedtype.NamedType('modification', AttributeTypeAndValues())))))
|
||||
)
|
||||
|
||||
class ModifyResponse(LDAPResult):
|
||||
tagSet = univ.Sequence.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 7)
|
||||
)
|
||||
|
||||
class AttributeList(univ.SequenceOf):
|
||||
componentType = univ.Sequence(componentType=namedtype.NamedTypes(namedtype.NamedType('type', AttributeDescription()), namedtype.NamedType('vals', univ.SetOf(componentType=AttributeValue()))))
|
||||
|
||||
class AddRequest(univ.Sequence):
|
||||
tagSet = univ.Sequence.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 8)
|
||||
)
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('entry', LDAPDN()),
|
||||
namedtype.NamedType('attributes', AttributeList())
|
||||
)
|
||||
|
||||
class AddResponse(LDAPResult):
|
||||
tagSet = univ.Sequence.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 9)
|
||||
)
|
||||
|
||||
class DelRequest(LDAPResult):
|
||||
tagSet = univ.Sequence.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 10)
|
||||
)
|
||||
|
||||
class DelResponse(LDAPResult):
|
||||
tagSet = univ.Sequence.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 11)
|
||||
)
|
||||
|
||||
class ModifyDNRequest(univ.Sequence):
|
||||
tagSet = univ.Sequence.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 12)
|
||||
)
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('entry', LDAPDN()),
|
||||
namedtype.NamedType('newrdn', RelativeLDAPDN()),
|
||||
namedtype.NamedType('deleteoldrdn', univ.Boolean()),
|
||||
namedtype.OptionalNamedType('newSuperior', LDAPDN().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
|
||||
|
||||
)
|
||||
|
||||
class ModifyDNResponse(LDAPResult):
|
||||
tagSet = univ.Sequence.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 13)
|
||||
)
|
||||
|
||||
class CompareRequest(univ.Sequence):
|
||||
tagSet = univ.Sequence.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 14)
|
||||
)
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('entry', LDAPDN()),
|
||||
namedtype.NamedType('ava', AttributeValueAssertion())
|
||||
)
|
||||
|
||||
class CompareResponse(LDAPResult):
|
||||
tagSet = univ.Sequence.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 15)
|
||||
)
|
||||
|
||||
class AbandonRequest(LDAPResult):
|
||||
tagSet = univ.Sequence.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 16)
|
||||
)
|
||||
|
||||
class ExtendedRequest(univ.Sequence):
|
||||
tagSet = univ.Sequence.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 23)
|
||||
)
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('requestName', LDAPOID().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.OptionalNamedType('requestValue', univ.OctetString().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)))
|
||||
)
|
||||
|
||||
class ExtendedResponse(univ.Sequence):
|
||||
tagSet = univ.Sequence.tagSet.tagImplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 24)
|
||||
)
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('resultCode', univ.Enumerated(namedValues=namedval.NamedValues(('success', 0), ('operationsError', 1), ('protocolError', 2), ('timeLimitExceeded', 3), ('sizeLimitExceeded', 4), ('compareFalse', 5), ('compareTrue', 6), ('authMethodNotSupported', 7), ('strongAuthRequired', 8), ('reserved-9', 9), ('referral', 10), ('adminLimitExceeded', 11), ('unavailableCriticalExtension', 12), ('confidentialityRequired', 13), ('saslBindInProgress', 14), ('noSuchAttribute', 16), ('undefinedAttributeType', 17), ('inappropriateMatching', 18), ('constraintViolation', 19), ('attributeOrValueExists', 20), ('invalidAttributeSyntax', 21), ('noSuchObject', 32), ('aliasProblem', 33), ('invalidDNSyntax', 34), ('reserved-35', 35), ('aliasDereferencingProblem', 36), ('inappropriateAuthentication', 48), ('invalidCredentials', 49), ('insufficientAccessRights', 50), ('busy', 51), ('unavailable', 52), ('unwillingToPerform', 53), ('loopDetect', 54), ('namingViolation', 64), ('objectClassViolation', 65), ('notAllowedOnNonLeaf', 66), ('notAllowedOnRDN', 67), ('entryAlreadyExists', 68), ('objectClassModsProhibited', 69), ('reserved-70', 70), ('affectsMultipleDSAs', 71), ('other', 80), ('reserved-81', 81), ('reserved-82', 82), ('reserved-83', 83), ('reserved-84', 84), ('reserved-85', 85), ('reserved-86', 86), ('reserved-87', 87), ('reserved-88', 88), ('reserved-89', 89), ('reserved-90', 90)))),
|
||||
namedtype.NamedType('matchedDN', LDAPDN()),
|
||||
namedtype.NamedType('errorMessage', LDAPString()),
|
||||
namedtype.OptionalNamedType('referral', Referral().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3))),
|
||||
|
||||
namedtype.OptionalNamedType('responseName', LDAPOID().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10))),
|
||||
namedtype.OptionalNamedType('response', univ.OctetString().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 11)))
|
||||
)
|
||||
|
||||
class MessageID(univ.Integer):
|
||||
subtypeSpec = univ.Integer.subtypeSpec + constraint.ValueRangeConstraint(
|
||||
0, maxInt
|
||||
)
|
||||
|
||||
class LDAPMessage(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('messageID', MessageID()),
|
||||
namedtype.NamedType('protocolOp', univ.Choice(componentType=namedtype.NamedTypes(namedtype.NamedType('bindRequest', BindRequest()), namedtype.NamedType('bindResponse', BindResponse()), namedtype.NamedType('unbindRequest', UnbindRequest()), namedtype.NamedType('searchRequest', SearchRequest()), namedtype.NamedType('searchResEntry', SearchResultEntry()), namedtype.NamedType('searchResDone', SearchResultDone()), namedtype.NamedType('searchResRef', SearchResultReference()), namedtype.NamedType('modifyRequest', ModifyRequest()), namedtype.NamedType('modifyResponse', ModifyResponse()), namedtype.NamedType('addRequest', AddRequest()), namedtype.NamedType('addResponse', AddResponse()), namedtype.NamedType('delRequest', DelRequest()), namedtype.NamedType('delResponse', DelResponse()), namedtype.NamedType('modDNRequest', ModifyDNRequest()), namedtype.NamedType('modDNResponse', ModifyDNResponse()), namedtype.NamedType('compareRequest', CompareRequest()), namedtype.NamedType('compareResponse', CompareResponse()), namedtype.NamedType('abandonRequest', AbandonRequest()), namedtype.NamedType('extendedReq', ExtendedRequest()), namedtype.NamedType('extendedResp', ExtendedResponse())))),
|
||||
namedtype.OptionalNamedType('controls', Controls().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
|
||||
)
|
||||
@@ -0,0 +1,33 @@
|
||||
#
|
||||
# PKCS#10 syntax
|
||||
#
|
||||
# ASN.1 source from:
|
||||
# http://tools.ietf.org/html/rfc2314
|
||||
#
|
||||
# Sample captures could be obtained with "openssl req" command
|
||||
#
|
||||
from pyasn1.type import tag, namedtype, namedval, univ, constraint
|
||||
from pyasn1_modules.rfc2459 import *
|
||||
|
||||
class Attributes(univ.SetOf):
|
||||
componentType = Attribute()
|
||||
|
||||
class Version(univ.Integer): pass
|
||||
|
||||
class CertificationRequestInfo(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('version', Version()),
|
||||
namedtype.NamedType('subject', Name()),
|
||||
namedtype.NamedType('subjectPublicKeyInfo', SubjectPublicKeyInfo()),
|
||||
namedtype.NamedType('attributes', Attributes().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
|
||||
)
|
||||
|
||||
class Signature(univ.BitString): pass
|
||||
class SignatureAlgorithmIdentifier(AlgorithmIdentifier): pass
|
||||
|
||||
class CertificationRequest(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('certificationRequestInfo', CertificationRequestInfo()),
|
||||
namedtype.NamedType('signatureAlgorithm', SignatureAlgorithmIdentifier()),
|
||||
namedtype.NamedType('signature', Signature())
|
||||
)
|
||||
@@ -0,0 +1,205 @@
|
||||
#
|
||||
# PKCS#7 message syntax
|
||||
#
|
||||
# ASN.1 source from:
|
||||
# http://www.trl.ibm.com/projects/xml/xss4j/data/asn1/grammars/pkcs7.asn
|
||||
#
|
||||
# Sample captures from:
|
||||
# openssl crl2pkcs7 -nocrl -certfile cert1.cer -out outfile.p7b
|
||||
#
|
||||
from pyasn1.type import tag,namedtype,namedval,univ,constraint,char,useful
|
||||
from pyasn1_modules.rfc2459 import *
|
||||
|
||||
class Attribute(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('type', AttributeType()),
|
||||
namedtype.NamedType('values', univ.SetOf(componentType=AttributeValue()))
|
||||
)
|
||||
|
||||
class AttributeValueAssertion(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('attributeType', AttributeType()),
|
||||
namedtype.NamedType('attributeValue', AttributeValue())
|
||||
)
|
||||
|
||||
pkcs_7 = univ.ObjectIdentifier('1.2.840.113549.1.7')
|
||||
data = univ.ObjectIdentifier('1.2.840.113549.1.7.1')
|
||||
signedData = univ.ObjectIdentifier('1.2.840.113549.1.7.2')
|
||||
envelopedData = univ.ObjectIdentifier('1.2.840.113549.1.7.3')
|
||||
signedAndEnvelopedData = univ.ObjectIdentifier('1.2.840.113549.1.7.4')
|
||||
digestedData = univ.ObjectIdentifier('1.2.840.113549.1.7.5')
|
||||
encryptedData = univ.ObjectIdentifier('1.2.840.113549.1.7.6')
|
||||
|
||||
class ContentType(univ.ObjectIdentifier): pass
|
||||
|
||||
class ContentEncryptionAlgorithmIdentifier(AlgorithmIdentifier): pass
|
||||
|
||||
class EncryptedContent(univ.OctetString): pass
|
||||
|
||||
class EncryptedContentInfo(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('contentType', ContentType()),
|
||||
namedtype.NamedType('contentEncryptionAlgorithm', ContentEncryptionAlgorithmIdentifier()),
|
||||
namedtype.OptionalNamedType('encryptedContent', EncryptedContent().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
|
||||
)
|
||||
|
||||
class Version(univ.Integer): pass # overrides x509.Version
|
||||
|
||||
class EncryptedData(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('version', Version()),
|
||||
namedtype.NamedType('encryptedContentInfo', EncryptedContentInfo())
|
||||
)
|
||||
|
||||
class DigestAlgorithmIdentifier(AlgorithmIdentifier): pass
|
||||
|
||||
class DigestAlgorithmIdentifiers(univ.SetOf):
|
||||
componentType = DigestAlgorithmIdentifier()
|
||||
|
||||
class Digest(univ.OctetString): pass
|
||||
|
||||
class ContentInfo(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('contentType', ContentType()),
|
||||
namedtype.OptionalNamedType('content', univ.Any().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
|
||||
)
|
||||
|
||||
class DigestedData(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('version', Version()),
|
||||
namedtype.NamedType('digestAlgorithm', DigestAlgorithmIdentifier()),
|
||||
namedtype.NamedType('contentInfo', ContentInfo()),
|
||||
namedtype.NamedType('digest', Digest)
|
||||
)
|
||||
|
||||
class IssuerAndSerialNumber(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('issuer', Name()),
|
||||
namedtype.NamedType('serialNumber', CertificateSerialNumber())
|
||||
)
|
||||
|
||||
class KeyEncryptionAlgorithmIdentifier(AlgorithmIdentifier): pass
|
||||
|
||||
class EncryptedKey(univ.OctetString): pass
|
||||
|
||||
class RecipientInfo(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('version', Version()),
|
||||
namedtype.NamedType('issuerAndSerialNumber', IssuerAndSerialNumber()),
|
||||
namedtype.NamedType('keyEncryptionAlgorithm', KeyEncryptionAlgorithmIdentifier()),
|
||||
namedtype.NamedType('encryptedKey', EncryptedKey())
|
||||
)
|
||||
|
||||
class RecipientInfos(univ.SetOf):
|
||||
componentType = RecipientInfo()
|
||||
|
||||
class Attributes(univ.SetOf):
|
||||
componentType = Attribute()
|
||||
|
||||
class ExtendedCertificateInfo(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('version', Version()),
|
||||
namedtype.NamedType('certificate', Certificate()),
|
||||
namedtype.NamedType('attributes', Attributes())
|
||||
)
|
||||
|
||||
class SignatureAlgorithmIdentifier(AlgorithmIdentifier): pass
|
||||
|
||||
class Signature(univ.BitString): pass
|
||||
|
||||
class ExtendedCertificate(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('extendedCertificateInfo', ExtendedCertificateInfo()),
|
||||
namedtype.NamedType('signatureAlgorithm', SignatureAlgorithmIdentifier()),
|
||||
namedtype.NamedType('signature', Signature())
|
||||
)
|
||||
|
||||
class ExtendedCertificateOrCertificate(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('certificate', Certificate()),
|
||||
namedtype.NamedType('extendedCertificate', ExtendedCertificate().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
|
||||
)
|
||||
|
||||
class ExtendedCertificatesAndCertificates(univ.SetOf):
|
||||
componentType = ExtendedCertificateOrCertificate()
|
||||
|
||||
class SerialNumber(univ.Integer): pass
|
||||
|
||||
class CRLEntry(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('userCertificate', SerialNumber()),
|
||||
namedtype.NamedType('revocationDate', useful.UTCTime())
|
||||
)
|
||||
|
||||
class TBSCertificateRevocationList(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('signature', AlgorithmIdentifier()),
|
||||
namedtype.NamedType('issuer', Name()),
|
||||
namedtype.NamedType('lastUpdate', useful.UTCTime()),
|
||||
namedtype.NamedType('nextUpdate', useful.UTCTime()),
|
||||
namedtype.OptionalNamedType('revokedCertificates', univ.SequenceOf(componentType=CRLEntry()))
|
||||
)
|
||||
|
||||
class CertificateRevocationList(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('tbsCertificateRevocationList', TBSCertificateRevocationList()),
|
||||
namedtype.NamedType('signatureAlgorithm', AlgorithmIdentifier()),
|
||||
namedtype.NamedType('signature', univ.BitString())
|
||||
)
|
||||
|
||||
class CertificateRevocationLists(univ.SetOf):
|
||||
componentType = CertificateRevocationList()
|
||||
|
||||
class DigestEncryptionAlgorithmIdentifier(AlgorithmIdentifier): pass
|
||||
|
||||
class EncryptedDigest(univ.OctetString): pass
|
||||
|
||||
class SignerInfo(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('version', Version()),
|
||||
namedtype.NamedType('issuerAndSerialNumber', IssuerAndSerialNumber()),
|
||||
namedtype.NamedType('digestAlgorithm', DigestAlgorithmIdentifier()),
|
||||
namedtype.OptionalNamedType('authenticatedAttributes', Attributes().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
|
||||
namedtype.NamedType('digestEncryptionAlgorithm', DigestEncryptionAlgorithmIdentifier()),
|
||||
namedtype.NamedType('encryptedDigest', EncryptedDigest()),
|
||||
namedtype.OptionalNamedType('unauthenticatedAttributes', Attributes().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
|
||||
)
|
||||
|
||||
class SignerInfos(univ.SetOf):
|
||||
componentType = SignerInfo()
|
||||
|
||||
class SignedAndEnvelopedData(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('version', Version()),
|
||||
namedtype.NamedType('recipientInfos', RecipientInfos()),
|
||||
namedtype.NamedType('digestAlgorithms', DigestAlgorithmIdentifiers()),
|
||||
namedtype.NamedType('encryptedContentInfo', EncryptedContentInfo()),
|
||||
namedtype.OptionalNamedType('certificates', ExtendedCertificatesAndCertificates().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
|
||||
namedtype.OptionalNamedType('crls', CertificateRevocationLists().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))),
|
||||
namedtype.NamedType('signerInfos', SignerInfos())
|
||||
)
|
||||
|
||||
class EnvelopedData(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('version', Version()),
|
||||
namedtype.NamedType('recipientInfos', RecipientInfos()),
|
||||
namedtype.NamedType('encryptedContentInfo', EncryptedContentInfo())
|
||||
)
|
||||
|
||||
class DigestInfo(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('digestAlgorithm', DigestAlgorithmIdentifier()),
|
||||
namedtype.NamedType('digest', Digest())
|
||||
)
|
||||
|
||||
class SignedData(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('version', Version()),
|
||||
namedtype.NamedType('digestAlgorithms', DigestAlgorithmIdentifiers()),
|
||||
namedtype.NamedType('contentInfo', ContentInfo()),
|
||||
namedtype.OptionalNamedType('certificates', ExtendedCertificatesAndCertificates().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
|
||||
namedtype.OptionalNamedType('crls', CertificateRevocationLists().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))),
|
||||
namedtype.NamedType('signerInfos', SignerInfos())
|
||||
)
|
||||
|
||||
class Data(univ.OctetString): pass
|
||||
@@ -0,0 +1,53 @@
|
||||
#
|
||||
# PKCS#1 syntax
|
||||
#
|
||||
# ASN.1 source from:
|
||||
# ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2.asn
|
||||
#
|
||||
# Sample captures could be obtained with "openssl genrsa" command
|
||||
#
|
||||
from pyasn1.type import tag, namedtype, namedval, univ, constraint
|
||||
from pyasn1_modules.rfc2459 import AlgorithmIdentifier
|
||||
|
||||
pkcs_1 = univ.ObjectIdentifier('1.2.840.113549.1.1')
|
||||
rsaEncryption = univ.ObjectIdentifier('1.2.840.113549.1.1.1')
|
||||
md2WithRSAEncryption = univ.ObjectIdentifier('1.2.840.113549.1.1.2')
|
||||
md4WithRSAEncryption = univ.ObjectIdentifier('1.2.840.113549.1.1.3')
|
||||
md5WithRSAEncryption = univ.ObjectIdentifier('1.2.840.113549.1.1.4')
|
||||
sha1WithRSAEncryption = univ.ObjectIdentifier('1.2.840.113549.1.1.5')
|
||||
rsaOAEPEncryptionSET = univ.ObjectIdentifier('1.2.840.113549.1.1.6')
|
||||
id_RSAES_OAEP = univ.ObjectIdentifier('1.2.840.113549.1.1.7')
|
||||
id_mgf1 = univ.ObjectIdentifier('1.2.840.113549.1.1.8')
|
||||
id_pSpecified = univ.ObjectIdentifier('1.2.840.113549.1.1.9')
|
||||
id_sha1 = univ.ObjectIdentifier('1.3.14.3.2.26')
|
||||
|
||||
MAX = 16
|
||||
|
||||
class Version(univ.Integer): pass
|
||||
|
||||
class RSAPrivateKey(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('version', Version()),
|
||||
namedtype.NamedType('modulus', univ.Integer()),
|
||||
namedtype.NamedType('publicExponent', univ.Integer()),
|
||||
namedtype.NamedType('privateExponent', univ.Integer()),
|
||||
namedtype.NamedType('prime1', univ.Integer()),
|
||||
namedtype.NamedType('prime2', univ.Integer()),
|
||||
namedtype.NamedType('exponent1', univ.Integer()),
|
||||
namedtype.NamedType('exponent2', univ.Integer()),
|
||||
namedtype.NamedType('coefficient', univ.Integer())
|
||||
)
|
||||
|
||||
class RSAPublicKey(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('modulus', univ.Integer()),
|
||||
namedtype.NamedType('publicExponent', univ.Integer())
|
||||
)
|
||||
|
||||
# XXX defaults not set
|
||||
class RSAES_OAEP_params(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('hashFunc', AlgorithmIdentifier().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
|
||||
namedtype.NamedType('maskGenFunc', AlgorithmIdentifier().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))),
|
||||
namedtype.NamedType('pSourceFunc', AlgorithmIdentifier().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2)))
|
||||
)
|
||||
@@ -0,0 +1,903 @@
|
||||
#
|
||||
# X.509 message syntax
|
||||
#
|
||||
# ASN.1 source from:
|
||||
# http://www.trl.ibm.com/projects/xml/xss4j/data/asn1/grammars/x509.asn
|
||||
# http://www.ietf.org/rfc/rfc2459.txt
|
||||
#
|
||||
# Sample captures from:
|
||||
# http://wiki.wireshark.org/SampleCaptures/
|
||||
#
|
||||
from pyasn1.type import tag,namedtype,namedval,univ,constraint,char,useful
|
||||
|
||||
MAX = 64 # XXX ?
|
||||
|
||||
#
|
||||
# PKIX1Explicit88
|
||||
#
|
||||
|
||||
# Upper Bounds
|
||||
ub_name = univ.Integer(32768)
|
||||
ub_common_name = univ.Integer(64)
|
||||
ub_locality_name = univ.Integer(128)
|
||||
ub_state_name = univ.Integer(128)
|
||||
ub_organization_name = univ.Integer(64)
|
||||
ub_organizational_unit_name = univ.Integer(64)
|
||||
ub_title = univ.Integer(64)
|
||||
ub_match = univ.Integer(128)
|
||||
ub_emailaddress_length = univ.Integer(128)
|
||||
ub_common_name_length = univ.Integer(64)
|
||||
ub_country_name_alpha_length = univ.Integer(2)
|
||||
ub_country_name_numeric_length = univ.Integer(3)
|
||||
ub_domain_defined_attributes = univ.Integer(4)
|
||||
ub_domain_defined_attribute_type_length = univ.Integer(8)
|
||||
ub_domain_defined_attribute_value_length = univ.Integer(128)
|
||||
ub_domain_name_length = univ.Integer(16)
|
||||
ub_extension_attributes = univ.Integer(256)
|
||||
ub_e163_4_number_length = univ.Integer(15)
|
||||
ub_e163_4_sub_address_length = univ.Integer(40)
|
||||
ub_generation_qualifier_length = univ.Integer(3)
|
||||
ub_given_name_length = univ.Integer(16)
|
||||
ub_initials_length = univ.Integer(5)
|
||||
ub_integer_options = univ.Integer(256)
|
||||
ub_numeric_user_id_length = univ.Integer(32)
|
||||
ub_organization_name_length = univ.Integer(64)
|
||||
ub_organizational_unit_name_length = univ.Integer(32)
|
||||
ub_organizational_units = univ.Integer(4)
|
||||
ub_pds_name_length = univ.Integer(16)
|
||||
ub_pds_parameter_length = univ.Integer(30)
|
||||
ub_pds_physical_address_lines = univ.Integer(6)
|
||||
ub_postal_code_length = univ.Integer(16)
|
||||
ub_surname_length = univ.Integer(40)
|
||||
ub_terminal_id_length = univ.Integer(24)
|
||||
ub_unformatted_address_length = univ.Integer(180)
|
||||
ub_x121_address_length = univ.Integer(16)
|
||||
|
||||
class UniversalString(char.UniversalString): pass
|
||||
class BMPString(char.BMPString): pass
|
||||
class UTF8String(char.UTF8String): pass
|
||||
|
||||
id_pkix = univ.ObjectIdentifier('1.3.6.1.5.5.7')
|
||||
id_pe = univ.ObjectIdentifier('1.3.6.1.5.5.7.1')
|
||||
id_qt = univ.ObjectIdentifier('1.3.6.1.5.5.7.2')
|
||||
id_kp = univ.ObjectIdentifier('1.3.6.1.5.5.7.3')
|
||||
id_ad = univ.ObjectIdentifier('1.3.6.1.5.5.7.48')
|
||||
|
||||
id_qt_cps = univ.ObjectIdentifier('1.3.6.1.5.5.7.2.1')
|
||||
id_qt_unotice = univ.ObjectIdentifier('1.3.6.1.5.5.7.2.2')
|
||||
|
||||
id_ad_ocsp = univ.ObjectIdentifier('1.3.6.1.5.5.7.48.1')
|
||||
id_ad_caIssuers = univ.ObjectIdentifier('1.3.6.1.5.5.7.48.2')
|
||||
|
||||
class AttributeValue(univ.Any): pass
|
||||
|
||||
class AttributeType(univ.ObjectIdentifier): pass
|
||||
|
||||
class AttributeTypeAndValue(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('type', AttributeType()),
|
||||
namedtype.NamedType('value', AttributeValue())
|
||||
)
|
||||
|
||||
class Attribute(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('type', AttributeType()),
|
||||
namedtype.NamedType('vals', univ.SetOf(componentType=AttributeValue()))
|
||||
)
|
||||
|
||||
id_at = univ.ObjectIdentifier('2.5.4')
|
||||
id_at_name = univ.ObjectIdentifier('2.5.4.41')
|
||||
id_at_sutname = univ.ObjectIdentifier('2.5.4.4')
|
||||
id_at_givenName = univ.ObjectIdentifier('2.5.4.42')
|
||||
id_at_initials = univ.ObjectIdentifier('2.5.4.43')
|
||||
id_at_generationQualifier = univ.ObjectIdentifier('2.5.4.44')
|
||||
|
||||
class X520name(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('teletexString', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_name))),
|
||||
namedtype.NamedType('printableString', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_name))),
|
||||
namedtype.NamedType('universalString', char.UniversalString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_name))),
|
||||
namedtype.NamedType('utf8String', char.UTF8String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_name))),
|
||||
namedtype.NamedType('bmpString', char.BMPString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_name)))
|
||||
)
|
||||
|
||||
id_at_commonName = univ.ObjectIdentifier('2.5.4.3')
|
||||
|
||||
class X520CommonName(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('teletexString', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_common_name))),
|
||||
namedtype.NamedType('printableString', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_common_name))),
|
||||
namedtype.NamedType('universalString', char.UniversalString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_common_name))),
|
||||
namedtype.NamedType('utf8String', char.UTF8String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_common_name))),
|
||||
namedtype.NamedType('bmpString', char.BMPString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_common_name)))
|
||||
)
|
||||
|
||||
id_at_localityName = univ.ObjectIdentifier('2.5.4.7')
|
||||
|
||||
class X520LocalityName(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('teletexString', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_locality_name))),
|
||||
namedtype.NamedType('printableString', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_locality_name))),
|
||||
namedtype.NamedType('universalString', char.UniversalString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_locality_name))),
|
||||
namedtype.NamedType('utf8String', char.UTF8String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_locality_name))),
|
||||
namedtype.NamedType('bmpString', char.BMPString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_locality_name)))
|
||||
)
|
||||
|
||||
id_at_stateOrProvinceName = univ.ObjectIdentifier('2.5.4.8')
|
||||
|
||||
class X520StateOrProvinceName(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('teletexString', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_state_name))),
|
||||
namedtype.NamedType('printableString', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_state_name))),
|
||||
namedtype.NamedType('universalString', char.UniversalString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_state_name))),
|
||||
namedtype.NamedType('utf8String', char.UTF8String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_state_name))),
|
||||
namedtype.NamedType('bmpString', char.BMPString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_state_name)))
|
||||
)
|
||||
|
||||
id_at_organizationName = univ.ObjectIdentifier('2.5.4.10')
|
||||
|
||||
class X520OrganizationName(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('teletexString', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_organization_name))),
|
||||
namedtype.NamedType('printableString', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_organization_name))),
|
||||
namedtype.NamedType('universalString', char.UniversalString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_organization_name))),
|
||||
namedtype.NamedType('utf8String', char.UTF8String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_organization_name))),
|
||||
namedtype.NamedType('bmpString', char.BMPString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_organization_name)))
|
||||
)
|
||||
|
||||
id_at_organizationalUnitName = univ.ObjectIdentifier('2.5.4.11')
|
||||
|
||||
class X520OrganizationalUnitName(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('teletexString', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_organizational_unit_name))),
|
||||
namedtype.NamedType('printableString', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_organizational_unit_name))),
|
||||
namedtype.NamedType('universalString', char.UniversalString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_organizational_unit_name))),
|
||||
namedtype.NamedType('utf8String', char.UTF8String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_organizational_unit_name))),
|
||||
namedtype.NamedType('bmpString', char.BMPString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_organizational_unit_name)))
|
||||
)
|
||||
|
||||
id_at_title = univ.ObjectIdentifier('2.5.4.12')
|
||||
|
||||
class X520Title(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('teletexString', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_title))),
|
||||
namedtype.NamedType('printableString', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_title))),
|
||||
namedtype.NamedType('universalString', char.UniversalString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_title))),
|
||||
namedtype.NamedType('utf8String', char.UTF8String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_title))),
|
||||
namedtype.NamedType('bmpString', char.BMPString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_title)))
|
||||
)
|
||||
|
||||
id_at_dnQualifier = univ.ObjectIdentifier('2.5.4.46')
|
||||
|
||||
class X520dnQualifier(char.PrintableString): pass
|
||||
|
||||
id_at_countryName = univ.ObjectIdentifier('2.5.4.6')
|
||||
|
||||
class X520countryName(char.PrintableString):
|
||||
subtypeSpec = char.PrintableString.subtypeSpec + constraint.ValueSizeConstraint(2, 2)
|
||||
|
||||
pkcs_9 = univ.ObjectIdentifier('1.2.840.113549.1.9')
|
||||
|
||||
emailAddress = univ.ObjectIdentifier('1.2.840.113549.1.9.1')
|
||||
|
||||
class Pkcs9email(char.IA5String):
|
||||
subtypeSpec = char.IA5String.subtypeSpec + constraint.ValueSizeConstraint(1, ub_emailaddress_length)
|
||||
|
||||
# ----
|
||||
|
||||
class DSAPrivateKey(univ.Sequence):
|
||||
"""PKIX compliant DSA private key structure"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('version', univ.Integer(namedValues=namedval.NamedValues(('v1', 0)))),
|
||||
namedtype.NamedType('p', univ.Integer()),
|
||||
namedtype.NamedType('q', univ.Integer()),
|
||||
namedtype.NamedType('g', univ.Integer()),
|
||||
namedtype.NamedType('public', univ.Integer()),
|
||||
namedtype.NamedType('private', univ.Integer())
|
||||
)
|
||||
|
||||
# ----
|
||||
|
||||
class RelativeDistinguishedName(univ.SetOf):
|
||||
componentType = AttributeTypeAndValue()
|
||||
|
||||
class RDNSequence(univ.SequenceOf):
|
||||
componentType = RelativeDistinguishedName()
|
||||
|
||||
class Name(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('', RDNSequence())
|
||||
)
|
||||
|
||||
class DirectoryString(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('teletexString', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
|
||||
namedtype.NamedType('printableString', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
|
||||
namedtype.NamedType('universalString', char.UniversalString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
|
||||
namedtype.NamedType('utf8String', char.UTF8String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
|
||||
namedtype.NamedType('bmpString', char.BMPString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
|
||||
namedtype.NamedType('ia5String', char.IA5String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))) # hm, this should not be here!? XXX
|
||||
)
|
||||
|
||||
# certificate and CRL specific structures begin here
|
||||
|
||||
class AlgorithmIdentifier(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('algorithm', univ.ObjectIdentifier()),
|
||||
namedtype.OptionalNamedType('parameters', univ.Any())
|
||||
)
|
||||
|
||||
class Extension(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('extnID', univ.ObjectIdentifier()),
|
||||
namedtype.DefaultedNamedType('critical', univ.Boolean('False')),
|
||||
namedtype.NamedType('extnValue', univ.Any())
|
||||
)
|
||||
|
||||
class Extensions(univ.SequenceOf):
|
||||
componentType = Extension()
|
||||
sizeSpec = univ.SequenceOf.sizeSpec + constraint.ValueSizeConstraint(1, MAX)
|
||||
|
||||
class SubjectPublicKeyInfo(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('algorithm', AlgorithmIdentifier()),
|
||||
namedtype.NamedType('subjectPublicKey', univ.BitString())
|
||||
)
|
||||
|
||||
class UniqueIdentifier(univ.BitString): pass
|
||||
|
||||
class Time(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('utcTime', useful.UTCTime()),
|
||||
namedtype.NamedType('generalTime', useful.GeneralizedTime())
|
||||
)
|
||||
|
||||
class Validity(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('notBefore', Time()),
|
||||
namedtype.NamedType('notAfter', Time())
|
||||
)
|
||||
|
||||
class CertificateSerialNumber(univ.Integer): pass
|
||||
|
||||
class Version(univ.Integer):
|
||||
namedValues = namedval.NamedValues(
|
||||
('v1', 0), ('v2', 1), ('v3', 2)
|
||||
)
|
||||
|
||||
class TBSCertificate(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.DefaultedNamedType('version', Version('v1').subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.NamedType('serialNumber', CertificateSerialNumber()),
|
||||
namedtype.NamedType('signature', AlgorithmIdentifier()),
|
||||
namedtype.NamedType('issuer', Name()),
|
||||
namedtype.NamedType('validity', Validity()),
|
||||
namedtype.NamedType('subject', Name()),
|
||||
namedtype.NamedType('subjectPublicKeyInfo', SubjectPublicKeyInfo()),
|
||||
namedtype.OptionalNamedType('issuerUniqueID', UniqueIdentifier().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
|
||||
namedtype.OptionalNamedType('subjectUniqueID', UniqueIdentifier().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
|
||||
namedtype.OptionalNamedType('extensions', Extensions().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3)))
|
||||
)
|
||||
|
||||
class Certificate(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('tbsCertificate', TBSCertificate()),
|
||||
namedtype.NamedType('signatureAlgorithm', AlgorithmIdentifier()),
|
||||
namedtype.NamedType('signatureValue', univ.BitString())
|
||||
)
|
||||
|
||||
# CRL structures
|
||||
|
||||
class RevokedCertificate(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('userCertificate', CertificateSerialNumber()),
|
||||
namedtype.NamedType('revocationDate', Time()),
|
||||
namedtype.OptionalNamedType('crlEntryExtensions', Extensions())
|
||||
)
|
||||
|
||||
class TBSCertList(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.OptionalNamedType('version', Version()),
|
||||
namedtype.NamedType('signature', AlgorithmIdentifier()),
|
||||
namedtype.NamedType('issuer', Name()),
|
||||
namedtype.NamedType('thisUpdate', Time()),
|
||||
namedtype.OptionalNamedType('nextUpdate', Time()),
|
||||
namedtype.OptionalNamedType('revokedCertificates', univ.SequenceOf(componentType=RevokedCertificate())),
|
||||
namedtype.OptionalNamedType('crlExtensions', Extensions().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
|
||||
)
|
||||
|
||||
class CertificateList(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('tbsCertList', TBSCertList()),
|
||||
namedtype.NamedType('signatureAlgorithm', AlgorithmIdentifier()),
|
||||
namedtype.NamedType('signature', univ.BitString())
|
||||
)
|
||||
|
||||
# Algorithm OIDs and parameter structures
|
||||
|
||||
pkcs_1 = univ.ObjectIdentifier('1.2.840.113549.1.1')
|
||||
rsaEncryption = univ.ObjectIdentifier('1.2.840.113549.1.1.1')
|
||||
md2WithRSAEncryption = univ.ObjectIdentifier('1.2.840.113549.1.1.2')
|
||||
md5WithRSAEncryption = univ.ObjectIdentifier('1.2.840.113549.1.1.4')
|
||||
sha1WithRSAEncryption = univ.ObjectIdentifier('1.2.840.113549.1.1.5')
|
||||
id_dsa_with_sha1 = univ.ObjectIdentifier('1.2.840.10040.4.3')
|
||||
|
||||
class Dss_Sig_Value(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('r', univ.Integer()),
|
||||
namedtype.NamedType('s', univ.Integer())
|
||||
)
|
||||
|
||||
dhpublicnumber = univ.ObjectIdentifier('1.2.840.10046.2.1')
|
||||
|
||||
class ValidationParms(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('seed', univ.BitString()),
|
||||
namedtype.NamedType('pgenCounter', univ.Integer())
|
||||
)
|
||||
|
||||
class DomainParameters(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('p', univ.Integer()),
|
||||
namedtype.NamedType('g', univ.Integer()),
|
||||
namedtype.NamedType('q', univ.Integer()),
|
||||
namedtype.NamedType('j', univ.Integer()),
|
||||
namedtype.OptionalNamedType('validationParms', ValidationParms())
|
||||
)
|
||||
|
||||
id_dsa = univ.ObjectIdentifier('1.2.840.10040.4.1')
|
||||
|
||||
class Dss_Parms(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('p', univ.Integer()),
|
||||
namedtype.NamedType('q', univ.Integer()),
|
||||
namedtype.NamedType('g', univ.Integer())
|
||||
)
|
||||
|
||||
# x400 address syntax starts here
|
||||
|
||||
teletex_domain_defined_attributes = univ.Integer(6)
|
||||
|
||||
class TeletexDomainDefinedAttribute(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('type', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_domain_defined_attribute_type_length))),
|
||||
namedtype.NamedType('value', char.TeletexString())
|
||||
)
|
||||
|
||||
class TeletexDomainDefinedAttributes(univ.SequenceOf):
|
||||
componentType = TeletexDomainDefinedAttribute()
|
||||
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, ub_domain_defined_attributes)
|
||||
|
||||
terminal_type = univ.Integer(23)
|
||||
|
||||
class TerminalType(univ.Integer):
|
||||
subtypeSpec = univ.Integer.subtypeSpec + constraint.ValueSizeConstraint(0, ub_integer_options)
|
||||
namedValues = namedval.NamedValues(
|
||||
('telex', 3),
|
||||
('teletelex', 4),
|
||||
('g3-facsimile', 5),
|
||||
('g4-facsimile', 6),
|
||||
('ia5-terminal', 7),
|
||||
('videotex', 8)
|
||||
)
|
||||
|
||||
class PresentationAddress(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.OptionalNamedType('pSelector', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.OptionalNamedType('sSelector', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
|
||||
namedtype.OptionalNamedType('tSelector', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
|
||||
namedtype.OptionalNamedType('nAddresses', univ.SetOf(componentType=univ.OctetString()).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3), subtypeSpec=constraint.ValueSizeConstraint(1, MAX))),
|
||||
)
|
||||
|
||||
extended_network_address = univ.Integer(22)
|
||||
|
||||
class E163_4_address(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('number', char.NumericString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_e163_4_number_length), explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.OptionalNamedType('sub-address', char.NumericString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_e163_4_sub_address_length), explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)))
|
||||
)
|
||||
|
||||
class ExtendedNetworkAddress(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('e163-4-address', E163_4_address()),
|
||||
namedtype.NamedType('psap-address', PresentationAddress().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
|
||||
)
|
||||
|
||||
class PDSParameter(univ.Set):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.OptionalNamedType('printable-string', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_pds_parameter_length))),
|
||||
namedtype.OptionalNamedType('teletex-string', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_pds_parameter_length)))
|
||||
)
|
||||
|
||||
local_postal_attributes = univ.Integer(21)
|
||||
|
||||
class LocalPostalAttributes(PDSParameter): pass
|
||||
|
||||
class UniquePostalName(PDSParameter): pass
|
||||
|
||||
unique_postal_name = univ.Integer(20)
|
||||
|
||||
poste_restante_address = univ.Integer(19)
|
||||
|
||||
class PosteRestanteAddress(PDSParameter): pass
|
||||
|
||||
post_office_box_address = univ.Integer(18)
|
||||
|
||||
class PostOfficeBoxAddress(PDSParameter): pass
|
||||
|
||||
street_address = univ.Integer(17)
|
||||
|
||||
class StreetAddress(PDSParameter): pass
|
||||
|
||||
class UnformattedPostalAddress(univ.Set):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.OptionalNamedType('printable-address', univ.SequenceOf(componentType=char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_pds_parameter_length)).subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_pds_physical_address_lines)))),
|
||||
namedtype.OptionalNamedType('teletex-string', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_unformatted_address_length)))
|
||||
)
|
||||
|
||||
physical_delivery_office_name = univ.Integer(10)
|
||||
|
||||
class PhysicalDeliveryOfficeName(PDSParameter): pass
|
||||
|
||||
physical_delivery_office_number = univ.Integer(11)
|
||||
|
||||
class PhysicalDeliveryOfficeNumber(PDSParameter): pass
|
||||
|
||||
extension_OR_address_components = univ.Integer(12)
|
||||
|
||||
class ExtensionORAddressComponents(PDSParameter): pass
|
||||
|
||||
physical_delivery_personal_name = univ.Integer(13)
|
||||
|
||||
class PhysicalDeliveryPersonalName(PDSParameter): pass
|
||||
|
||||
physical_delivery_organization_name = univ.Integer(14)
|
||||
|
||||
class PhysicalDeliveryOrganizationName(PDSParameter): pass
|
||||
|
||||
extension_physical_delivery_address_components = univ.Integer(15)
|
||||
|
||||
class ExtensionPhysicalDeliveryAddressComponents(PDSParameter): pass
|
||||
|
||||
unformatted_postal_address = univ.Integer(16)
|
||||
|
||||
postal_code = univ.Integer(9)
|
||||
|
||||
class PostalCode(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('numeric-code', char.NumericString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_postal_code_length))),
|
||||
namedtype.NamedType('printable-code', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_postal_code_length)))
|
||||
)
|
||||
|
||||
class PhysicalDeliveryCountryName(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('x121-dcc-code', char.NumericString().subtype(subtypeSpec=constraint.ValueSizeConstraint(ub_country_name_numeric_length, ub_country_name_numeric_length))),
|
||||
namedtype.NamedType('iso-3166-alpha2-code', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(ub_country_name_alpha_length, ub_country_name_alpha_length)))
|
||||
)
|
||||
|
||||
class PDSName(char.PrintableString):
|
||||
subtypeSpec = char.PrintableString.subtypeSpec + constraint.ValueSizeConstraint(1, ub_pds_name_length)
|
||||
|
||||
physical_delivery_country_name = univ.Integer(8)
|
||||
|
||||
class TeletexOrganizationalUnitName(char.TeletexString):
|
||||
subtypeSpec = char.TeletexString.subtypeSpec + constraint.ValueSizeConstraint(1, ub_organizational_unit_name_length)
|
||||
|
||||
pds_name = univ.Integer(7)
|
||||
|
||||
teletex_organizational_unit_names = univ.Integer(5)
|
||||
|
||||
class TeletexOrganizationalUnitNames(univ.SequenceOf):
|
||||
componentType = TeletexOrganizationalUnitName()
|
||||
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, ub_organizational_units)
|
||||
|
||||
teletex_personal_name = univ.Integer(4)
|
||||
|
||||
class TeletexPersonalName(univ.Set):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('surname', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_surname_length), explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.OptionalNamedType('given-name', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_given_name_length), explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
|
||||
namedtype.OptionalNamedType('initials', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_initials_length), explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
|
||||
namedtype.OptionalNamedType('generation-qualifier', char.TeletexString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_generation_qualifier_length), explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3)))
|
||||
)
|
||||
|
||||
teletex_organization_name = univ.Integer(3)
|
||||
|
||||
class TeletexOrganizationName(char.TeletexString):
|
||||
subtypeSpec = char.TeletexString.subtypeSpec + constraint.ValueSizeConstraint(1, ub_organization_name_length)
|
||||
|
||||
teletex_common_name = univ.Integer(2)
|
||||
|
||||
class TeletexCommonName(char.TeletexString):
|
||||
subtypeSpec = char.TeletexString.subtypeSpec + constraint.ValueSizeConstraint(1, ub_common_name_length)
|
||||
|
||||
class CommonName(char.PrintableString):
|
||||
subtypeSpec = char.PrintableString.subtypeSpec + constraint.ValueSizeConstraint(1, ub_common_name_length)
|
||||
|
||||
common_name = univ.Integer(1)
|
||||
|
||||
class ExtensionAttribute(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('extension-attribute-type', univ.Integer().subtype(subtypeSpec=constraint.ValueSizeConstraint(0, ub_extension_attributes), explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.NamedType('extension-attribute-value', univ.Any().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)))
|
||||
)
|
||||
|
||||
class ExtensionAttributes(univ.SetOf):
|
||||
componentType = ExtensionAttribute()
|
||||
subtypeSpec = univ.SetOf.subtypeSpec + constraint.ValueSizeConstraint(1, ub_extension_attributes)
|
||||
|
||||
class BuiltInDomainDefinedAttribute(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('type', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_domain_defined_attribute_type_length))),
|
||||
namedtype.NamedType('value', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_domain_defined_attribute_value_length)))
|
||||
)
|
||||
|
||||
class BuiltInDomainDefinedAttributes(univ.SequenceOf):
|
||||
componentType = BuiltInDomainDefinedAttribute()
|
||||
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, ub_domain_defined_attributes)
|
||||
|
||||
class OrganizationalUnitName(char.PrintableString):
|
||||
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, ub_organizational_unit_name_length)
|
||||
|
||||
class OrganizationalUnitNames(univ.SequenceOf):
|
||||
componentType = OrganizationalUnitName()
|
||||
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, ub_organizational_units)
|
||||
|
||||
class PersonalName(univ.Set):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('surname', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_surname_length), explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.OptionalNamedType('given-name', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_given_name_length), explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
|
||||
namedtype.OptionalNamedType('initials', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_initials_length), explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
|
||||
namedtype.OptionalNamedType('generation-qualifier', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_generation_qualifier_length), explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3)))
|
||||
)
|
||||
|
||||
class NumericUserIdentifier(char.NumericString):
|
||||
subtypeSpec = char.NumericString.subtypeSpec + constraint.ValueSizeConstraint(1, ub_numeric_user_id_length)
|
||||
|
||||
class OrganizationName(char.PrintableString):
|
||||
subtypeSpec = char.PrintableString.subtypeSpec + constraint.ValueSizeConstraint(1, ub_organization_name_length)
|
||||
|
||||
class PrivateDomainName(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('numeric', char.NumericString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_domain_name_length))),
|
||||
namedtype.NamedType('printable', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, ub_domain_name_length)))
|
||||
)
|
||||
|
||||
class TerminalIdentifier(char.PrintableString):
|
||||
subtypeSpec = char.PrintableString.subtypeSpec + constraint.ValueSizeConstraint(1, ub_terminal_id_length)
|
||||
|
||||
class X121Address(char.NumericString):
|
||||
subtypeSpec = char.NumericString.subtypeSpec + constraint.ValueSizeConstraint(1, ub_x121_address_length)
|
||||
|
||||
class NetworkAddress(X121Address): pass
|
||||
|
||||
class AdministrationDomainName(univ.Choice):
|
||||
tagSet = univ.Choice.tagSet.tagExplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 2)
|
||||
)
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('numeric', char.NumericString().subtype(subtypeSpec=constraint.ValueSizeConstraint(0, ub_domain_name_length))),
|
||||
namedtype.NamedType('printable', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(0, ub_domain_name_length)))
|
||||
)
|
||||
|
||||
class CountryName(univ.Choice):
|
||||
tagSet = univ.Choice.tagSet.tagExplicitly(
|
||||
tag.Tag(tag.tagClassApplication, tag.tagFormatConstructed, 1)
|
||||
)
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('x121-dcc-code', char.NumericString().subtype(subtypeSpec=constraint.ValueSizeConstraint(ub_country_name_numeric_length, ub_country_name_numeric_length))),
|
||||
namedtype.NamedType('iso-3166-alpha2-code', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(ub_country_name_alpha_length, ub_country_name_alpha_length)))
|
||||
)
|
||||
|
||||
class BuiltInStandardAttributes(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.OptionalNamedType('country-name', CountryName()),
|
||||
namedtype.OptionalNamedType('administration-domain-name', AdministrationDomainName()),
|
||||
namedtype.OptionalNamedType('network-address', NetworkAddress().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.OptionalNamedType('terminal-identifier', TerminalIdentifier().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
|
||||
namedtype.OptionalNamedType('private-domain-name', PrivateDomainName().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
|
||||
namedtype.OptionalNamedType('organization-name', OrganizationName().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))),
|
||||
namedtype.OptionalNamedType('numeric-user-identifier', NumericUserIdentifier().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4))),
|
||||
namedtype.OptionalNamedType('personal-name', PersonalName().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 5))),
|
||||
namedtype.OptionalNamedType('organizational-unit-names', OrganizationalUnitNames().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 6)))
|
||||
)
|
||||
|
||||
class ORAddress(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('built-in-standard-attributes', BuiltInStandardAttributes()),
|
||||
namedtype.OptionalNamedType('built-in-domain-defined-attributes', BuiltInDomainDefinedAttributes()),
|
||||
namedtype.OptionalNamedType('extension-attributes', ExtensionAttributes())
|
||||
)
|
||||
|
||||
#
|
||||
# PKIX1Implicit88
|
||||
#
|
||||
|
||||
id_ce_invalidityDate = univ.ObjectIdentifier('2.5.29.24')
|
||||
|
||||
class InvalidityDate(useful.GeneralizedTime): pass
|
||||
|
||||
id_holdinstruction_none = univ.ObjectIdentifier('2.2.840.10040.2.1')
|
||||
id_holdinstruction_callissuer = univ.ObjectIdentifier('2.2.840.10040.2.2')
|
||||
id_holdinstruction_reject = univ.ObjectIdentifier('2.2.840.10040.2.3')
|
||||
|
||||
holdInstruction = univ.ObjectIdentifier('2.2.840.10040.2')
|
||||
|
||||
id_ce_holdInstructionCode = univ.ObjectIdentifier('2.5.29.23')
|
||||
|
||||
class HoldInstructionCode(univ.ObjectIdentifier): pass
|
||||
|
||||
id_ce_cRLReasons = univ.ObjectIdentifier('2.5.29.21')
|
||||
|
||||
class CRLReason(univ.Enumerated):
|
||||
namedValues = namedval.NamedValues(
|
||||
('unspecified', 0),
|
||||
('keyCompromise', 1),
|
||||
('cACompromise', 2),
|
||||
('affiliationChanged', 3),
|
||||
('superseded', 4),
|
||||
('cessationOfOperation', 5),
|
||||
('certificateHold', 6),
|
||||
('removeFromCRL', 8)
|
||||
)
|
||||
|
||||
id_ce_cRLNumber = univ.ObjectIdentifier('2.5.29.20')
|
||||
|
||||
class CRLNumber(univ.Integer):
|
||||
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(0, MAX)
|
||||
|
||||
class BaseCRLNumber(CRLNumber): pass
|
||||
|
||||
id_kp_serverAuth = univ.ObjectIdentifier('1.3.6.1.5.5.7.3.1.1')
|
||||
id_kp_clientAuth = univ.ObjectIdentifier('1.3.6.1.5.5.7.3.2')
|
||||
id_kp_codeSigning = univ.ObjectIdentifier('1.3.6.1.5.5.7.3.3')
|
||||
id_kp_emailProtection = univ.ObjectIdentifier('1.3.6.1.5.5.7.3.4')
|
||||
id_kp_ipsecEndSystem = univ.ObjectIdentifier('1.3.6.1.5.5.7.3.5')
|
||||
id_kp_ipsecTunnel = univ.ObjectIdentifier('1.3.6.1.5.5.7.3.6')
|
||||
id_kp_ipsecUser = univ.ObjectIdentifier('1.3.6.1.5.5.7.3.7')
|
||||
id_kp_timeStamping = univ.ObjectIdentifier('1.3.6.1.5.5.7.3.8')
|
||||
id_pe_authorityInfoAccess = univ.ObjectIdentifier('1.3.6.1.5.5.7.1.1')
|
||||
id_ce_extKeyUsage = univ.ObjectIdentifier('2.5.29.37')
|
||||
|
||||
class KeyPurposeId(univ.ObjectIdentifier): pass
|
||||
|
||||
class ExtKeyUsageSyntax(univ.SequenceOf):
|
||||
componentType = KeyPurposeId()
|
||||
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
|
||||
|
||||
class ReasonFlags(univ.BitString):
|
||||
namedValues = namedval.NamedValues(
|
||||
('unused', 0),
|
||||
('keyCompromise', 1),
|
||||
('cACompromise', 2),
|
||||
('affiliationChanged', 3),
|
||||
('superseded', 4),
|
||||
('cessationOfOperation', 5),
|
||||
('certificateHold', 6)
|
||||
)
|
||||
|
||||
|
||||
class SkipCerts(univ.Integer):
|
||||
subtypeSpec = univ.Integer.subtypeSpec + constraint.ValueSizeConstraint(0, MAX)
|
||||
|
||||
id_ce_policyConstraints = univ.ObjectIdentifier('2.5.29.36')
|
||||
|
||||
class PolicyConstraints(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.OptionalNamedType('requireExplicitPolicy', SkipCerts().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
|
||||
namedtype.OptionalNamedType('inhibitPolicyMapping', SkipCerts().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
|
||||
)
|
||||
|
||||
id_ce_basicConstraints = univ.ObjectIdentifier('2.5.29.19')
|
||||
|
||||
class BasicConstraints(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('cA', univ.Boolean(False)),
|
||||
namedtype.OptionalNamedType('pathLenConstraint', univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, MAX)))
|
||||
)
|
||||
|
||||
id_ce_subjectDirectoryAttributes = univ.ObjectIdentifier('2.5.29.9')
|
||||
|
||||
class SubjectDirectoryAttributes(univ.SequenceOf):
|
||||
componentType = Attribute()
|
||||
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
|
||||
|
||||
class EDIPartyName(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.OptionalNamedType('nameAssigner', DirectoryString().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.NamedType('partyName', DirectoryString().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)))
|
||||
)
|
||||
|
||||
class AnotherName(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('type-id', univ.ObjectIdentifier()),
|
||||
namedtype.NamedType('value', univ.Any().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
|
||||
)
|
||||
|
||||
class GeneralName(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('otherName', AnotherName().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.NamedType('rfc822Name', char.IA5String().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
|
||||
namedtype.NamedType('dNSName', char.IA5String().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
|
||||
namedtype.NamedType('x400Address', ORAddress().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))),
|
||||
namedtype.NamedType('directoryName', Name().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4))),
|
||||
namedtype.NamedType('ediPartyName', EDIPartyName().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 5))),
|
||||
namedtype.NamedType('uniformResourceIdentifier', char.IA5String().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 6))),
|
||||
namedtype.NamedType('iPAddress', univ.OctetString().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 7))),
|
||||
namedtype.NamedType('registeredID', univ.ObjectIdentifier().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 8)))
|
||||
)
|
||||
|
||||
class GeneralNames(univ.SequenceOf):
|
||||
componentType = GeneralName()
|
||||
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
|
||||
|
||||
class AccessDescription(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('accessMethod', univ.ObjectIdentifier()),
|
||||
namedtype.NamedType('accessLocation', GeneralName())
|
||||
)
|
||||
|
||||
class AuthorityInfoAccessSyntax(univ.SequenceOf):
|
||||
componentType = AccessDescription()
|
||||
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
|
||||
|
||||
id_ce_deltaCRLIndicator = univ.ObjectIdentifier('2.5.29.27')
|
||||
|
||||
class DistributionPointName(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('fullName', GeneralNames().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
|
||||
namedtype.NamedType('nameRelativeToCRLIssuer', RelativeDistinguishedName().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
|
||||
)
|
||||
|
||||
class DistributionPoint(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.OptionalNamedType('distributionPoint', DistributionPointName().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
|
||||
namedtype.OptionalNamedType('reasons', ReasonFlags().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
|
||||
namedtype.OptionalNamedType('cRLIssuer', GeneralNames().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2)))
|
||||
)
|
||||
class BaseDistance(univ.Integer):
|
||||
subtypeSpec = univ.Integer.subtypeSpec + constraint.ValueRangeConstraint(0, MAX)
|
||||
|
||||
id_ce_cRLDistributionPoints = univ.ObjectIdentifier('2.5.29.31')
|
||||
|
||||
class CRLDistPointsSyntax(univ.SequenceOf):
|
||||
componentType = DistributionPoint
|
||||
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
|
||||
id_ce_issuingDistributionPoint = univ.ObjectIdentifier('2.5.29.28')
|
||||
|
||||
class IssuingDistributionPoint(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.OptionalNamedType('distributionPoint', DistributionPointName().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
|
||||
namedtype.NamedType('onlyContainsUserCerts', univ.Boolean(False).subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
|
||||
namedtype.NamedType('onlyContainsCACerts', univ.Boolean(False).subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
|
||||
namedtype.OptionalNamedType('onlySomeReasons', ReasonFlags().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))),
|
||||
namedtype.NamedType('indirectCRL', univ.Boolean(False).subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4)))
|
||||
)
|
||||
|
||||
class GeneralSubtree(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('base', GeneralName()),
|
||||
namedtype.NamedType('minimum', BaseDistance(0).subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
|
||||
namedtype.OptionalNamedType('maximum', BaseDistance().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
|
||||
)
|
||||
|
||||
class GeneralSubtrees(univ.SequenceOf):
|
||||
componentType = GeneralSubtree()
|
||||
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
|
||||
|
||||
id_ce_nameConstraints = univ.ObjectIdentifier('2.5.29.30')
|
||||
|
||||
class NameConstraints(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.OptionalNamedType('permittedSubtrees', GeneralSubtrees().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
|
||||
namedtype.OptionalNamedType('excludedSubtrees', GeneralSubtrees().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
|
||||
)
|
||||
|
||||
|
||||
class DisplayText(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('visibleString', char.VisibleString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, 200))),
|
||||
namedtype.NamedType('bmpString', char.BMPString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, 200))),
|
||||
namedtype.NamedType('utf8String', char.UTF8String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, 200)))
|
||||
)
|
||||
|
||||
class NoticeReference(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('organization', DisplayText()),
|
||||
namedtype.NamedType('noticeNumbers', univ.SequenceOf(componentType=univ.Integer()))
|
||||
)
|
||||
|
||||
class UserNotice(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.OptionalNamedType('noticeRef', NoticeReference()),
|
||||
namedtype.OptionalNamedType('explicitText', DisplayText())
|
||||
)
|
||||
|
||||
class CPSuri(char.IA5String): pass
|
||||
|
||||
class PolicyQualifierId(univ.ObjectIdentifier):
|
||||
subtypeSpec = univ.ObjectIdentifier.subtypeSpec + constraint.SingleValueConstraint(id_qt_cps, id_qt_unotice)
|
||||
|
||||
class CertPolicyId(univ.ObjectIdentifier): pass
|
||||
|
||||
class PolicyQualifierInfo(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('policyQualifierId', PolicyQualifierId()),
|
||||
namedtype.NamedType('qualifier', univ.Any())
|
||||
)
|
||||
|
||||
id_ce_certificatePolicies = univ.ObjectIdentifier('2.5.29.32')
|
||||
|
||||
class PolicyInformation(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('policyIdentifier', CertPolicyId()),
|
||||
namedtype.OptionalNamedType('policyQualifiers', univ.SequenceOf(componentType=PolicyQualifierInfo()).subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX)))
|
||||
)
|
||||
|
||||
class CertificatePolicies(univ.SequenceOf):
|
||||
componentType = PolicyInformation()
|
||||
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
|
||||
|
||||
id_ce_policyMappings = univ.ObjectIdentifier('2.5.29.33')
|
||||
|
||||
class PolicyMapping(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('issuerDomainPolicy', CertPolicyId()),
|
||||
namedtype.NamedType('subjectDomainPolicy', CertPolicyId())
|
||||
)
|
||||
|
||||
class PolicyMappings(univ.SequenceOf):
|
||||
componentType = PolicyMapping()
|
||||
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
|
||||
|
||||
id_ce_privateKeyUsagePeriod = univ.ObjectIdentifier('2.5.29.16')
|
||||
|
||||
class PrivateKeyUsagePeriod(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.OptionalNamedType('notBefore', useful.GeneralizedTime().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.OptionalNamedType('notAfter', useful.GeneralizedTime().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)))
|
||||
)
|
||||
|
||||
id_ce_keyUsage = univ.ObjectIdentifier('2.5.29.15')
|
||||
|
||||
class KeyUsage(univ.BitString):
|
||||
namedValues = namedval.NamedValues(
|
||||
('digitalSignature', 0),
|
||||
('nonRepudiation', 1),
|
||||
('keyEncipherment', 2),
|
||||
('dataEncipherment', 3),
|
||||
('keyAgreement', 4),
|
||||
('keyCertSign', 5),
|
||||
('cRLSign', 6),
|
||||
('encipherOnly', 7),
|
||||
('decipherOnly', 8)
|
||||
)
|
||||
|
||||
id_ce = univ.ObjectIdentifier('2.5.29')
|
||||
|
||||
id_ce_authorityKeyIdentifier = univ.ObjectIdentifier('2.5.29.35')
|
||||
|
||||
class KeyIdentifier(univ.OctetString): pass
|
||||
|
||||
id_ce_subjectKeyIdentifier = univ.ObjectIdentifier('2.5.29.14')
|
||||
|
||||
class SubjectKeyIdentifier(KeyIdentifier): pass
|
||||
|
||||
class AuthorityKeyIdentifier(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.OptionalNamedType('keyIdentifier', KeyIdentifier().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.OptionalNamedType('authorityCertIssuer', GeneralNames().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
|
||||
namedtype.OptionalNamedType('authorityCertSerialNumber', CertificateSerialNumber().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2)))
|
||||
)
|
||||
|
||||
id_ce_certificateIssuer = univ.ObjectIdentifier('2.5.29.29')
|
||||
|
||||
class CertificateIssuer(GeneralNames): pass
|
||||
|
||||
id_ce_subjectAltName = univ.ObjectIdentifier('2.5.29.17')
|
||||
|
||||
class SubjectAltName(GeneralNames): pass
|
||||
|
||||
id_ce_issuerAltName = univ.ObjectIdentifier('2.5.29.18')
|
||||
|
||||
class IssuerAltName(GeneralNames): pass
|
||||
@@ -0,0 +1,176 @@
|
||||
#
|
||||
# X.509 certificate Request Message Format (CRMF) syntax
|
||||
#
|
||||
# ASN.1 source from:
|
||||
# http://tools.ietf.org/html/rfc2511
|
||||
#
|
||||
# Sample captures could be obtained with OpenSSL
|
||||
#
|
||||
from pyasn1.type import tag, namedtype, namedval, univ, constraint, char,useful
|
||||
from pyasn1_modules.rfc2459 import *
|
||||
from pyasn1_modules import rfc2315
|
||||
|
||||
MAX=16
|
||||
|
||||
id_pkix = univ.ObjectIdentifier('1.3.6.1.5.5.7')
|
||||
id_pkip = univ.ObjectIdentifier('1.3.6.1.5.5.7.5')
|
||||
id_regCtrl = univ.ObjectIdentifier('1.3.6.1.5.5.7.5.1')
|
||||
id_regCtrl_regToken = univ.ObjectIdentifier('1.3.6.1.5.5.7.5.1.1')
|
||||
id_regCtrl_authenticator = univ.ObjectIdentifier('1.3.6.1.5.5.7.5.1.2')
|
||||
id_regCtrl_pkiPublicationInfo = univ.ObjectIdentifier('1.3.6.1.5.5.7.5.1.3')
|
||||
id_regCtrl_pkiArchiveOptions = univ.ObjectIdentifier('1.3.6.1.5.5.7.5.1.4')
|
||||
id_regCtrl_oldCertID = univ.ObjectIdentifier('1.3.6.1.5.5.7.5.1.5')
|
||||
id_regCtrl_protocolEncrKey = univ.ObjectIdentifier('1.3.6.1.5.5.7.5.1.6')
|
||||
id_regInfo = univ.ObjectIdentifier('1.3.6.1.5.5.7.5.2')
|
||||
id_regInfo_utf8Pairs = univ.ObjectIdentifier('1.3.6.1.5.5.7.5.2.1')
|
||||
id_regInfo_certReq = univ.ObjectIdentifier('1.3.6.1.5.5.7.5.2.2')
|
||||
|
||||
# This should be in PKIX Certificate Extensions module
|
||||
|
||||
class GeneralName(univ.OctetString): pass
|
||||
|
||||
# end of PKIX Certificate Extensions module
|
||||
|
||||
class UTF8Pairs(char.UTF8String): pass
|
||||
|
||||
class ProtocolEncrKey(SubjectPublicKeyInfo): pass
|
||||
|
||||
class CertId(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('issuer', GeneralName()),
|
||||
namedtype.NamedType('serialNumber', univ.Integer())
|
||||
)
|
||||
|
||||
class OldCertId(CertId): pass
|
||||
|
||||
class KeyGenParameters(univ.OctetString): pass
|
||||
|
||||
class EncryptedValue(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.OptionalNamedType('intendedAlg', AlgorithmIdentifier().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
|
||||
namedtype.OptionalNamedType('symmAlg', AlgorithmIdentifier().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))),
|
||||
namedtype.OptionalNamedType('encSymmKey', univ.BitString().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2))),
|
||||
namedtype.OptionalNamedType('keyAlg', AlgorithmIdentifier().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3))),
|
||||
namedtype.OptionalNamedType('valueHint', univ.OctetString().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 4))),
|
||||
namedtype.NamedType('encValue', univ.BitString())
|
||||
)
|
||||
|
||||
class EncryptedKey(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('encryptedValue', EncryptedValue()),
|
||||
namedtype.NamedType('envelopedData', rfc2315.EnvelopedData().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
|
||||
)
|
||||
|
||||
class PKIArchiveOptions(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('encryptedPrivKey', EncryptedKey().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
|
||||
namedtype.NamedType('keyGenParameters', KeyGenParameters().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
|
||||
namedtype.NamedType('archiveRemGenPrivKey', univ.Boolean().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2)))
|
||||
)
|
||||
|
||||
class SinglePubInfo(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('pubMethod', univ.Integer(namedValues=namedval.NamedValues(('dontCare', 0), ('x500', 1), ('web', 2), ('ldap', 3)))),
|
||||
namedtype.OptionalNamedType('pubLocation', GeneralName())
|
||||
)
|
||||
|
||||
class PKIPublicationInfo(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('action', univ.Integer(namedValues=namedval.NamedValues(('dontPublish', 0), ('pleasePublish', 1)))),
|
||||
namedtype.OptionalNamedType('pubInfos', univ.SequenceOf(componentType=SinglePubInfo()).subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX)))
|
||||
)
|
||||
|
||||
class Authenticator(char.UTF8String): pass
|
||||
class RegToken(char.UTF8String): pass
|
||||
|
||||
class SubsequentMessage(univ.Integer):
|
||||
namedValues = namedval.NamedValues(
|
||||
('encrCert', 0),
|
||||
('challengeResp', 1)
|
||||
)
|
||||
|
||||
class POPOPrivKey(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('thisMessage', univ.BitString().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.NamedType('subsequentMessage', SubsequentMessage().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
|
||||
namedtype.NamedType('dhMAC', univ.BitString().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2)))
|
||||
)
|
||||
|
||||
class PBMParameter(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('salt', univ.OctetString()),
|
||||
namedtype.NamedType('owf', AlgorithmIdentifier()),
|
||||
namedtype.NamedType('iterationCount', univ.Integer()),
|
||||
namedtype.NamedType('mac', AlgorithmIdentifier())
|
||||
)
|
||||
|
||||
class PKMACValue(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('algId', AlgorithmIdentifier()),
|
||||
namedtype.NamedType('value', univ.BitString())
|
||||
)
|
||||
|
||||
class POPOSigningKeyInput(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('authInfo', univ.Choice(componentType=namedtype.NamedTypes(namedtype.NamedType('sender', GeneralName().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))), namedtype.NamedType('publicKeyMAC', PKMACValue())))),
|
||||
namedtype.NamedType('publicKey', SubjectPublicKeyInfo())
|
||||
)
|
||||
|
||||
class POPOSigningKey(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.OptionalNamedType('poposkInput', POPOSigningKeyInput().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
|
||||
namedtype.NamedType('algorithmIdentifier', AlgorithmIdentifier()),
|
||||
namedtype.NamedType('signature', univ.BitString())
|
||||
)
|
||||
|
||||
class ProofOfPossession(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('raVerified', univ.Null().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.NamedType('signature', POPOSigningKey().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))),
|
||||
namedtype.NamedType('keyEncipherment', POPOPrivKey().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2))),
|
||||
namedtype.NamedType('keyAgreement', POPOPrivKey().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3)))
|
||||
)
|
||||
|
||||
class Controls(univ.SequenceOf):
|
||||
componentType = AttributeTypeAndValue()
|
||||
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
|
||||
|
||||
class OptionalValidity(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.OptionalNamedType('notBefore', Time().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.OptionalNamedType('notAfter', Time().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)))
|
||||
)
|
||||
|
||||
class CertTemplate(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.OptionalNamedType('version', Version().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.OptionalNamedType('serialNumber', univ.Integer().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
|
||||
namedtype.OptionalNamedType('signingAlg', AlgorithmIdentifier().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2))),
|
||||
namedtype.OptionalNamedType('issuer', Name().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3))),
|
||||
namedtype.OptionalNamedType('validity', OptionalValidity().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 4))),
|
||||
namedtype.OptionalNamedType('subject', Name().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 5))),
|
||||
namedtype.OptionalNamedType('publicKey', SubjectPublicKeyInfo().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 6))),
|
||||
namedtype.OptionalNamedType('issuerUID', UniqueIdentifier().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 7))),
|
||||
namedtype.OptionalNamedType('subjectUID', UniqueIdentifier().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 8))),
|
||||
namedtype.OptionalNamedType('extensions', Extensions().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 9)))
|
||||
)
|
||||
|
||||
class CertRequest(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('certReqId', univ.Integer()),
|
||||
namedtype.NamedType('certTemplate', CertTemplate()),
|
||||
namedtype.OptionalNamedType('controls', Controls())
|
||||
)
|
||||
|
||||
class CertReq(CertRequest): pass
|
||||
|
||||
class CertReqMsg(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('certReq', CertRequest()),
|
||||
namedtype.OptionalNamedType('pop', ProofOfPossession()),
|
||||
namedtype.OptionalNamedType('regInfo', univ.SequenceOf(componentType=AttributeTypeAndValue).subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX)))
|
||||
)
|
||||
|
||||
class CertReqMessages(univ.SequenceOf):
|
||||
componentType = CertReqMsg()
|
||||
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
|
||||
@@ -0,0 +1,171 @@
|
||||
#
|
||||
# OCSP request/response syntax
|
||||
#
|
||||
# Derived from a minimal OCSP library (RFC2560) code written by
|
||||
# Bud P. Bruegger <bud@ancitel.it>
|
||||
# Copyright: Ancitel, S.p.a, Rome, Italy
|
||||
# License: BSD
|
||||
#
|
||||
|
||||
#
|
||||
# current limitations:
|
||||
# * request and response works only for a single certificate
|
||||
# * only some values are parsed out of the response
|
||||
# * the request does't set a nonce nor signature
|
||||
# * there is no signature validation of the response
|
||||
# * dates are left as strings in GeneralizedTime format -- datetime.datetime
|
||||
# would be nicer
|
||||
#
|
||||
from pyasn1.type import tag, namedtype, namedval, univ, constraint, useful
|
||||
from pyasn1_modules import rfc2459
|
||||
|
||||
# Start of OCSP module definitions
|
||||
|
||||
# This should be in directory Authentication Framework (X.509) module
|
||||
|
||||
class CRLReason(univ.Enumerated):
|
||||
namedValues = namedval.NamedValues(
|
||||
('unspecified', 0),
|
||||
('keyCompromise', 1),
|
||||
('cACompromise', 2),
|
||||
('affiliationChanged', 3),
|
||||
('superseded', 4),
|
||||
('cessationOfOperation', 5),
|
||||
('certificateHold', 6),
|
||||
('removeFromCRL', 8),
|
||||
('privilegeWithdrawn', 9),
|
||||
('aACompromise', 10)
|
||||
)
|
||||
|
||||
# end of directory Authentication Framework (X.509) module
|
||||
|
||||
# This should be in PKIX Certificate Extensions module
|
||||
|
||||
class GeneralName(univ.OctetString): pass
|
||||
|
||||
# end of PKIX Certificate Extensions module
|
||||
|
||||
id_kp_OCSPSigning = univ.ObjectIdentifier((1, 3, 6, 1, 5, 5, 7, 3, 9))
|
||||
id_pkix_ocsp = univ.ObjectIdentifier((1, 3, 6, 1, 5, 5, 7, 48, 1))
|
||||
id_pkix_ocsp_basic = univ.ObjectIdentifier((1, 3, 6, 1, 5, 5, 7, 48, 1, 1))
|
||||
id_pkix_ocsp_nonce = univ.ObjectIdentifier((1, 3, 6, 1, 5, 5, 7, 48, 1, 2))
|
||||
id_pkix_ocsp_crl = univ.ObjectIdentifier((1, 3, 6, 1, 5, 5, 7, 48, 1, 3))
|
||||
id_pkix_ocsp_response = univ.ObjectIdentifier((1, 3, 6, 1, 5, 5, 7, 48, 1, 4))
|
||||
id_pkix_ocsp_nocheck = univ.ObjectIdentifier((1, 3, 6, 1, 5, 5, 7, 48, 1, 5))
|
||||
id_pkix_ocsp_archive_cutoff = univ.ObjectIdentifier((1, 3, 6, 1, 5, 5, 7, 48, 1, 6))
|
||||
id_pkix_ocsp_service_locator = univ.ObjectIdentifier((1, 3, 6, 1, 5, 5, 7, 48, 1, 7))
|
||||
|
||||
class AcceptableResponses(univ.SequenceOf):
|
||||
componentType = univ.ObjectIdentifier()
|
||||
|
||||
class ArchiveCutoff(useful.GeneralizedTime): pass
|
||||
|
||||
class UnknownInfo(univ.Null): pass
|
||||
|
||||
class RevokedInfo(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('revocationTime', useful.GeneralizedTime()),
|
||||
namedtype.OptionalNamedType('revocationReason', CRLReason().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
|
||||
)
|
||||
|
||||
class CertID(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('hashAlgorithm', rfc2459.AlgorithmIdentifier()),
|
||||
namedtype.NamedType('issuerNameHash', univ.OctetString()),
|
||||
namedtype.NamedType('issuerKeyHash', univ.OctetString()),
|
||||
namedtype.NamedType('serialNumber', rfc2459.CertificateSerialNumber())
|
||||
)
|
||||
|
||||
class CertStatus(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('good', univ.Null().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.NamedType('revoked', RevokedInfo().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
|
||||
namedtype.NamedType('unknown', UnknownInfo().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2)))
|
||||
)
|
||||
|
||||
class SingleResponse(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('certID', CertID()),
|
||||
namedtype.NamedType('certStatus', CertStatus()),
|
||||
namedtype.NamedType('thisUpdate', useful.GeneralizedTime()),
|
||||
namedtype.OptionalNamedType('nextUpdate', useful.GeneralizedTime().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.OptionalNamedType('singleExtensions', rfc2459.Extensions().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)))
|
||||
)
|
||||
|
||||
class KeyHash(univ.OctetString): pass
|
||||
|
||||
class ResponderID(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('byName', rfc2459.Name().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
|
||||
namedtype.NamedType('byKey', KeyHash().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2)))
|
||||
)
|
||||
|
||||
class Version(univ.Integer):
|
||||
namedValues = namedval.NamedValues(('v1', 0))
|
||||
|
||||
class ResponseData(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.DefaultedNamedType('version', Version('v1').subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.NamedType('responderID', ResponderID()),
|
||||
namedtype.NamedType('producedAt', useful.GeneralizedTime()),
|
||||
namedtype.NamedType('responses', univ.SequenceOf(SingleResponse())),
|
||||
namedtype.OptionalNamedType('responseExtensions', rfc2459.Extensions().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)))
|
||||
)
|
||||
|
||||
class BasicOCSPResponse(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('tbsResponseData', ResponseData()),
|
||||
namedtype.NamedType('signatureAlgorithm', rfc2459.AlgorithmIdentifier()),
|
||||
namedtype.NamedType('signature', univ.BitString()),
|
||||
namedtype.OptionalNamedType('certs', univ.SequenceOf(rfc2459.Certificate()).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
|
||||
)
|
||||
|
||||
class ResponseBytes(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('responseType', univ.ObjectIdentifier()),
|
||||
namedtype.NamedType('response', univ.OctetString())
|
||||
)
|
||||
|
||||
class OCSPResponseStatus(univ.Enumerated):
|
||||
namedValues = namedval.NamedValues(
|
||||
('successful', 0),
|
||||
('malformedRequest', 1),
|
||||
('internalError', 2),
|
||||
('tryLater', 3),
|
||||
('undefinedStatus', 4), # should never occur
|
||||
('sigRequired', 5),
|
||||
('unauthorized', 6)
|
||||
)
|
||||
|
||||
class OCSPResponse(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('responseStatus', OCSPResponseStatus()),
|
||||
namedtype.OptionalNamedType('responseBytes', ResponseBytes().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
|
||||
)
|
||||
|
||||
class Request(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('reqCert', CertID()),
|
||||
namedtype.OptionalNamedType('singleRequestExtensions', rfc2459.Extensions().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
|
||||
)
|
||||
|
||||
class Signature(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('signatureAlgorithm', rfc2459.AlgorithmIdentifier()),
|
||||
namedtype.NamedType('signature', univ.BitString()),
|
||||
namedtype.OptionalNamedType('certs', univ.SequenceOf(rfc2459.Certificate()).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
|
||||
)
|
||||
|
||||
class TBSRequest(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.DefaultedNamedType('version', Version('v1').subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.OptionalNamedType('requestorName', GeneralName().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
|
||||
namedtype.NamedType('requestList', univ.SequenceOf(Request())),
|
||||
namedtype.OptionalNamedType('requestExtensions', rfc2459.Extensions().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2)))
|
||||
)
|
||||
|
||||
class OCSPRequest(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('tbsRequest', TBSRequest()),
|
||||
namedtype.OptionalNamedType('optionalSignature', Signature().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
|
||||
)
|
||||
@@ -0,0 +1,38 @@
|
||||
#
|
||||
# SNMPv3 message syntax
|
||||
#
|
||||
# ASN.1 source from:
|
||||
# http://www.ietf.org/rfc/rfc3412.txt
|
||||
#
|
||||
from pyasn1.type import univ, namedtype, namedval, tag, constraint
|
||||
from pyasn1_modules import rfc1905
|
||||
|
||||
class ScopedPDU(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('contextEngineId', univ.OctetString()),
|
||||
namedtype.NamedType('contextName', univ.OctetString()),
|
||||
namedtype.NamedType('data', rfc1905.PDUs())
|
||||
)
|
||||
|
||||
class ScopedPduData(univ.Choice):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('plaintext', ScopedPDU()),
|
||||
namedtype.NamedType('encryptedPDU', univ.OctetString()),
|
||||
)
|
||||
|
||||
class HeaderData(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('msgID', univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, 2147483647))),
|
||||
namedtype.NamedType('msgMaxSize', univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(484, 2147483647))),
|
||||
namedtype.NamedType('msgFlags', univ.OctetString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, 1))),
|
||||
namedtype.NamedType('msgSecurityModel', univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(1, 2147483647)))
|
||||
)
|
||||
|
||||
class SNMPv3Message(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('msgVersion', univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, 2147483647))),
|
||||
namedtype.NamedType('msgGlobalData', HeaderData()),
|
||||
namedtype.NamedType('msgSecurityParameters', univ.OctetString()),
|
||||
namedtype.NamedType('msgData', ScopedPduData())
|
||||
)
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#
|
||||
# SNMPv3 message syntax
|
||||
#
|
||||
# ASN.1 source from:
|
||||
# http://www.ietf.org/rfc/rfc3414.txt
|
||||
#
|
||||
from pyasn1.type import univ, namedtype, namedval, tag, constraint
|
||||
|
||||
class UsmSecurityParameters(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('msgAuthoritativeEngineID', univ.OctetString()),
|
||||
namedtype.NamedType('msgAuthoritativeEngineBoots', univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, 2147483647))),
|
||||
namedtype.NamedType('msgAuthoritativeEngineTime', univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, 2147483647))),
|
||||
namedtype.NamedType('msgUserName', univ.OctetString().subtype(subtypeSpec=constraint.ValueSizeConstraint(0, 32))),
|
||||
namedtype.NamedType('msgAuthenticationParameters', univ.OctetString()),
|
||||
namedtype.NamedType('msgPrivacyParameters', univ.OctetString())
|
||||
)
|
||||
@@ -0,0 +1,35 @@
|
||||
#
|
||||
# PKCS#1 syntax
|
||||
#
|
||||
# ASN.1 source from:
|
||||
# ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn
|
||||
#
|
||||
# Sample captures could be obtained with "openssl genrsa" command
|
||||
#
|
||||
from pyasn1_modules.rfc2437 import *
|
||||
|
||||
class OtherPrimeInfo(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('prime', univ.Integer()),
|
||||
namedtype.NamedType('exponent', univ.Integer()),
|
||||
namedtype.NamedType('coefficient', univ.Integer())
|
||||
)
|
||||
|
||||
class OtherPrimeInfos(univ.SequenceOf):
|
||||
componentType = OtherPrimeInfo()
|
||||
subtypeSpec = univ.SequenceOf.subtypeSpec + \
|
||||
constraint.ValueSizeConstraint(1, MAX)
|
||||
|
||||
class RSAPrivateKey(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('version', univ.Integer(namedValues=namedval.NamedValues(('two-prime', 0), ('multi', 1)))),
|
||||
namedtype.NamedType('modulus', univ.Integer()),
|
||||
namedtype.NamedType('publicExponent', univ.Integer()),
|
||||
namedtype.NamedType('privateExponent', univ.Integer()),
|
||||
namedtype.NamedType('prime1', univ.Integer()),
|
||||
namedtype.NamedType('prime2', univ.Integer()),
|
||||
namedtype.NamedType('exponent1', univ.Integer()),
|
||||
namedtype.NamedType('exponent2', univ.Integer()),
|
||||
namedtype.NamedType('coefficient', univ.Integer()),
|
||||
namedtype.OptionalNamedType('otherPrimeInfos', OtherPrimeInfos())
|
||||
)
|
||||
@@ -0,0 +1,695 @@
|
||||
#
|
||||
# Certificate Management Protocol structures as per RFC4210
|
||||
#
|
||||
# Based on Alex Railean's work
|
||||
#
|
||||
from pyasn1.type import tag,namedtype,namedval,univ,constraint,char,useful
|
||||
from pyasn1_modules import rfc2459, rfc2511, rfc2314
|
||||
|
||||
MAX = 64
|
||||
|
||||
class KeyIdentifier(univ.OctetString): pass
|
||||
|
||||
class CMPCertificate(rfc2459.Certificate): pass
|
||||
|
||||
class OOBCert(CMPCertificate): pass
|
||||
|
||||
class CertAnnContent(CMPCertificate): pass
|
||||
|
||||
class PKIFreeText(univ.SequenceOf):
|
||||
"""
|
||||
PKIFreeText ::= SEQUENCE SIZE (1..MAX) OF UTF8String
|
||||
"""
|
||||
componentType = char.UTF8String()
|
||||
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
|
||||
|
||||
class PollRepContent(univ.SequenceOf):
|
||||
"""
|
||||
PollRepContent ::= SEQUENCE OF SEQUENCE {
|
||||
certReqId INTEGER,
|
||||
checkAfter INTEGER, -- time in seconds
|
||||
reason PKIFreeText OPTIONAL
|
||||
}
|
||||
"""
|
||||
class CertReq(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('certReqId', univ.Integer()),
|
||||
namedtype.NamedType('checkAfter', univ.Integer()),
|
||||
namedtype.OptionalNamedType('reason', PKIFreeText())
|
||||
)
|
||||
componentType = CertReq()
|
||||
|
||||
class PollReqContent(univ.SequenceOf):
|
||||
"""
|
||||
PollReqContent ::= SEQUENCE OF SEQUENCE {
|
||||
certReqId INTEGER
|
||||
}
|
||||
|
||||
"""
|
||||
class CertReq(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('certReqId', univ.Integer())
|
||||
)
|
||||
componentType = CertReq()
|
||||
|
||||
class InfoTypeAndValue(univ.Sequence):
|
||||
"""
|
||||
InfoTypeAndValue ::= SEQUENCE {
|
||||
infoType OBJECT IDENTIFIER,
|
||||
infoValue ANY DEFINED BY infoType OPTIONAL
|
||||
}"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('infoType', univ.ObjectIdentifier()),
|
||||
namedtype.OptionalNamedType('infoValue', univ.Any())
|
||||
)
|
||||
|
||||
class GenRepContent(univ.SequenceOf):
|
||||
componentType = InfoTypeAndValue()
|
||||
|
||||
class GenMsgContent(univ.SequenceOf):
|
||||
componentType = InfoTypeAndValue()
|
||||
|
||||
class PKIConfirmContent(univ.Null): pass
|
||||
|
||||
class CRLAnnContent(univ.SequenceOf):
|
||||
componentType = rfc2459.CertificateList()
|
||||
|
||||
class CAKeyUpdAnnContent(univ.Sequence):
|
||||
"""
|
||||
CAKeyUpdAnnContent ::= SEQUENCE {
|
||||
oldWithNew CMPCertificate,
|
||||
newWithOld CMPCertificate,
|
||||
newWithNew CMPCertificate
|
||||
}
|
||||
"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('oldWithNew', CMPCertificate()),
|
||||
namedtype.NamedType('newWithOld', CMPCertificate()),
|
||||
namedtype.NamedType('newWithNew', CMPCertificate())
|
||||
)
|
||||
|
||||
class RevDetails(univ.Sequence):
|
||||
"""
|
||||
RevDetails ::= SEQUENCE {
|
||||
certDetails CertTemplate,
|
||||
crlEntryDetails Extensions OPTIONAL
|
||||
}
|
||||
"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('certDetails', rfc2511.CertTemplate()),
|
||||
namedtype.OptionalNamedType('crlEntryDetails', rfc2459.Extensions())
|
||||
)
|
||||
|
||||
class RevReqContent(univ.SequenceOf):
|
||||
componentType = RevDetails()
|
||||
|
||||
class CertOrEncCert(univ.Choice):
|
||||
"""
|
||||
CertOrEncCert ::= CHOICE {
|
||||
certificate [0] CMPCertificate,
|
||||
encryptedCert [1] EncryptedValue
|
||||
}
|
||||
"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('certificate', CMPCertificate().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('encryptedCert', rfc2511.EncryptedValue().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
class CertifiedKeyPair(univ.Sequence):
|
||||
"""
|
||||
CertifiedKeyPair ::= SEQUENCE {
|
||||
certOrEncCert CertOrEncCert,
|
||||
privateKey [0] EncryptedValue OPTIONAL,
|
||||
publicationInfo [1] PKIPublicationInfo OPTIONAL
|
||||
}
|
||||
"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('certOrEncCert', CertOrEncCert()),
|
||||
namedtype.OptionalNamedType('privateKey', rfc2511.EncryptedValue().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)
|
||||
)
|
||||
),
|
||||
namedtype.OptionalNamedType('publicationInfo', rfc2511.PKIPublicationInfo().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class POPODecKeyRespContent(univ.SequenceOf):
|
||||
componentType = univ.Integer()
|
||||
|
||||
class Challenge(univ.Sequence):
|
||||
"""
|
||||
Challenge ::= SEQUENCE {
|
||||
owf AlgorithmIdentifier OPTIONAL,
|
||||
witness OCTET STRING,
|
||||
challenge OCTET STRING
|
||||
}
|
||||
"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.OptionalNamedType('owf', rfc2459.AlgorithmIdentifier()),
|
||||
namedtype.NamedType('witness', univ.OctetString()),
|
||||
namedtype.NamedType('challenge', univ.OctetString())
|
||||
)
|
||||
|
||||
class PKIStatus(univ.Integer):
|
||||
"""
|
||||
PKIStatus ::= INTEGER {
|
||||
accepted (0),
|
||||
grantedWithMods (1),
|
||||
rejection (2),
|
||||
waiting (3),
|
||||
revocationWarning (4),
|
||||
revocationNotification (5),
|
||||
keyUpdateWarning (6)
|
||||
}
|
||||
"""
|
||||
namedValues = namedval.NamedValues(
|
||||
('accepted', 0),
|
||||
('grantedWithMods', 1),
|
||||
('rejection', 2),
|
||||
('waiting', 3),
|
||||
('revocationWarning', 4),
|
||||
('revocationNotification', 5),
|
||||
('keyUpdateWarning', 6)
|
||||
)
|
||||
|
||||
class PKIFailureInfo(univ.BitString):
|
||||
"""
|
||||
PKIFailureInfo ::= BIT STRING {
|
||||
badAlg (0),
|
||||
badMessageCheck (1),
|
||||
badRequest (2),
|
||||
badTime (3),
|
||||
badCertId (4),
|
||||
badDataFormat (5),
|
||||
wrongAuthority (6),
|
||||
incorrectData (7),
|
||||
missingTimeStamp (8),
|
||||
badPOP (9),
|
||||
certRevoked (10),
|
||||
certConfirmed (11),
|
||||
wrongIntegrity (12),
|
||||
badRecipientNonce (13),
|
||||
timeNotAvailable (14),
|
||||
unacceptedPolicy (15),
|
||||
unacceptedExtension (16),
|
||||
addInfoNotAvailable (17),
|
||||
badSenderNonce (18),
|
||||
badCertTemplate (19),
|
||||
signerNotTrusted (20),
|
||||
transactionIdInUse (21),
|
||||
unsupportedVersion (22),
|
||||
notAuthorized (23),
|
||||
systemUnavail (24),
|
||||
systemFailure (25),
|
||||
duplicateCertReq (26)
|
||||
"""
|
||||
namedValues = namedval.NamedValues(
|
||||
('badAlg', 0),
|
||||
('badMessageCheck', 1),
|
||||
('badRequest', 2),
|
||||
('badTime', 3),
|
||||
('badCertId', 4),
|
||||
('badDataFormat', 5),
|
||||
('wrongAuthority', 6),
|
||||
('incorrectData', 7),
|
||||
('missingTimeStamp', 8),
|
||||
('badPOP', 9),
|
||||
('certRevoked', 10),
|
||||
('certConfirmed', 11),
|
||||
('wrongIntegrity', 12),
|
||||
('badRecipientNonce', 13),
|
||||
('timeNotAvailable', 14),
|
||||
('unacceptedPolicy', 15),
|
||||
('unacceptedExtension', 16),
|
||||
('addInfoNotAvailable', 17),
|
||||
('badSenderNonce', 18),
|
||||
('badCertTemplate', 19),
|
||||
('signerNotTrusted', 20),
|
||||
('transactionIdInUse', 21),
|
||||
('unsupportedVersion', 22),
|
||||
('notAuthorized', 23),
|
||||
('systemUnavail', 24),
|
||||
('systemFailure', 25),
|
||||
('duplicateCertReq', 26)
|
||||
)
|
||||
|
||||
class PKIStatusInfo(univ.Sequence):
|
||||
"""
|
||||
PKIStatusInfo ::= SEQUENCE {
|
||||
status PKIStatus,
|
||||
statusString PKIFreeText OPTIONAL,
|
||||
failInfo PKIFailureInfo OPTIONAL
|
||||
}
|
||||
"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('status', PKIStatus()),
|
||||
namedtype.OptionalNamedType('statusString', PKIFreeText()),
|
||||
namedtype.OptionalNamedType('failInfo', PKIFailureInfo())
|
||||
)
|
||||
|
||||
class ErrorMsgContent(univ.Sequence):
|
||||
"""
|
||||
ErrorMsgContent ::= SEQUENCE {
|
||||
pKIStatusInfo PKIStatusInfo,
|
||||
errorCode INTEGER OPTIONAL,
|
||||
-- implementation-specific error codes
|
||||
errorDetails PKIFreeText OPTIONAL
|
||||
-- implementation-specific error details
|
||||
}
|
||||
"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('pKIStatusInfo', PKIStatusInfo()),
|
||||
namedtype.OptionalNamedType('errorCode', univ.Integer()),
|
||||
namedtype.OptionalNamedType('errorDetails', PKIFreeText())
|
||||
)
|
||||
|
||||
class CertStatus(univ.Sequence):
|
||||
"""
|
||||
CertStatus ::= SEQUENCE {
|
||||
certHash OCTET STRING,
|
||||
certReqId INTEGER,
|
||||
statusInfo PKIStatusInfo OPTIONAL
|
||||
}
|
||||
"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('certHash', univ.OctetString()),
|
||||
namedtype.NamedType('certReqId', univ.Integer()),
|
||||
namedtype.OptionalNamedType('statusInfo', PKIStatusInfo())
|
||||
)
|
||||
|
||||
class CertConfirmContent(univ.SequenceOf):
|
||||
componentType = CertStatus()
|
||||
|
||||
class RevAnnContent(univ.Sequence):
|
||||
"""
|
||||
RevAnnContent ::= SEQUENCE {
|
||||
status PKIStatus,
|
||||
certId CertId,
|
||||
willBeRevokedAt GeneralizedTime,
|
||||
badSinceDate GeneralizedTime,
|
||||
crlDetails Extensions OPTIONAL
|
||||
}
|
||||
"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('status', PKIStatus()),
|
||||
namedtype.NamedType('certId', rfc2511.CertId()),
|
||||
namedtype.NamedType('willBeRevokedAt', useful.GeneralizedTime()),
|
||||
namedtype.NamedType('badSinceDate', useful.GeneralizedTime()),
|
||||
namedtype.OptionalNamedType('crlDetails', rfc2459.Extensions())
|
||||
)
|
||||
|
||||
class RevRepContent(univ.Sequence):
|
||||
"""
|
||||
RevRepContent ::= SEQUENCE {
|
||||
status SEQUENCE SIZE (1..MAX) OF PKIStatusInfo,
|
||||
revCerts [0] SEQUENCE SIZE (1..MAX) OF CertId
|
||||
OPTIONAL,
|
||||
crls [1] SEQUENCE SIZE (1..MAX) OF CertificateList
|
||||
OPTIONAL
|
||||
"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('status', PKIStatusInfo()),
|
||||
namedtype.OptionalNamedType('revCerts', univ.SequenceOf(
|
||||
componentType=rfc2511.CertId()
|
||||
).subtype(
|
||||
subtypeSpec=constraint.ValueSizeConstraint(1, MAX),
|
||||
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)
|
||||
)
|
||||
),
|
||||
namedtype.OptionalNamedType('crls', univ.SequenceOf(
|
||||
componentType=rfc2459.CertificateList()
|
||||
).subtype(
|
||||
subtypeSpec=constraint.ValueSizeConstraint(1, MAX),
|
||||
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
class KeyRecRepContent(univ.Sequence):
|
||||
"""
|
||||
KeyRecRepContent ::= SEQUENCE {
|
||||
status PKIStatusInfo,
|
||||
newSigCert [0] CMPCertificate OPTIONAL,
|
||||
caCerts [1] SEQUENCE SIZE (1..MAX) OF
|
||||
CMPCertificate OPTIONAL,
|
||||
keyPairHist [2] SEQUENCE SIZE (1..MAX) OF
|
||||
CertifiedKeyPair OPTIONAL
|
||||
}
|
||||
"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('status', PKIStatusInfo()),
|
||||
namedtype.OptionalNamedType('newSigCert', CMPCertificate().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)
|
||||
)
|
||||
),
|
||||
namedtype.OptionalNamedType('caCerts', univ.SequenceOf(
|
||||
componentType=CMPCertificate()
|
||||
).subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1),
|
||||
subtypeSpec=constraint.ValueSizeConstraint(1, MAX)
|
||||
)
|
||||
),
|
||||
namedtype.OptionalNamedType('keyPairHist', univ.SequenceOf(
|
||||
componentType=CertifiedKeyPair()
|
||||
).subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2),
|
||||
subtypeSpec=constraint.ValueSizeConstraint(1, MAX)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
class CertResponse(univ.Sequence):
|
||||
"""
|
||||
CertResponse ::= SEQUENCE {
|
||||
certReqId INTEGER,
|
||||
status PKIStatusInfo,
|
||||
certifiedKeyPair CertifiedKeyPair OPTIONAL,
|
||||
rspInfo OCTET STRING OPTIONAL
|
||||
}
|
||||
"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('certReqId', univ.Integer()),
|
||||
namedtype.NamedType('status', PKIStatusInfo()),
|
||||
namedtype.OptionalNamedType('certifiedKeyPair', CertifiedKeyPair()),
|
||||
namedtype.OptionalNamedType('rspInfo', univ.OctetString())
|
||||
)
|
||||
|
||||
class CertRepMessage(univ.Sequence):
|
||||
"""
|
||||
CertRepMessage ::= SEQUENCE {
|
||||
caPubs [1] SEQUENCE SIZE (1..MAX) OF CMPCertificate
|
||||
OPTIONAL,
|
||||
response SEQUENCE OF CertResponse
|
||||
}
|
||||
"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.OptionalNamedType('caPubs', univ.SequenceOf(
|
||||
componentType=CMPCertificate()
|
||||
).subtype(
|
||||
subtypeSpec=constraint.ValueSizeConstraint(1, MAX),
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,1)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('response', univ.SequenceOf(
|
||||
componentType=CertResponse())
|
||||
)
|
||||
)
|
||||
|
||||
class POPODecKeyChallContent(univ.SequenceOf):
|
||||
componentType = Challenge()
|
||||
|
||||
class OOBCertHash(univ.Sequence):
|
||||
"""
|
||||
OOBCertHash ::= SEQUENCE {
|
||||
hashAlg [0] AlgorithmIdentifier OPTIONAL,
|
||||
certId [1] CertId OPTIONAL,
|
||||
hashVal BIT STRING
|
||||
}
|
||||
"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.OptionalNamedType('hashAlg',
|
||||
rfc2459.AlgorithmIdentifier().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,0)
|
||||
)
|
||||
),
|
||||
namedtype.OptionalNamedType('certId', rfc2511.CertId().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,1)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('hashVal', univ.BitString())
|
||||
)
|
||||
|
||||
# pyasn1 does not naturally handle recursive definitions, thus this hack:
|
||||
# NestedMessageContent ::= PKIMessages
|
||||
class NestedMessageContent(univ.SequenceOf):
|
||||
"""
|
||||
NestedMessageContent ::= PKIMessages
|
||||
"""
|
||||
componentType = univ.Any()
|
||||
|
||||
class DHBMParameter(univ.Sequence):
|
||||
"""
|
||||
DHBMParameter ::= SEQUENCE {
|
||||
owf AlgorithmIdentifier,
|
||||
-- AlgId for a One-Way Function (SHA-1 recommended)
|
||||
mac AlgorithmIdentifier
|
||||
-- the MAC AlgId (e.g., DES-MAC, Triple-DES-MAC [PKCS11],
|
||||
} -- or HMAC [RFC2104, RFC2202])
|
||||
"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('owf', rfc2459.AlgorithmIdentifier()),
|
||||
namedtype.NamedType('mac', rfc2459.AlgorithmIdentifier())
|
||||
)
|
||||
|
||||
id_DHBasedMac = univ.ObjectIdentifier('1.2.840.113533.7.66.30')
|
||||
|
||||
class PBMParameter(univ.Sequence):
|
||||
"""
|
||||
PBMParameter ::= SEQUENCE {
|
||||
salt OCTET STRING,
|
||||
owf AlgorithmIdentifier,
|
||||
iterationCount INTEGER,
|
||||
mac AlgorithmIdentifier
|
||||
}
|
||||
"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('salt', univ.OctetString().subtype(
|
||||
subtypeSpec=constraint.ValueSizeConstraint(0, 128)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('owf', rfc2459.AlgorithmIdentifier()),
|
||||
namedtype.NamedType('iterationCount', univ.Integer()),
|
||||
namedtype.NamedType('mac', rfc2459.AlgorithmIdentifier())
|
||||
)
|
||||
|
||||
id_PasswordBasedMac = univ.ObjectIdentifier('1.2.840.113533.7.66.13')
|
||||
|
||||
class PKIProtection(univ.BitString): pass
|
||||
|
||||
# pyasn1 does not naturally handle recursive definitions, thus this hack:
|
||||
# NestedMessageContent ::= PKIMessages
|
||||
nestedMessageContent = NestedMessageContent().subtype(explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,20))
|
||||
|
||||
class PKIBody(univ.Choice):
|
||||
"""
|
||||
PKIBody ::= CHOICE { -- message-specific body elements
|
||||
ir [0] CertReqMessages, --Initialization Request
|
||||
ip [1] CertRepMessage, --Initialization Response
|
||||
cr [2] CertReqMessages, --Certification Request
|
||||
cp [3] CertRepMessage, --Certification Response
|
||||
p10cr [4] CertificationRequest, --imported from [PKCS10]
|
||||
popdecc [5] POPODecKeyChallContent, --pop Challenge
|
||||
popdecr [6] POPODecKeyRespContent, --pop Response
|
||||
kur [7] CertReqMessages, --Key Update Request
|
||||
kup [8] CertRepMessage, --Key Update Response
|
||||
krr [9] CertReqMessages, --Key Recovery Request
|
||||
krp [10] KeyRecRepContent, --Key Recovery Response
|
||||
rr [11] RevReqContent, --Revocation Request
|
||||
rp [12] RevRepContent, --Revocation Response
|
||||
ccr [13] CertReqMessages, --Cross-Cert. Request
|
||||
ccp [14] CertRepMessage, --Cross-Cert. Response
|
||||
ckuann [15] CAKeyUpdAnnContent, --CA Key Update Ann.
|
||||
cann [16] CertAnnContent, --Certificate Ann.
|
||||
rann [17] RevAnnContent, --Revocation Ann.
|
||||
crlann [18] CRLAnnContent, --CRL Announcement
|
||||
pkiconf [19] PKIConfirmContent, --Confirmation
|
||||
nested [20] NestedMessageContent, --Nested Message
|
||||
genm [21] GenMsgContent, --General Message
|
||||
|
||||
"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('ir', rfc2511.CertReqMessages().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,0)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('ip', CertRepMessage().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,1)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('cr', rfc2511.CertReqMessages().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,2)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('cp', CertRepMessage().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,3)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('p10cr', rfc2314.CertificationRequest().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,4)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('popdecc', POPODecKeyChallContent().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,5)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('popdecr', POPODecKeyRespContent().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,6)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('kur', rfc2511.CertReqMessages().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,7)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('kup', CertRepMessage().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,8)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('krr', rfc2511.CertReqMessages().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,9)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('krp', KeyRecRepContent().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,10)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('rr', RevReqContent().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,11)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('rp', RevRepContent().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,12)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('ccr', rfc2511.CertReqMessages().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,13)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('ccp', CertRepMessage().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,14)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('ckuann', CAKeyUpdAnnContent().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,15)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('cann', CertAnnContent().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,16)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('rann', RevAnnContent().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,17)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('crlann', CRLAnnContent().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,18)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('pkiconf', PKIConfirmContent().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,19)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('nested', nestedMessageContent),
|
||||
# namedtype.NamedType('nested', NestedMessageContent().subtype(
|
||||
# explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,20)
|
||||
# )
|
||||
# ),
|
||||
namedtype.NamedType('genm', GenMsgContent().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,21)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class PKIHeader(univ.Sequence):
|
||||
"""
|
||||
PKIHeader ::= SEQUENCE {
|
||||
pvno INTEGER { cmp1999(1), cmp2000(2) },
|
||||
sender GeneralName,
|
||||
recipient GeneralName,
|
||||
messageTime [0] GeneralizedTime OPTIONAL,
|
||||
protectionAlg [1] AlgorithmIdentifier OPTIONAL,
|
||||
senderKID [2] KeyIdentifier OPTIONAL,
|
||||
recipKID [3] KeyIdentifier OPTIONAL,
|
||||
transactionID [4] OCTET STRING OPTIONAL,
|
||||
senderNonce [5] OCTET STRING OPTIONAL,
|
||||
recipNonce [6] OCTET STRING OPTIONAL,
|
||||
freeText [7] PKIFreeText OPTIONAL,
|
||||
generalInfo [8] SEQUENCE SIZE (1..MAX) OF
|
||||
InfoTypeAndValue OPTIONAL
|
||||
}
|
||||
|
||||
"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('pvno', univ.Integer(
|
||||
namedValues=namedval.NamedValues(
|
||||
('cmp1999', 1),
|
||||
('cmp2000', 2)
|
||||
)
|
||||
)
|
||||
),
|
||||
namedtype.NamedType('sender', rfc2459.GeneralName()),
|
||||
namedtype.NamedType('recipient', rfc2459.GeneralName()),
|
||||
namedtype.OptionalNamedType('messageTime', useful.GeneralizedTime().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.OptionalNamedType('protectionAlg', rfc2459.AlgorithmIdentifier().subtype(
|
||||
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))),
|
||||
namedtype.OptionalNamedType('senderKID', rfc2459.KeyIdentifier().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
|
||||
namedtype.OptionalNamedType('recipKID', rfc2459.KeyIdentifier().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))),
|
||||
namedtype.OptionalNamedType('transactionID', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4))),
|
||||
namedtype.OptionalNamedType('senderNonce', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 5))),
|
||||
namedtype.OptionalNamedType('recipNonce', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 6))),
|
||||
namedtype.OptionalNamedType('freeText', PKIFreeText().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 7))),
|
||||
namedtype.OptionalNamedType('generalInfo',
|
||||
univ.SequenceOf(
|
||||
componentType=InfoTypeAndValue().subtype(
|
||||
subtypeSpec=constraint.ValueSizeConstraint(1, MAX),
|
||||
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 8)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
class ProtectedPart(univ.Sequence):
|
||||
"""
|
||||
ProtectedPart ::= SEQUENCE {
|
||||
header PKIHeader,
|
||||
body PKIBody
|
||||
}
|
||||
"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('header', PKIHeader()),
|
||||
namedtype.NamedType('infoValue', PKIBody())
|
||||
)
|
||||
|
||||
class PKIMessage(univ.Sequence):
|
||||
"""
|
||||
PKIMessage ::= SEQUENCE {
|
||||
header PKIHeader,
|
||||
body PKIBody,
|
||||
protection [0] PKIProtection OPTIONAL,
|
||||
extraCerts [1] SEQUENCE SIZE (1..MAX) OF CMPCertificate
|
||||
OPTIONAL
|
||||
}"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('header', PKIHeader()),
|
||||
namedtype.NamedType('body', PKIBody()),
|
||||
namedtype.OptionalNamedType('protection', PKIProtection().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
|
||||
namedtype.OptionalNamedType( 'extraCerts',
|
||||
univ.SequenceOf(
|
||||
componentType=CMPCertificate()
|
||||
).subtype(
|
||||
subtypeSpec=constraint.ValueSizeConstraint(1, MAX),
|
||||
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
class PKIMessages(univ.SequenceOf):
|
||||
"""
|
||||
PKIMessages ::= SEQUENCE SIZE (1..MAX) OF PKIMessage
|
||||
"""
|
||||
componentType = PKIMessage()
|
||||
subtypeSpec = univ.SequenceOf.subtypeSpec + constraint.ValueSizeConstraint(1, MAX)
|
||||
|
||||
# pyasn1 does not naturally handle recursive definitions, thus this hack:
|
||||
# NestedMessageContent ::= PKIMessages
|
||||
NestedMessageContent.componentType = PKIMessages()
|
||||
nestedMessageContent.componentType = PKIMessages()
|
||||
@@ -0,0 +1,39 @@
|
||||
#
|
||||
# PKCS#8 syntax
|
||||
#
|
||||
# ASN.1 source from:
|
||||
# http://tools.ietf.org/html/rfc5208
|
||||
#
|
||||
# Sample captures could be obtained with "openssl pkcs8 -topk8" command
|
||||
#
|
||||
from pyasn1.type import tag, namedtype, namedval, univ, constraint
|
||||
from pyasn1_modules.rfc2459 import *
|
||||
from pyasn1_modules import rfc2251
|
||||
|
||||
class KeyEncryptionAlgorithms(AlgorithmIdentifier): pass
|
||||
|
||||
class PrivateKeyAlgorithms(AlgorithmIdentifier): pass
|
||||
|
||||
class EncryptedData(univ.OctetString): pass
|
||||
|
||||
class EncryptedPrivateKeyInfo(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('encryptionAlgorithm', AlgorithmIdentifier()),
|
||||
namedtype.NamedType('encryptedData', EncryptedData())
|
||||
)
|
||||
|
||||
class PrivateKey(univ.OctetString): pass
|
||||
|
||||
class Attributes(univ.SetOf):
|
||||
componentType = rfc2251.Attribute()
|
||||
|
||||
class Version(univ.Integer):
|
||||
namedValues = namedval.NamedValues(('v1', 0), ('v2', 1))
|
||||
|
||||
class PrivateKeyInfo(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('version', Version()),
|
||||
namedtype.NamedType('privateKeyAlgorithm', AlgorithmIdentifier()),
|
||||
namedtype.NamedType('privateKey', PrivateKey()),
|
||||
namedtype.OptionalNamedType('attributes', Attributes().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
|
||||
)
|
||||
@@ -0,0 +1,5 @@
|
||||
[egg_info]
|
||||
tag_build =
|
||||
tag_date = 0
|
||||
tag_svn_revision = 0
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env python
|
||||
"""A collection of ASN.1-based protocols modules.
|
||||
|
||||
A collection of ASN.1 modules expressed in form of pyasn1 classes.
|
||||
Includes protocols PDUs definition (SNMP, LDAP etc.) and various
|
||||
data structures (X.509, PKCS etc.).
|
||||
"""
|
||||
|
||||
classifiers = """\
|
||||
Development Status :: 5 - Production/Stable
|
||||
Environment :: Console
|
||||
Intended Audience :: Developers
|
||||
Intended Audience :: Education
|
||||
Intended Audience :: Information Technology
|
||||
Intended Audience :: Science/Research
|
||||
Intended Audience :: System Administrators
|
||||
Intended Audience :: Telecommunications Industry
|
||||
License :: OSI Approved :: BSD License
|
||||
Natural Language :: English
|
||||
Operating System :: OS Independent
|
||||
Programming Language :: Python :: 2
|
||||
Programming Language :: Python :: 3
|
||||
Topic :: Communications
|
||||
Topic :: Security :: Cryptography
|
||||
Topic :: Software Development :: Libraries :: Python Modules
|
||||
"""
|
||||
|
||||
def howto_install_distribute():
|
||||
print("""
|
||||
Error: You need the distribute Python package!
|
||||
|
||||
It's very easy to install it, just type (as root on Linux):
|
||||
|
||||
wget http://python-distribute.org/distribute_setup.py
|
||||
python distribute_setup.py
|
||||
|
||||
Then you could make eggs from this package.
|
||||
""")
|
||||
|
||||
def howto_install_setuptools():
|
||||
print("""
|
||||
Error: You need setuptools Python package!
|
||||
|
||||
It's very easy to install it, just type (as root on Linux):
|
||||
|
||||
wget http://peak.telecommunity.com/dist/ez_setup.py
|
||||
python ez_setup.py
|
||||
|
||||
Then you could make eggs from this package.
|
||||
""")
|
||||
|
||||
try:
|
||||
from setuptools import setup
|
||||
params = {
|
||||
'install_requires': [ 'pyasn1>=0.1.4' ],
|
||||
'zip_safe': True
|
||||
}
|
||||
except ImportError:
|
||||
import sys
|
||||
for arg in sys.argv:
|
||||
if arg.find('egg') != -1:
|
||||
if sys.version_info[0] > 2:
|
||||
howto_install_distribute()
|
||||
else:
|
||||
howto_install_setuptools()
|
||||
sys.exit(1)
|
||||
from distutils.core import setup
|
||||
params = {}
|
||||
if sys.version_info[:2] > (2, 4):
|
||||
params['requires'] = [ 'pyasn1(>=0.1.4)' ]
|
||||
|
||||
doclines = [ x.strip() for x in __doc__.split('\n') if x ]
|
||||
|
||||
params.update( {
|
||||
'name': 'pyasn1-modules',
|
||||
'version': open('pyasn1_modules/__init__.py').read().split('\'')[1],
|
||||
'description': doclines[0],
|
||||
'long_description': ' '.join(doclines[1:]),
|
||||
'maintainer': 'Ilya Etingof <ilya@glas.net>',
|
||||
'author': 'Ilya Etingof',
|
||||
'author_email': 'ilya@glas.net',
|
||||
'url': 'http://sourceforge.net/projects/pyasn1/',
|
||||
'platforms': ['any'],
|
||||
'classifiers': [ x for x in classifiers.split('\n') if x ],
|
||||
'license': 'BSD',
|
||||
'packages': [ 'pyasn1_modules' ]
|
||||
} )
|
||||
|
||||
setup(**params)
|
||||
@@ -0,0 +1,93 @@
|
||||
#!/bin/sh
|
||||
|
||||
cmpdump.py <<EOT
|
||||
MIITuTCCARECAQKkWTBXMQswCQYDVQQGEwJUUjEQMA4GA1UEChMHRS1HdXZlbjEUMBIGA1UECxML
|
||||
VHJ1c3RDZW50ZXIxIDAeBgNVBAMTF1JTQSBTZWN1cml0eSBDTVAgU2VydmVypC0wKzELMAkGA1UE
|
||||
BhMCVFIxHDAaBgNVBAMME1ZhbGltby1WZXR0b3ItMTdEZWOgERgPMjAxMjA1MDMxMTE2MTdaoQ8w
|
||||
DQYJKoZIhvcNAQEFBQCiIgQgZWVhMjg5MGU2ZGY5N2IyNzk5NWY2MWE0MzE2MzI1OWGkEgQQQ01Q
|
||||
VjJUMTIyMzM0NjI3MKUSBBCAAAABgAAAAYAAAAGAAAABphIEEDEzNjY0NDMwMjlSYW5kb22jghIZ
|
||||
MIISFaGCC84wggvKMIIFwDCCBKigAwIBAgIQfOVE05R616R6Nqgu3drXHzANBgkqhkiG9w0BAQUF
|
||||
ADBxMQswCQYDVQQGEwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxpZ2kgQS5T
|
||||
LjE4MDYGA1UEAxMvZS1HdXZlbiBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2FnbGF5aWNp
|
||||
c2kwHhcNMDgxMTI0MTAwMzI0WhcNMTYxMjE0MTExNzI0WjBdMQswCQYDVQQGEwJUUjEoMCYGA1UE
|
||||
CgwfRWxla3Ryb25payBCaWxnaSBHdXZlbmxpZ2kgQS5TLjEkMCIGA1UEAwwbZS1HdXZlbiBNb2Jp
|
||||
bCBUZXN0VVRGLTgtU09OMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzqaymRo5chRK
|
||||
EKrhjWQky1HOm6b/Jy4tSUuo4vq3O9U3G2osOU/hHb6fyMmznLpc6CaZ3qKYiuDMFRW8g1kNjEjV
|
||||
sFSvH0Yd4qgwP1+qqzhBSe+nCAnEbRUrz+nXJ4fKhmGaQ+ZSic+MeyoqDsf/zENKqdV7ea9l3Ilu
|
||||
Rj93bmTxas9aWPWQ/U/fpwkwRXaqaONlM5e4GWdgA7T1aq106NvH1z6LDNXcMYw4lSZkj/UjmM/0
|
||||
NhVz+57Ib4a0bogTaBmm8a1E5NtzkcA7pgnZT8576T0UoiOpEo+NAELA1B0mRh1/82HK1/0xn1zt
|
||||
1ym4XZRtn2r2l/wTeEwU79ALVQIDAQABo4ICZjCCAmIwfAYIKwYBBQUHAQEEcDBuMDIGCCsGAQUF
|
||||
BzABhiZodHRwOi8vdGVzdG9jc3AyLmUtZ3V2ZW4uY29tL29jc3AueHVkYTA4BggrBgEFBQcwAoYs
|
||||
aHR0cDovL3d3dy5lLWd1dmVuLmNvbS9kb2N1bWVudHMvVGVzdEtvay5jcnQwDgYDVR0PAQH/BAQD
|
||||
AgEGMA8GA1UdEwEB/wQFMAMBAf8wggElBgNVHSAEggEcMIIBGDCCARQGCWCGGAMAAQECATCCAQUw
|
||||
NgYIKwYBBQUHAgEWKmh0dHA6Ly93d3cuZS1ndXZlbi5jb20vZG9jdW1lbnRzL05FU1VFLnBkZjCB
|
||||
ygYIKwYBBQUHAgIwgb0egboAQgB1ACAAcwBlAHIAdABpAGYAaQBrAGEAIABpAGwAZQAgAGkAbABn
|
||||
AGkAbABpACAAcwBlAHIAdABpAGYAaQBrAGEAIAB1AHkAZwB1AGwAYQBtAGEAIABlAHMAYQBzAGwA
|
||||
YQByATEAbgExACAAbwBrAHUAbQBhAGsAIABpAOcAaQBuACAAYgBlAGwAaQByAHQAaQBsAGUAbgAg
|
||||
AGQAbwBrAPwAbQBhAG4BMQAgAGEA5wExAG4BMQB6AC4wWAYDVR0fBFEwTzBNoEugSYZHaHR0cDov
|
||||
L3Rlc3RzaWwuZS1ndXZlbi5jb20vRWxla3Ryb25pa0JpbGdpR3V2ZW5saWdpQVNSb290L0xhdGVz
|
||||
dENSTC5jcmwwHQYDVR0OBBYEFLMoTImEKeXbqNjbYZkKshQi2vwzMB8GA1UdIwQYMBaAFGCI4dY9
|
||||
qCIkag0hwBgz5haCSNl0MA0GCSqGSIb3DQEBBQUAA4IBAQAWOsmvpoFB9sX2aq1/LjPDJ+A5Fpxm
|
||||
0XkOGM9yD/FsLfWgyv2HqBY1cVM7mjJfJ1ezkS0ODdlU6TyN5ouvAi21V9CIk69I3eUYSDjPpGia
|
||||
qcCCvJoMF0QD7B70kj2zW7IJ7pF11cbvPLaatdzojsH9fVfKtxtn/ZLrXtKsyUW5vKHOeniU6BBB
|
||||
Gl/ZZkFNXNN4mrB+B+wDV9OmdMw+Mc8KPq463hJQRat5a9lrXMdNtMAJOkvsUUzOemAsITjXWlyg
|
||||
BULijBhi8ZmMp0W7p6oKENX3vH2HCPCGQU29WIrK4iUoscjz93fB6oa4FQpxY0k3JRnWvD5FqkRD
|
||||
FKJdq/q9MIIDzzCCAregAwIBAgIQa34pJYdDFNXx90OkMkKzIjANBgkqhkiG9w0BAQUFADBxMQsw
|
||||
CQYDVQQGEwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxpZ2kgQS5TLjE4MDYG
|
||||
A1UEAxMvZS1HdXZlbiBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2FnbGF5aWNpc2kwHhcN
|
||||
MDYxMjE1MTUxMzU0WhcNMTYxMjE1MTExMzU0WjBxMQswCQYDVQQGEwJUUjEoMCYGA1UEChMfRWxl
|
||||
a3Ryb25payBCaWxnaSBHdXZlbmxpZ2kgQS5TLjE4MDYGA1UEAxMvZS1HdXZlbiBFbGVrdHJvbmlr
|
||||
IFNlcnRpZmlrYSBIaXptZXQgU2FnbGF5aWNpc2kwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||
AoIBAQCU/PTxSkcWPJMx4UO8L8ep9/JqRgAZ79EqYWgR4K2bNLgENpc5j0hO+QydgovFODzkEIBP
|
||||
RIBavMz9Cw2PONpSBmxd4K1A/5hGqoGEz8UCA2tIx4+Z2A9AQ2O3BYi9FWM+0D1brJDO+6yvX4m5
|
||||
Rf3mLlso52NIVV705fIkmOExHjdAj/xB0/LICZMfwKn8F19Jae/SQv9cFnptbNRCq8hU5zLRngpR
|
||||
eT1PYrZVV0XLbzbDPwgzLXCzDxG1atdGd5JRTnD58qM1foC3+hGafuyissMQVGnBQFlsx7V6OdlD
|
||||
bsxUXegCl2li0RpRJXLqyqMdtEplaznKp8NnbddylfrPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIB
|
||||
hjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFGCI4dY9qCIkag0hwBgz5haCSNl0MB0GA1Ud
|
||||
DgQWBBRgiOHWPagiJGoNIcAYM+YWgkjZdDANBgkqhkiG9w0BAQUFAAOCAQEAKftTVjgltZJxXwDs
|
||||
MumguOSlljOQjotVVpES1QYwo3a5RQVpKuS4KYDEdWLD4ITtDNOA/iGKYWCNyKsE1BCL66irknZw
|
||||
iR6p6P+q2Wf7fGYSwUBcSBwWBTA+0EgpvPL3/vRuVVCVgC8XHBr72jKKTg9Nwcj+1FwXGZTDpjX8
|
||||
dzPhTXEWceQcDn2FRdNt6BQad9Hdq08lMHiyozsWniYZYuWpud91i8Pl698H9t0KqiJg6rPKc9kd
|
||||
z9QyC8E/cLIJgYhvfzXMxvmSjeSSFSqTHioqfpU3k8AWXuxqJUxbdQ8QrVaTXRByzEr1Ze0TYpDs
|
||||
oel1PjC9ouO8bC7cGrbCWzCCAi8wggGYAhBlEjJUo9asY2ISG4oHjcpzMA0GCSqGSIb3DQEBBQUA
|
||||
MFoxCzAJBgNVBAYTAlRSMRAwDgYDVQQKEwdFLUd1dmVuMRQwEgYDVQQLEwtUcnVzdENlbnRlcjEj
|
||||
MCEGA1UEAxMaRS1HdXZlblRFU1RDQUhTTSBTeXN0ZW0gQ0EwHhcNMDkxMTMwMjIxMzEzWhcNMTYx
|
||||
MTMwMTkxMTUxWjBXMQswCQYDVQQGEwJUUjEQMA4GA1UEChMHRS1HdXZlbjEUMBIGA1UECxMLVHJ1
|
||||
c3RDZW50ZXIxIDAeBgNVBAMTF1JTQSBTZWN1cml0eSBDTVAgU2VydmVyMIGfMA0GCSqGSIb3DQEB
|
||||
AQUAA4GNADCBiQKBgQDCaZeJerGULW+1UPSu9T0voPNgzPcihXX6G5Q45nS4RNCe+pOc226EtD51
|
||||
wu6Eq2oARpZmCrKPn63EFmHEE04dRDr8MS2LHuZK8xslIx/AvPnV568795EPoAyhGIX9Na9ZHhnI
|
||||
zSPWmWfBd9bsQiLVF7C9dOvfW125mtywWXELewIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAAiIse/x
|
||||
aWwRWUM0CIzfnoXfrgyLdKVykK7dTPgoMJgAx229uN6VTPyk+E+lTKq9PhK+e/VJNNg9PjSFjKFd
|
||||
lfSDOi9ne1xOrb7cNTjw+sGf1mfNWyzizLXa7su7ISFN+GaClmAstH9vXsRxg1oh3pFMJv47I6iw
|
||||
gUQlwwg8WsY/MIIGPzCCBjsCAQAwAwIBADCCBi+gggYrMIIGJzCCBQ+gAwIBAgIRALGVtVAeoM1x
|
||||
gjgOX3alZ5MwDQYJKoZIhvcNAQEFBQAwXTELMAkGA1UEBhMCVFIxKDAmBgNVBAoMH0VsZWt0cm9u
|
||||
aWsgQmlsZ2kgR3V2ZW5saWdpIEEuUy4xJDAiBgNVBAMMG2UtR3V2ZW4gTW9iaWwgVGVzdFVURi04
|
||||
LVNPTjAeFw0xMjA1MDMxMTE2MTdaFw0xMzA1MDMxMTE2MTdaMGoxCzAJBgNVBAYTAlRSMREwDwYD
|
||||
VQQKDAhGaXJlIExMVDEbMBkGA1UECwwScG9wQ29kZSAtIDEyMzQ1Njc4MRQwEgYDVQQFEws3NjU0
|
||||
MzQ1Njc2NTEVMBMGA1UEAwwMQnVyYWsgWW9uZGVtMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
|
||||
gQCpfSB7xcsHZR4E27yGHkzUJx1y2iknzX4gRM2acyPljRw/V5Lm7POrfWIX9UF2sxfYfRqxYmD0
|
||||
+nw72nx8R/5AFQK0BfjHxIc5W1YekMHF8PSORo9rJqcX+qn+NBYwqcJl4EdObTcOtMWC6ws6n0uA
|
||||
oDvYYN0ujkua496sp+INiQIDAQABo4IDVzCCA1MwQgYIKwYBBQUHAQEENjA0MDIGCCsGAQUFBzAB
|
||||
hiZodHRwOi8vdGVzdG9jc3AyLmUtZ3V2ZW4uY29tL29jc3AueHVkYTAfBgNVHSMEGDAWgBSzKEyJ
|
||||
hCnl26jY22GZCrIUItr8MzCCAXIGA1UdIASCAWkwggFlMIGxBgZghhgDAAEwgaYwNgYIKwYBBQUH
|
||||
AgEWKmh0dHA6Ly93d3cuZS1ndXZlbi5jb20vZG9jdW1lbnRzL05FU1VFLnBkZjBsBggrBgEFBQcC
|
||||
AjBgGl5CdSBzZXJ0aWZpa2EsIDUwNzAgc2F5xLFsxLEgRWxla3Ryb25payDEsG16YSBLYW51bnVu
|
||||
YSBnw7ZyZSBuaXRlbGlrbGkgZWxla3Ryb25payBzZXJ0aWZpa2FkxLFyMIGuBglghhgDAAEBAQMw
|
||||
gaAwNwYIKwYBBQUHAgEWK2h0dHA6Ly93d3cuZS1ndXZlbi5jb20vZG9jdW1lbnRzL01LTkVTSS5w
|
||||
ZGYwZQYIKwYBBQUHAgIwWRpXQnUgc2VydGlmaWthLCBNS05FU0kga2Fwc2FtxLFuZGEgeWF5xLFu
|
||||
bGFubcSxxZ8gYmlyIG5pdGVsaWtsaSBlbGVrdHJvbmlrIHNlcnRpZmlrYWTEsXIuMA4GA1UdDwEB
|
||||
/wQEAwIGwDCBgwYIKwYBBQUHAQMEdzB1MAgGBgQAjkYBATBpBgtghhgBPQABp04BAQxaQnUgc2Vy
|
||||
dGlmaWthLCA1MDcwIHNheWlsaSBFbGVrdHJvbmlrIEltemEgS2FudW51bmEgZ8O2cmUgbml0ZWxp
|
||||
a2xpIGVsZWt0cm9uaWsgc2VydGlmaWthZGlyMEUGA1UdCQQ+MDwwFAYIKwYBBQUHCQIxCAQGQW5r
|
||||
YXJhMBIGCCsGAQUFBwkBMQYEBDE5NzkwEAYIKwYBBQUHCQQxBAQCVFIwGAYDVR0RBBEwD4ENZmly
|
||||
ZUBmaXJlLmNvbTBgBgNVHR8EWTBXMFWgU6BRhk9odHRwOi8vdGVzdHNpbC5lLWd1dmVuLmNvbS9F
|
||||
bGVrdHJvbmlrQmlsZ2lHdXZlbmxpZ2lBU01LTkVTSS1VVEYtOC9MYXRlc3RDUkwuY3JsMB0GA1Ud
|
||||
DgQWBBSLG9aIb1k2emFLCpM93kXJkWhzuTANBgkqhkiG9w0BAQUFAAOCAQEACoGCn4bzDWLzs799
|
||||
rndpB971UD2wbwt8Hkw1MGZkkJVQeVF4IS8FacAyYk5vY8ONuTA/Wsh4x23v9WTCtO89HMTz81eU
|
||||
BclqZ2Gc2UeMq7Y4FQWR8PNCMdCsxVVhpRRE6jQAyyR9YEBHQYVLfy34e3+9G/h/BR73VGHZJdZI
|
||||
DDJYd+VWXmUD9kGk/mI35qYdzN3O28KI8sokqX0z2hvkpDKuP4jNXSCHcVkK23tX2x5m6m0LdqVn
|
||||
vnCx2LfBn1wf1u7q30p/GgMVX+mR3QHs7feGewEjlkxuEyLVVD+uBwWCT6zcad17oaAyXV5RV28L
|
||||
vH0WNg6pFUpwOP0l+nIOqqCBhAOBgQBAtTB5Qd18sTxEKhSzRiN2OycFPrqoqlZZTHBohe8bE2D4
|
||||
Xc1ejkFWUEvQivkqJxCD6C7I37xgDaq8DZnaczIBxbPkY0QMdeL4MiEqlw/tlrJGrWoC5Twb0t/m
|
||||
JA5RSwQoMDYTj2WrwtM/nsP12T39or4JRZhlLSM43IaTwEBtQw==
|
||||
EOT
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
crldump.py <<EOT
|
||||
-----BEGIN X509 CRL-----
|
||||
MIIBVjCBwAIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJBVTETMBEGA1UE
|
||||
CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk
|
||||
MRUwEwYDVQQDEwxzbm1wbGFicy5jb20xIDAeBgkqhkiG9w0BCQEWEWluZm9Ac25t
|
||||
cGxhYnMuY29tFw0xMjA0MTExMzQwNTlaFw0xMjA1MTExMzQwNTlaoA4wDDAKBgNV
|
||||
HRQEAwIBATANBgkqhkiG9w0BAQUFAAOBgQC1D/wwnrcY/uFBHGc6SyoYss2kn+nY
|
||||
RTwzXmmldbNTCQ03x5vkWGGIaRJdN8QeCzbEi7gpgxgpxAx6Y5WkxkMQ1UPjNM5n
|
||||
DGVDOtR0dskFrrbHuNpWqWrDaBN0/ryZiWKjr9JRbrpkHgVY29I1gLooQ6IHuKHY
|
||||
vjnIhxTFoCb5vA==
|
||||
-----END X509 CRL-----
|
||||
EOT
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
crmfdump.py <<EOT
|
||||
MIIBozCCAZ8wggEFAgUAwTnj2jCByoABAqURMA8xDTALBgNVBAMTBHVzZXKmgZ8w
|
||||
DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJ6ZQ2cYbn/lFsmBOlRltbRbFQUvvE0Q
|
||||
nbopOu1kC7Bmaaz7QTx8nxeiHi4m7uxCbGGxHNoGCt7EmdG8eZUBNAcHyGlXrJdm
|
||||
0z3/uNEGiBHq+xB8FnFJCA5EIJ3RWFnlbu9otSITLxWK7c5+/NHmWM+yaeHD/f/h
|
||||
rp01c/8qXZfZAgMBAAGpEDAOBgNVHQ8BAf8EBAMCBeAwLzASBgkrBgEFBQcFAQEM
|
||||
BTExMTExMBkGCSsGAQUFBwUBAgwMc2VydmVyX21hZ2ljoYGTMA0GCSqGSIb3DQEB
|
||||
BQUAA4GBAEI3KNEvTq/n1kNVhNhPkovk1AZxyJrN1u1+7Gkc4PLjWwjLOjcEVWt4
|
||||
AajUk/gkIJ6bbeO+fZlMjHfPSDKcD6AV2hN+n72QZwfzcw3icNvBG1el9EU4XfIm
|
||||
xfu5YVWi81/fw8QQ6X6YGHFQkomLd7jxakVyjxSng9BhO6GpjJNF
|
||||
EOT
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
ocspreqdump.py <<EOT
|
||||
MGowaDBBMD8wPTAJBgUrDgMCGgUABBS3ZrMV9C5Dko03aH13cEZeppg3wgQUkqR1LKSevoFE63n8
|
||||
isWVpesQdXMCBDXe9M+iIzAhMB8GCSsGAQUFBzABAgQSBBBjdJOiIW9EKJGELNNf/rdA
|
||||
EOT
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
|
||||
ocsprspdump.py <<EOT
|
||||
MIIEvQoBAKCCBLYwggSyBgkrBgEFBQcwAQEEggSjMIIEnzCCAQ+hgYAwfjELMAkGA1UEBhMCQVUx
|
||||
EzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEV
|
||||
MBMGA1UEAxMMc25tcGxhYnMuY29tMSAwHgYJKoZIhvcNAQkBFhFpbmZvQHNubXBsYWJzLmNvbRgP
|
||||
MjAxMjA0MTExNDA5MjJaMFQwUjA9MAkGBSsOAwIaBQAEFLdmsxX0LkOSjTdofXdwRl6mmDfCBBSS
|
||||
pHUspJ6+gUTrefyKxZWl6xB1cwIENd70z4IAGA8yMDEyMDQxMTE0MDkyMlqhIzAhMB8GCSsGAQUF
|
||||
BzABAgQSBBBjdJOiIW9EKJGELNNf/rdAMA0GCSqGSIb3DQEBBQUAA4GBADk7oRiCy4ew1u0N52QL
|
||||
RFpW+tdb0NfkV2Xyu+HChKiTThZPr9ZXalIgkJ1w3BAnzhbB0JX/zq7Pf8yEz/OrQ4GGH7HyD3Vg
|
||||
PkMu+J6I3A2An+bUQo99AmCbZ5/tSHtDYQMQt3iNbv1fk0yvDmh7UdKuXUNSyJdHeg27dMNy4k8A
|
||||
oIIC9TCCAvEwggLtMIICVqADAgECAgEBMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAkFVMRMw
|
||||
EQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxFTAT
|
||||
BgNVBAMTDHNubXBsYWJzLmNvbTEgMB4GCSqGSIb3DQEJARYRaW5mb0Bzbm1wbGFicy5jb20wHhcN
|
||||
MTIwNDExMTMyNTM1WhcNMTMwNDExMTMyNTM1WjB+MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29t
|
||||
ZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRUwEwYDVQQDEwxzbm1w
|
||||
bGFicy5jb20xIDAeBgkqhkiG9w0BCQEWEWluZm9Ac25tcGxhYnMuY29tMIGfMA0GCSqGSIb3DQEB
|
||||
AQUAA4GNADCBiQKBgQDDDU5HOnNV8I2CojxB8ilIWRHYQuaAjnjrETMOprouDHFXnwWqQo/I3m0b
|
||||
XYmocrh9kDefb+cgc7+eJKvAvBqrqXRnU38DmQU/zhypCftGGfP8xjuBZ1n23lR3hplN1yYA0J2X
|
||||
SgBaAg6e8OsKf1vcX8Es09rDo8mQpt4G2zR56wIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG
|
||||
+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQU8Ys2dpJFLMHl
|
||||
yY57D4BNmlqnEcYwHwYDVR0jBBgwFoAU8Ys2dpJFLMHlyY57D4BNmlqnEcYwDQYJKoZIhvcNAQEF
|
||||
BQADgYEAWR0uFJVlQId6hVpUbgXFTpywtNitNXFiYYkRRv77McSJqLCa/c1wnuLmqcFcuRUK0oN6
|
||||
8ZJDP2HDDKe8MCZ8+sx+CF54eM8VCgN9uQ9XyE7x9XrXDd3Uw9RJVaWSIezkNKNeBE0lDM2jUjC4
|
||||
HAESdf7nebz1wtqAOXE1jWF/y8g=
|
||||
EOT
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
|
||||
pkcs1dump.py <<EOT
|
||||
-----BEGIN DSA PRIVATE KEY-----
|
||||
MIIBugIBAAKBgQCN91+Cma8UPw09gjwP9WOJCdpv3mv3/qFqzgiODGZx0Q002iTl
|
||||
1dq36m5TsWYFEcMCEyC3tFuoQ0mGq5zUUOmJvHCIPufs0g8Av0fhY77uFqneHHUi
|
||||
VQMCPCHX9vTCWskmDE21LJppU27bR4H2q+ysE30d6u3+84qrItsn4bjpcQIVAPR5
|
||||
QrmooOXDn7fHJzshmxImGC4VAoGAXxKyEnlvzq93d4V6KLWX3H5Jk2JP771Ss1bT
|
||||
6D/mSbLlvjjo7qsj6diul1axu6Wny31oPertzA2FeGEzkqvjSNmSxyYYMDB3kEcx
|
||||
ahntt37I1FgSlgdZHuhdtl1h1DBKXqCCneOZuNj+kW5ib14u5HDfFIbec2HJbvVs
|
||||
lJ/k83kCgYB4TD8vgHetXHxqsiZDoy5wOnQ3mmFAfl8ZdQsIfov6kEgArwPYUOVB
|
||||
JsX84f+MFjIOKXUV8dHZ8VRrGCLAbXcxKqLNWKlKHUnEsvt63pkaTy/RKHyQS+pn
|
||||
wontdTt9EtbF+CqIWnm2wpn3O+SbdtawzPOL1CcGB0jYABwbeQ81RwIUFKdyRYaa
|
||||
INow2I3/ks+0MxDabTY=
|
||||
-----END DSA PRIVATE KEY-----
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIBPAIBAAJBAMfAjvBNDDYBCl1w3yNcagZkPhqd0q5KqeOTgKSLuJWfe5+VSeR5
|
||||
Y1PcF3DyH8dvS3t8PIQjxJLoKS7HVRlsfhECAwEAAQJBAIr93/gxhIenXbD7MykF
|
||||
yvi7k8MtgkWoymICZwcX+c6RudFyuPPfQJ/sf6RmFZlRA9X9CQm5NwVG7+x1Yi6t
|
||||
KoECIQDmJUCWkPCiQYow6YxetpXFa0K6hTzOPmax7MNHVWNgmQIhAN4xOZ4JFT34
|
||||
xVhK+8EudBCYRomJUHmOJfoQAxiIXVw5AiEAyB7ecc5on/5zhqKef4Eu7LKfHIdc
|
||||
304diFuDVpTmTAkCIC2ZmKOQZaWkSowGR4isCfHl7oQHhFaOD8k0RA5i3hYxAiEA
|
||||
n8lDw3JT6NjvMnD6aM8KBsLyhazWSVVkaUSqmJzgCF0=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
EOT
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
|
||||
pkcs10dump.py <<EOT
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIDATCCAekCAQAwgZkxCzAJBgNVBAYTAlJVMRYwFAYDVQQIEw1Nb3Njb3cgUmVn
|
||||
aW9uMQ8wDQYDVQQHEwZNb3Njb3cxGjAYBgNVBAoTEVNOTVAgTGFib3JhdG9yaWVz
|
||||
MQwwCgYDVQQLFANSJkQxFTATBgNVBAMTDHNubXBsYWJzLmNvbTEgMB4GCSqGSIb3
|
||||
DQEJARYRaW5mb0Bzbm1wbGFicy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
|
||||
ggEKAoIBAQC9n2NfGS98JDBmAXQn+vNUyPB3QPYC1cwpX8UMYh9MdAmBZJCnvXrQ
|
||||
Pp14gNAv6AQKxefmGES1b+Yd+1we9HB8AKm1/8xvRDUjAvy4iO0sqFCPvIfSujUy
|
||||
pBcfnR7QE2itvyrMxCDSEVnMhKdCNb23L2TptUmpvLcb8wfAMLFsSu2yaOtJysep
|
||||
oH/mvGqlRv2ti2+E2YA0M7Pf83wyV1XmuEsc9tQ225rprDk2uyshUglkDD2235rf
|
||||
0QyONq3Aw3BMrO9ss1qj7vdDhVHVsxHnTVbEgrxEWkq2GkVKh9QReMZ2AKxe40j4
|
||||
og+OjKXguOCggCZHJyXKxccwqCaeCztbAgMBAAGgIjAgBgkqhkiG9w0BCQIxExMR
|
||||
U05NUCBMYWJvcmF0b3JpZXMwDQYJKoZIhvcNAQEFBQADggEBAAihbwmN9M2bsNNm
|
||||
9KfxqiGMqqcGCtzIlpDz/2NVwY93cEZsbz3Qscc0QpknRmyTSoDwIG+1nUH0vzkT
|
||||
Nv8sBmp9I1GdhGg52DIaWwL4t9O5WUHgfHSJpPxZ/zMP2qIsdPJ+8o19BbXRlufc
|
||||
73c03H1piGeb9VcePIaulSHI622xukI6f4Sis49vkDaoi+jadbEEb6TYkJQ3AMRD
|
||||
WdApGGm0BePdLqboW1Yv70WRRFFD8sxeT7Yw4qrJojdnq0xMHPGfKpf6dJsqWkHk
|
||||
b5DRbjil1Zt9pJuF680S9wtBzSi0hsMHXR9TzS7HpMjykL2nmCVY6A78MZapsCzn
|
||||
GGbx7DI=
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
EOT
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
#!/bin/sh
|
||||
|
||||
pkcs7dump.py <<EOT
|
||||
-----BEGIN PKCS7-----
|
||||
MIIKdQYJKoZIhvcNAQcCoIIKZjCCCmICAQExADALBgkqhkiG9w0BBwGgggpIMIIC
|
||||
XjCCAcegAwIBAgIBADANBgkqhkiG9w0BAQQFADB1MQswCQYDVQQGEwJSVTEPMA0G
|
||||
A1UEBxMGTW9zY293MRcwFQYDVQQKEw5Tb3ZhbSBUZWxlcG9ydDEMMAoGA1UECxMD
|
||||
TklTMQ8wDQYDVQQDEwZBQlMgQ0ExHTAbBgkqhkiG9w0BCQEWDmNlcnRAb25saW5l
|
||||
LnJ1MB4XDTk5MDgxNTE5MDI1OFoXDTAwMDExMjE5MDI1OFowdTELMAkGA1UEBhMC
|
||||
UlUxDzANBgNVBAcTBk1vc2NvdzEXMBUGA1UEChMOU292YW0gVGVsZXBvcnQxDDAK
|
||||
BgNVBAsTA05JUzEPMA0GA1UEAxMGQUJTIENBMR0wGwYJKoZIhvcNAQkBFg5jZXJ0
|
||||
QG9ubGluZS5ydTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAw0g1P0yQAZIi
|
||||
ml2XOCOxnCcuhHmAgj4Ei9M2ebrrGwUMONPzr1a8W7JcpnR3FeOjxEIxrzkHr6UA
|
||||
oj4l/oC7Rv28uIig+Okf+82ekhH6VgAQNr5LAzfN8J6dZLx2OXAmmLleAqHuisT7
|
||||
I40vEFRoRmC5hiMlILE2rIlIKJn6cUkCAwEAATANBgkqhkiG9w0BAQQFAAOBgQBZ
|
||||
7ELDfGUNb+fbpHl5W3d9JMXsdOgd96+HG+X1SPgeiRAMjkla8WFCSaQPIR4vCy0m
|
||||
tm5a2bWSji6+vP5FGbjOz5iMlHMrCtu0He7Eim2zpaGI06ZIY75Cn1h2r3+KS0/R
|
||||
h01TJUbmsfV1tZm6Wk3bayJ+/K8A4mBHv8P6rhYacDCCAowwggH1oAMCAQICAQAw
|
||||
DQYJKoZIhvcNAQEEBQAwgYsxCzAJBgNVBAYTAlJVMQ8wDQYDVQQHEwZNb3Njb3cx
|
||||
FzAVBgNVBAoTDkdvbGRlbiBUZWxlY29tMQwwCgYDVQQLEwNST0wxHjAcBgNVBAMT
|
||||
FUdvbGRlbiBUZWxlY29tIEFCUyBDQTEkMCIGCSqGSIb3DQEJARYVY2VydEBnb2xk
|
||||
ZW50ZWxlY29tLnJ1MB4XDTAwMDEwNTE1MDY1MVoXDTEwMDExNTE1MDY1MVowgYsx
|
||||
CzAJBgNVBAYTAlJVMQ8wDQYDVQQHEwZNb3Njb3cxFzAVBgNVBAoTDkdvbGRlbiBU
|
||||
ZWxlY29tMQwwCgYDVQQLEwNST0wxHjAcBgNVBAMTFUdvbGRlbiBUZWxlY29tIEFC
|
||||
UyBDQTEkMCIGCSqGSIb3DQEJARYVY2VydEBnb2xkZW50ZWxlY29tLnJ1MIGfMA0G
|
||||
CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPFel/Svli6ogoUEb6eLtEvNSjyalETSMP
|
||||
MIZXdmWIkWijvEUhDnNJVAE3knAt6dVYqxWq0vc6CbAGFZNqEyioGU48IECLzV0G
|
||||
toiYejF/c9PuyIKDejeV9/YZnNFaZAUOXhOjREdZURLISKhX4tAbQyvK0Qka9AAR
|
||||
MEy9DoqV8QIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAHQzgqFkoSMQr077UCr5C0l1
|
||||
rxLA17TrocCmUC1/PLmN0LmUHD0d7TjjTQKJaJBHxcKIg6+FOY6LSSY4nAN79eXi
|
||||
nBz+jEUG7+NTU/jcEArI35yP7fi4Mwb96EYDmUkUGtcLNq3JBe/d1Zhmy9HnNBL1
|
||||
Dn9thM2Q8RPYAJIU3JnGMIICqTCCAhICAQAwDQYJKoZIhvcNAQEEBQAwgZwxCzAJ
|
||||
BgNVBAYTAlJVMQ8wDQYDVQQIEwZNb3Njb3cxDzANBgNVBAcTBk1vc2NvdzEXMBUG
|
||||
A1UEChMOR29sZGVuIFRlbGVjb20xDDAKBgNVBAsTA1JPTDEeMBwGA1UEAxMVR29s
|
||||
ZGVuIFRlbGVjb20gQUJTIENBMSQwIgYJKoZIhvcNAQkBFhVjZXJ0QGdvbGRlbnRl
|
||||
bGVjb20ucnUwHhcNMTAwMTE1MTU0MDI2WhcNMjAwMjIyMTU0MDI2WjCBnDELMAkG
|
||||
A1UEBhMCUlUxDzANBgNVBAgTBk1vc2NvdzEPMA0GA1UEBxMGTW9zY293MRcwFQYD
|
||||
VQQKEw5Hb2xkZW4gVGVsZWNvbTEMMAoGA1UECxMDUk9MMR4wHAYDVQQDExVHb2xk
|
||||
ZW4gVGVsZWNvbSBBQlMgQ0ExJDAiBgkqhkiG9w0BCQEWFWNlcnRAZ29sZGVudGVs
|
||||
ZWNvbS5ydTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAzxXpf0r5YuqIKFBG
|
||||
+ni7RLzUo8mpRE0jDzCGV3ZliJFoo7xFIQ5zSVQBN5JwLenVWKsVqtL3OgmwBhWT
|
||||
ahMoqBlOPCBAi81dBraImHoxf3PT7siCg3o3lff2GZzRWmQFDl4To0RHWVESyEio
|
||||
V+LQG0MrytEJGvQAETBMvQ6KlfECAwEAATANBgkqhkiG9w0BAQQFAAOBgQCMrS4T
|
||||
LIzxcpu8nwOq/xMcxW4Ctz/wjIoePWkmSLe+Tkb4zo7aTsvzn+ETaWb7qztUpyl0
|
||||
QvlXn4vC2iCJloPpofPqSzF1UV3g5Zb93ReZu7E6kEyW0ag8R5XZKv0xuR3b3Le+
|
||||
ZqolT8wQELd5Mmw5JPofZ+O2cGNvet8tYwOKFjCCAqUwggIOoAMCAQICAgboMA0G
|
||||
CSqGSIb3DQEBBAUAMIGcMQswCQYDVQQGEwJSVTEPMA0GA1UECBMGTW9zY293MQ8w
|
||||
DQYDVQQHEwZNb3Njb3cxFzAVBgNVBAoTDkdvbGRlbiBUZWxlY29tMQwwCgYDVQQL
|
||||
EwNST0wxHjAcBgNVBAMTFUdvbGRlbiBUZWxlY29tIEFCUyBDQTEkMCIGCSqGSIb3
|
||||
DQEJARYVY2VydEBnb2xkZW50ZWxlY29tLnJ1MB4XDTExMDEyODEyMTcwOVoXDTEy
|
||||
MDIwMTAwMDAwMFowdjELMAkGA1UEBhMCUlUxDDAKBgNVBAgTA04vQTEXMBUGA1UE
|
||||
ChMOR29sZGVuIFRlbGVjb20xDDAKBgNVBAsTA0lTUDEWMBQGA1UEAxMNY3JheS5n
|
||||
bGFzLm5ldDEaMBgGCSqGSIb3DQEJARYLZWxpZUByb2wucnUwgZ8wDQYJKoZIhvcN
|
||||
AQEBBQADgY0AMIGJAoGBAPJAm8KG3ZCoJSvoGmLMPlGaMIpadu/EGSEYu+M/ybLp
|
||||
Cs8XmwB3876JVKKCbtGI6eqxOqvjedYXb+nKcyhz4Ztmm8RgAD7Z1WUItIpatejT
|
||||
79EYOUWrDN713SLZsImMyP4B4EySl4LZfHFRU2iOwLB6WozGCYuULLqYS9MDPrnT
|
||||
AgMBAAGjGzAZMBcGCWCGSAGG+EIBDQQKFghDPS07Uz0tOzANBgkqhkiG9w0BAQQF
|
||||
AAOBgQDEttS70qYCA+MGBA3hOR88XiBcTmuBarJDwn/rj31vRjYZUgp9bbFwscRI
|
||||
Ic4lDnlyvunwNitl+341bDg7u6Ebu9hCMbciyu4EtrsDh77DlLzbmNcXbnhlvbFL
|
||||
K9GiPz3dNyvQMfmaA0twd62zJDOVJ1SmO04lLmu/pAx8GhBZkqEAMQA=
|
||||
-----END PKCS7-----
|
||||
EOT
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
|
||||
pkcs8dump.py <<EOT
|
||||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIIBgTAbBgkqhkiG9w0BBQMwDgQIdtFgDWnipT8CAggABIIBYN0hkm2xqkTCt8dJ
|
||||
iZS8+HNiyHxy8g+rmWSXv/i+bTHFUReZA2GINtTRUkWpXqWcSHxNslgf7QdfgbVJ
|
||||
xQiUM+lLhwOFh85iAHR3xmPU1wfN9NvY9DiLSpM0DMhF3OvAMZD75zIhA0GSKu7w
|
||||
dUu7ey7H4fv7bez6RhEyLdKw9/Lf2KNStNOs4ow9CAtCoxeoMSniTt6CNhbvCkve
|
||||
9vNHKiGavX1tS/YTog4wiiGzh2YxuW1RiQpTdhWiKyECgD8qQVg2tY5t3QRcXrzi
|
||||
OkStpkiAPAbiwS/gyHpsqiLo0al63SCxRefugbn1ucZyc5Ya59e3xNFQXCNhYl+Z
|
||||
Hl3hIl3cssdWZkJ455Z/bBE29ks1HtsL+bTfFi+kw/4yuMzoaB8C7rXScpGNI/8E
|
||||
pvTU2+wtuoOFcttJregtR94ZHu5wgdYqRydmFNG8PnvZT1mRMmQgUe/vp88FMmsZ
|
||||
dLsZjNQ=
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEAx8CO8E0MNgEKXXDf
|
||||
I1xqBmQ+Gp3Srkqp45OApIu4lZ97n5VJ5HljU9wXcPIfx29Le3w8hCPEkugpLsdV
|
||||
GWx+EQIDAQABAkEAiv3f+DGEh6ddsPszKQXK+LuTwy2CRajKYgJnBxf5zpG50XK4
|
||||
899An+x/pGYVmVED1f0JCbk3BUbv7HViLq0qgQIhAOYlQJaQ8KJBijDpjF62lcVr
|
||||
QrqFPM4+ZrHsw0dVY2CZAiEA3jE5ngkVPfjFWEr7wS50EJhGiYlQeY4l+hADGIhd
|
||||
XDkCIQDIHt5xzmif/nOGop5/gS7ssp8ch1zfTh2IW4NWlOZMCQIgLZmYo5BlpaRK
|
||||
jAZHiKwJ8eXuhAeEVo4PyTREDmLeFjECIQCfyUPDclPo2O8ycPpozwoGwvKFrNZJ
|
||||
VWRpRKqYnOAIXQ==
|
||||
-----END PRIVATE KEY-----
|
||||
EOT
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#!/bin/sh
|
||||
|
||||
x509dump.py <<EOT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
|
||||
IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
|
||||
BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
|
||||
aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
|
||||
9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYy
|
||||
NjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
|
||||
azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
|
||||
YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
|
||||
Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
|
||||
cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfD
|
||||
cnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs
|
||||
2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqY
|
||||
JJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliE
|
||||
Zwgs3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJ
|
||||
n0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A
|
||||
PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu
|
||||
-----END CERTIFICATE-----
|
||||
EOT
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/python
|
||||
# Read ASN.1/PEM CMP message on stdin, parse into
|
||||
# plain text, then build substrate from it
|
||||
from pyasn1.codec.der import decoder, encoder
|
||||
from pyasn1_modules import rfc4210, pem
|
||||
from pyasn1 import debug
|
||||
import sys
|
||||
|
||||
if len(sys.argv) == 2 and sys.argv[1] == '-d':
|
||||
debug.setLogger(debug.Debug('all'))
|
||||
elif len(sys.argv) != 1:
|
||||
print("""Usage:
|
||||
$ cat cmp.pem | %s [-d]""" % sys.argv[0])
|
||||
sys.exit(-1)
|
||||
|
||||
pkiMessage = rfc4210.PKIMessage()
|
||||
|
||||
substrate = pem.readBase64FromFile(sys.stdin)
|
||||
if not substrate:
|
||||
sys.exit(0)
|
||||
|
||||
pkiMsg, rest = decoder.decode(substrate, asn1Spec=pkiMessage)
|
||||
|
||||
print(pkiMsg.prettyPrint())
|
||||
|
||||
assert encoder.encode(pkiMsg, defMode=False) == substrate or \
|
||||
encoder.encode(pkiMsg, defMode=True) == substrate, \
|
||||
'CMP message recode fails'
|
||||
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Read X.509 CRL on stdin, print them pretty and encode back into
|
||||
# original wire format.
|
||||
# CRL can be generated with "openssl openssl ca -gencrl ..." commands.
|
||||
#
|
||||
from pyasn1_modules import rfc2459, pem
|
||||
from pyasn1.codec.der import encoder, decoder
|
||||
import sys
|
||||
|
||||
if len(sys.argv) != 1:
|
||||
print("""Usage:
|
||||
$ cat crl.pem | %s""" % sys.argv[0])
|
||||
sys.exit(-1)
|
||||
|
||||
asn1Spec = rfc2459.CertificateList()
|
||||
|
||||
cnt = 0
|
||||
|
||||
while 1:
|
||||
idx, substrate = pem.readPemBlocksFromFile(sys.stdin, ('-----BEGIN X509 CRL-----', '-----END X509 CRL-----'))
|
||||
if not substrate:
|
||||
break
|
||||
|
||||
|
||||
key, rest = decoder.decode(substrate, asn1Spec=asn1Spec)
|
||||
|
||||
if rest: substrate = substrate[:-len(rest)]
|
||||
|
||||
print(key.prettyPrint())
|
||||
|
||||
assert encoder.encode(key, defMode=False) == substrate or \
|
||||
encoder.encode(key, defMode=True) == substrate, \
|
||||
'pkcs8 recode fails'
|
||||
|
||||
cnt = cnt + 1
|
||||
|
||||
print('*** %s CRL(s) re/serialized' % cnt)
|
||||
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/python
|
||||
# Read ASN.1/PEM X.509 CRMF request on stdin, parse into
|
||||
# plain text, then build substrate from it
|
||||
from pyasn1.codec.der import decoder, encoder
|
||||
from pyasn1_modules import rfc2511, pem
|
||||
import sys
|
||||
|
||||
if len(sys.argv) != 1:
|
||||
print("""Usage:
|
||||
$ cat crmf.pem | %s""" % sys.argv[0])
|
||||
sys.exit(-1)
|
||||
|
||||
certReq = rfc2511.CertReqMessages()
|
||||
|
||||
substrate = pem.readBase64FromFile(sys.stdin)
|
||||
if not substrate:
|
||||
sys.exit(0)
|
||||
|
||||
cr, rest = decoder.decode(substrate, asn1Spec=certReq)
|
||||
|
||||
print(cr.prettyPrint())
|
||||
|
||||
assert encoder.encode(cr, defMode=False) == substrate or \
|
||||
encoder.encode(cr, defMode=True) == substrate, \
|
||||
'crmf recode fails'
|
||||
@@ -0,0 +1,145 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
from pyasn1.codec.der import decoder, encoder
|
||||
from pyasn1_modules import rfc2560, rfc2459, pem
|
||||
from pyasn1.type import univ
|
||||
import sys, hashlib
|
||||
try:
|
||||
import urllib2
|
||||
except ImportError:
|
||||
import urllib.request as urllib2
|
||||
|
||||
sha1oid = univ.ObjectIdentifier((1, 3, 14, 3, 2, 26))
|
||||
|
||||
class ValueOnlyBitStringEncoder(encoder.encoder.BitStringEncoder):
|
||||
# These methods just do not encode tag and length fields of TLV
|
||||
def encodeTag(self, *args): return ''
|
||||
def encodeLength(self, *args): return ''
|
||||
def encodeValue(*args):
|
||||
substrate, isConstructed = encoder.encoder.BitStringEncoder.encodeValue(*args)
|
||||
# OCSP-specific hack follows: cut off the "unused bit count"
|
||||
# encoded bit-string value.
|
||||
return substrate[1:], isConstructed
|
||||
|
||||
def __call__(self, bitStringValue):
|
||||
return self.encode(None, bitStringValue, defMode=1, maxChunkSize=0)
|
||||
|
||||
valueOnlyBitStringEncoder = ValueOnlyBitStringEncoder()
|
||||
|
||||
def mkOcspRequest(issuerCert, userCert):
|
||||
issuerTbsCertificate = issuerCert.getComponentByName('tbsCertificate')
|
||||
issuerSubject = issuerTbsCertificate.getComponentByName('subject')
|
||||
|
||||
userTbsCertificate = userCert.getComponentByName('tbsCertificate')
|
||||
userIssuer = userTbsCertificate.getComponentByName('issuer')
|
||||
|
||||
assert issuerSubject == userIssuer, '%s\n%s' % (
|
||||
issuerSubject.prettyPrint(), userIssuer.prettyPrint()
|
||||
)
|
||||
|
||||
userIssuerHash = hashlib.sha1(
|
||||
encoder.encode(userIssuer)
|
||||
).digest()
|
||||
|
||||
issuerSubjectPublicKey = issuerTbsCertificate.getComponentByName('subjectPublicKeyInfo').getComponentByName('subjectPublicKey')
|
||||
|
||||
issuerKeyHash = hashlib.sha1(
|
||||
valueOnlyBitStringEncoder(issuerSubjectPublicKey)
|
||||
).digest()
|
||||
|
||||
userSerialNumber = userTbsCertificate.getComponentByName('serialNumber')
|
||||
|
||||
# Build request object
|
||||
|
||||
request = rfc2560.Request()
|
||||
|
||||
reqCert = request.setComponentByName('reqCert').getComponentByName('reqCert')
|
||||
|
||||
hashAlgorithm = reqCert.setComponentByName('hashAlgorithm').getComponentByName('hashAlgorithm')
|
||||
hashAlgorithm.setComponentByName('algorithm', sha1oid)
|
||||
|
||||
reqCert.setComponentByName('issuerNameHash', userIssuerHash)
|
||||
reqCert.setComponentByName('issuerKeyHash', issuerKeyHash)
|
||||
reqCert.setComponentByName('serialNumber', userSerialNumber)
|
||||
|
||||
ocspRequest = rfc2560.OCSPRequest()
|
||||
|
||||
tbsRequest = ocspRequest.setComponentByName('tbsRequest').getComponentByName('tbsRequest')
|
||||
tbsRequest.setComponentByName('version', 'v1')
|
||||
|
||||
requestList = tbsRequest.setComponentByName('requestList').getComponentByName('requestList')
|
||||
requestList.setComponentByPosition(0, request)
|
||||
|
||||
return ocspRequest
|
||||
|
||||
def parseOcspResponse(ocspResponse):
|
||||
responseStatus = ocspResponse.getComponentByName('responseStatus')
|
||||
assert responseStatus == rfc2560.OCSPResponseStatus('successful'), responseStatus.prettyPrint()
|
||||
responseBytes = ocspResponse.getComponentByName('responseBytes')
|
||||
responseType = responseBytes.getComponentByName('responseType')
|
||||
assert responseType == id_pkix_ocsp_basic, responseType.prettyPrint()
|
||||
|
||||
response = responseBytes.getComponentByName('response')
|
||||
|
||||
basicOCSPResponse, _ = decoder.decode(
|
||||
response, asn1Spec=rfc2560.BasicOCSPResponse()
|
||||
)
|
||||
|
||||
tbsResponseData = basicOCSPResponse.getComponentByName('tbsResponseData')
|
||||
|
||||
response0 = tbsResponseData.getComponentByName('responses').getComponentByPosition(0)
|
||||
|
||||
return (
|
||||
tbsResponseData.getComponentByName('producedAt'),
|
||||
response0.getComponentByName('certID'),
|
||||
response0.getComponentByName('certStatus').getName(),
|
||||
response0.getComponentByName('thisUpdate')
|
||||
)
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
print("""Usage:
|
||||
$ cat CACertificate.pem userCertificate.pem | %s <ocsp-responder-url>""" % sys.argv[0])
|
||||
sys.exit(-1)
|
||||
else:
|
||||
ocspUrl = sys.argv[1]
|
||||
|
||||
# Parse CA and user certificates
|
||||
|
||||
issuerCert, _ = decoder.decode(
|
||||
pem.readPemBlocksFromFile(
|
||||
sys.stdin, ('-----BEGIN CERTIFICATE-----', '-----END CERTIFICATE-----')
|
||||
)[1],
|
||||
asn1Spec=rfc2459.Certificate()
|
||||
)
|
||||
userCert, _ = decoder.decode(
|
||||
pem.readPemBlocksFromFile(
|
||||
sys.stdin, ('-----BEGIN CERTIFICATE-----', '-----END CERTIFICATE-----')
|
||||
)[1],
|
||||
asn1Spec=rfc2459.Certificate()
|
||||
)
|
||||
|
||||
# Build OCSP request
|
||||
|
||||
ocspReq = mkOcspRequest(issuerCert, userCert)
|
||||
|
||||
# Use HTTP POST to get response (see Appendix A of RFC 2560)
|
||||
# In case you need proxies, set the http_proxy env variable
|
||||
|
||||
httpReq = urllib2.Request(
|
||||
ocspUrl,
|
||||
encoder.encode(ocspReq),
|
||||
{ 'Content-Type': 'application/ocsp-request' }
|
||||
)
|
||||
httpRsp = urllib2.urlopen(httpReq).read()
|
||||
|
||||
# Process OCSP response
|
||||
|
||||
ocspRsp, _ = decoder.decode(httpRsp, asn1Spec=rfc2560.OCSPResponse())
|
||||
|
||||
producedAt, certId, certStatus, thisUpdate = parseOcspResponse(ocspRsp)
|
||||
|
||||
print('Certificate ID %s is %s at %s till %s\n' % (
|
||||
certId.getComponentByName('serialNumber'),
|
||||
certStatus,
|
||||
producedAt,
|
||||
thisUpdate))
|
||||
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Read ASN.1/PEM X.509 CRMF request on stdin, parse into
|
||||
# plain text, then build substrate from it
|
||||
#
|
||||
from pyasn1.codec.der import decoder, encoder
|
||||
from pyasn1_modules import rfc2560, pem
|
||||
import sys
|
||||
|
||||
if len(sys.argv) != 1:
|
||||
print("""Usage:
|
||||
$ cat ocsp-request.pem | %s""" % sys.argv[0])
|
||||
sys.exit(-1)
|
||||
|
||||
ocspReq = rfc2560.OCSPRequest()
|
||||
|
||||
substrate = pem.readBase64FromFile(sys.stdin)
|
||||
if not substrate:
|
||||
sys.exit(0)
|
||||
|
||||
cr, rest = decoder.decode(substrate, asn1Spec=ocspReq)
|
||||
|
||||
print(cr.prettyPrint())
|
||||
|
||||
assert encoder.encode(cr, defMode=False) == substrate or \
|
||||
encoder.encode(cr, defMode=True) == substrate, \
|
||||
'OCSP request recode fails'
|
||||
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Read ASN.1/PEM OCSP response on stdin, parse into
|
||||
# plain text, then build substrate from it
|
||||
#
|
||||
from pyasn1.codec.der import decoder, encoder
|
||||
from pyasn1_modules import rfc2560, pem
|
||||
import sys
|
||||
|
||||
if len(sys.argv) != 1:
|
||||
print("""Usage:
|
||||
$ cat ocsp-response.pem | %s""" % sys.argv[0])
|
||||
sys.exit(-1)
|
||||
|
||||
ocspReq = rfc2560.OCSPResponse()
|
||||
|
||||
substrate = pem.readBase64FromFile(sys.stdin)
|
||||
if not substrate:
|
||||
sys.exit(0)
|
||||
|
||||
cr, rest = decoder.decode(substrate, asn1Spec=ocspReq)
|
||||
|
||||
print(cr.prettyPrint())
|
||||
|
||||
assert encoder.encode(cr, defMode=False) == substrate or \
|
||||
encoder.encode(cr, defMode=True) == substrate, \
|
||||
'OCSP request recode fails'
|
||||
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
from pyasn1.codec.der import decoder, encoder
|
||||
from pyasn1_modules import rfc2560, rfc2459, pem
|
||||
from pyasn1.type import univ
|
||||
import sys, hashlib
|
||||
try:
|
||||
import urllib2
|
||||
except ImportError:
|
||||
import urllib.request as urllib2
|
||||
|
||||
sha1oid = univ.ObjectIdentifier((1, 3, 14, 3, 2, 26))
|
||||
|
||||
class ValueOnlyBitStringEncoder(encoder.encoder.BitStringEncoder):
|
||||
# These methods just do not encode tag and length fields of TLV
|
||||
def encodeTag(self, *args): return ''
|
||||
def encodeLength(self, *args): return ''
|
||||
def encodeValue(*args):
|
||||
substrate, isConstructed = encoder.encoder.BitStringEncoder.encodeValue(*args)
|
||||
# OCSP-specific hack follows: cut off the "unused bit count"
|
||||
# encoded bit-string value.
|
||||
return substrate[1:], isConstructed
|
||||
|
||||
def __call__(self, bitStringValue):
|
||||
return self.encode(None, bitStringValue, defMode=1, maxChunkSize=0)
|
||||
|
||||
valueOnlyBitStringEncoder = ValueOnlyBitStringEncoder()
|
||||
|
||||
def mkOcspRequest(issuerCert, userCert):
|
||||
issuerTbsCertificate = issuerCert.getComponentByName('tbsCertificate')
|
||||
issuerSubject = issuerTbsCertificate.getComponentByName('subject')
|
||||
|
||||
userTbsCertificate = userCert.getComponentByName('tbsCertificate')
|
||||
userIssuer = userTbsCertificate.getComponentByName('issuer')
|
||||
|
||||
assert issuerSubject == userIssuer, '%s\n%s' % (
|
||||
issuerSubject.prettyPrint(), userIssuer.prettyPrint()
|
||||
)
|
||||
|
||||
userIssuerHash = hashlib.sha1(
|
||||
encoder.encode(userIssuer)
|
||||
).digest()
|
||||
|
||||
issuerSubjectPublicKey = issuerTbsCertificate.getComponentByName('subjectPublicKeyInfo').getComponentByName('subjectPublicKey')
|
||||
|
||||
issuerKeyHash = hashlib.sha1(
|
||||
valueOnlyBitStringEncoder(issuerSubjectPublicKey)
|
||||
).digest()
|
||||
|
||||
userSerialNumber = userTbsCertificate.getComponentByName('serialNumber')
|
||||
|
||||
# Build request object
|
||||
|
||||
request = rfc2560.Request()
|
||||
|
||||
reqCert = request.setComponentByName('reqCert').getComponentByName('reqCert')
|
||||
|
||||
hashAlgorithm = reqCert.setComponentByName('hashAlgorithm').getComponentByName('hashAlgorithm')
|
||||
hashAlgorithm.setComponentByName('algorithm', sha1oid)
|
||||
|
||||
reqCert.setComponentByName('issuerNameHash', userIssuerHash)
|
||||
reqCert.setComponentByName('issuerKeyHash', issuerKeyHash)
|
||||
reqCert.setComponentByName('serialNumber', userSerialNumber)
|
||||
|
||||
ocspRequest = rfc2560.OCSPRequest()
|
||||
|
||||
tbsRequest = ocspRequest.setComponentByName('tbsRequest').getComponentByName('tbsRequest')
|
||||
tbsRequest.setComponentByName('version', 'v1')
|
||||
|
||||
requestList = tbsRequest.setComponentByName('requestList').getComponentByName('requestList')
|
||||
requestList.setComponentByPosition(0, request)
|
||||
|
||||
return ocspRequest
|
||||
|
||||
def parseOcspRequest(ocspRequest):
|
||||
tbsRequest = ocspRequest['responseStatus']
|
||||
|
||||
assert responseStatus == rfc2560.OCSPResponseStatus('successful'), responseStatus.prettyPrint()
|
||||
responseBytes = ocspResponse.getComponentByName('responseBytes')
|
||||
responseType = responseBytes.getComponentByName('responseType')
|
||||
assert responseType == id_pkix_ocsp_basic, responseType.prettyPrint()
|
||||
|
||||
response = responseBytes.getComponentByName('response')
|
||||
|
||||
basicOCSPResponse, _ = decoder.decode(
|
||||
response, asn1Spec=rfc2560.BasicOCSPResponse()
|
||||
)
|
||||
|
||||
tbsResponseData = basicOCSPResponse.getComponentByName('tbsResponseData')
|
||||
|
||||
response0 = tbsResponseData.getComponentByName('responses').getComponentByPosition(0)
|
||||
|
||||
return (
|
||||
tbsResponseData.getComponentByName('producedAt'),
|
||||
response0.getComponentByName('certID'),
|
||||
response0.getComponentByName('certStatus').getName(),
|
||||
response0.getComponentByName('thisUpdate')
|
||||
)
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
print("""Usage:
|
||||
$ cat CACertificate.pem userCertificate.pem | %s <ocsp-responder-url>""" % sys.argv[0])
|
||||
sys.exit(-1)
|
||||
else:
|
||||
ocspUrl = sys.argv[1]
|
||||
|
||||
# Parse CA and user certificates
|
||||
|
||||
issuerCert, _ = decoder.decode(
|
||||
pem.readPemFromFile(sys.stdin)[1],
|
||||
asn1Spec=rfc2459.Certificate()
|
||||
)
|
||||
userCert, _ = decoder.decode(
|
||||
pem.readPemFromFile(sys.stdin)[1],
|
||||
asn1Spec=rfc2459.Certificate()
|
||||
)
|
||||
|
||||
# Build OCSP request
|
||||
|
||||
ocspReq = mkOcspRequest(issuerCert, userCert)
|
||||
|
||||
# Use HTTP POST to get response (see Appendix A of RFC 2560)
|
||||
# In case you need proxies, set the http_proxy env variable
|
||||
|
||||
httpReq = urllib2.Request(
|
||||
ocspUrl,
|
||||
encoder.encode(ocspReq),
|
||||
{ 'Content-Type': 'application/ocsp-request' }
|
||||
)
|
||||
httpRsp = urllib2.urlopen(httpReq).read()
|
||||
|
||||
# Process OCSP response
|
||||
|
||||
ocspRsp, _ = decoder.decode(httpRsp, asn1Spec=rfc2560.OCSPResponse())
|
||||
|
||||
producedAt, certId, certStatus, thisUpdate = parseOcspResponse(ocspRsp)
|
||||
|
||||
print('Certificate ID %s is %s at %s till %s\n' % (
|
||||
certId.getComponentByName('serialNumber'),
|
||||
certStatus,
|
||||
producedAt,
|
||||
thisUpdate
|
||||
))
|
||||
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Read ASN.1/PEM X.509 certificate requests (PKCS#10 format) on stdin,
|
||||
# parse each into plain text, then build substrate from it
|
||||
#
|
||||
from pyasn1.codec.der import decoder, encoder
|
||||
from pyasn1_modules import rfc2314, pem
|
||||
import sys
|
||||
|
||||
if len(sys.argv) != 1:
|
||||
print("""Usage:
|
||||
$ cat certificateRequest.pem | %s""" % sys.argv[0])
|
||||
sys.exit(-1)
|
||||
|
||||
certType = rfc2314.CertificationRequest()
|
||||
|
||||
certCnt = 0
|
||||
|
||||
while 1:
|
||||
idx, substrate = pem.readPemBlocksFromFile(
|
||||
sys.stdin, ('-----BEGIN CERTIFICATE REQUEST-----',
|
||||
'-----END CERTIFICATE REQUEST-----')
|
||||
)
|
||||
if not substrate:
|
||||
break
|
||||
|
||||
cert, rest = decoder.decode(substrate, asn1Spec=certType)
|
||||
|
||||
if rest: substrate = substrate[:-len(rest)]
|
||||
|
||||
print(cert.prettyPrint())
|
||||
|
||||
assert encoder.encode(cert, defMode=False) == substrate or \
|
||||
encoder.encode(cert, defMode=True) == substrate, \
|
||||
'cert recode fails'
|
||||
|
||||
certCnt = certCnt + 1
|
||||
|
||||
print('*** %s PEM certificate request(s) de/serialized' % certCnt)
|
||||
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Read unencrypted PKCS#1/PKIX-compliant, PEM&DER encoded private keys on
|
||||
# stdin, print them pretty and encode back into original wire format.
|
||||
# Private keys can be generated with "openssl genrsa|gendsa" commands.
|
||||
#
|
||||
from pyasn1_modules import rfc2459, rfc2437, pem
|
||||
from pyasn1.codec.der import encoder, decoder
|
||||
import sys
|
||||
|
||||
if len(sys.argv) != 1:
|
||||
print("""Usage:
|
||||
$ cat rsakey.pem | %s""" % sys.argv[0])
|
||||
sys.exit(-1)
|
||||
|
||||
cnt = 0
|
||||
|
||||
while 1:
|
||||
idx, substrate = pem.readPemBlocksFromFile(sys.stdin, ('-----BEGIN RSA PRIVATE KEY-----', '-----END RSA PRIVATE KEY-----'), ('-----BEGIN DSA PRIVATE KEY-----', '-----END DSA PRIVATE KEY-----') )
|
||||
if not substrate:
|
||||
break
|
||||
|
||||
if idx == 0:
|
||||
asn1Spec = rfc2437.RSAPrivateKey()
|
||||
elif idx == 1:
|
||||
asn1Spec = rfc2459.DSAPrivateKey()
|
||||
else:
|
||||
break
|
||||
|
||||
key, rest = decoder.decode(substrate, asn1Spec=asn1Spec)
|
||||
|
||||
if rest: substrate = substrate[:-len(rest)]
|
||||
|
||||
print(key.prettyPrint())
|
||||
|
||||
assert encoder.encode(key, defMode=False) == substrate or \
|
||||
encoder.encode(key, defMode=True) == substrate, \
|
||||
'pkcs8 recode fails'
|
||||
|
||||
cnt = cnt + 1
|
||||
|
||||
print('*** %s key(s) re/serialized' % cnt)
|
||||
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Read ASN.1/PEM PKCS#7 on stdin, parse it into plain text,
|
||||
# then build substrate from it
|
||||
#
|
||||
from pyasn1_modules import rfc2315, pem
|
||||
from pyasn1.codec.der import encoder, decoder
|
||||
import sys
|
||||
|
||||
if len(sys.argv) != 1:
|
||||
print("""Usage:
|
||||
$ cat pkcs7Certificate.pem | %s""" % sys.argv[0])
|
||||
sys.exit(-1)
|
||||
|
||||
idx, substrate = pem.readPemBlocksFromFile(
|
||||
sys.stdin, ('-----BEGIN PKCS7-----', '-----END PKCS7-----')
|
||||
)
|
||||
|
||||
assert substrate, 'bad PKCS7 data on input'
|
||||
|
||||
contentInfo, rest = decoder.decode(substrate, asn1Spec=rfc2315.ContentInfo())
|
||||
|
||||
if rest: substrate = substrate[:-len(rest)]
|
||||
|
||||
print(contentInfo.prettyPrint())
|
||||
|
||||
assert encoder.encode(contentInfo, defMode=False) == substrate or \
|
||||
encoder.encode(contentInfo, defMode=True) == substrate, \
|
||||
're-encode fails'
|
||||
|
||||
contentType = contentInfo.getComponentByName('contentType')
|
||||
|
||||
contentInfoMap = {
|
||||
(1, 2, 840, 113549, 1, 7, 1): rfc2315.Data(),
|
||||
(1, 2, 840, 113549, 1, 7, 2): rfc2315.SignedData(),
|
||||
(1, 2, 840, 113549, 1, 7, 3): rfc2315.EnvelopedData(),
|
||||
(1, 2, 840, 113549, 1, 7, 4): rfc2315.SignedAndEnvelopedData(),
|
||||
(1, 2, 840, 113549, 1, 7, 5): rfc2315.DigestedData(),
|
||||
(1, 2, 840, 113549, 1, 7, 6): rfc2315.EncryptedData()
|
||||
}
|
||||
|
||||
content, _ = decoder.decode(
|
||||
contentInfo.getComponentByName('content'),
|
||||
asn1Spec=contentInfoMap[contentType]
|
||||
)
|
||||
|
||||
print(content.prettyPrint())
|
||||
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Read bunch of ASN.1/PEM plain/encrypted private keys in PKCS#8
|
||||
# format on stdin, parse each into plain text, then build substrate from it
|
||||
#
|
||||
from pyasn1.codec.der import decoder, encoder
|
||||
from pyasn1_modules import rfc5208, pem
|
||||
import sys
|
||||
|
||||
if len(sys.argv) != 1:
|
||||
print("""Usage:
|
||||
$ cat pkcs8key.pem | %s""" % sys.argv[0])
|
||||
sys.exit(-1)
|
||||
|
||||
cnt = 0
|
||||
|
||||
while 1:
|
||||
idx, substrate = pem.readPemBlocksFromFile(sys.stdin, ('-----BEGIN PRIVATE KEY-----', '-----END PRIVATE KEY-----'), ('-----BEGIN ENCRYPTED PRIVATE KEY-----', '-----END ENCRYPTED PRIVATE KEY-----') )
|
||||
if not substrate:
|
||||
break
|
||||
|
||||
if idx == 0:
|
||||
asn1Spec = rfc5208.PrivateKeyInfo()
|
||||
elif idx == 1:
|
||||
asn1Spec = rfc5208.EncryptedPrivateKeyInfo()
|
||||
else:
|
||||
break
|
||||
|
||||
key, rest = decoder.decode(substrate, asn1Spec=asn1Spec)
|
||||
|
||||
if rest: substrate = substrate[:-len(rest)]
|
||||
|
||||
print(key.prettyPrint())
|
||||
|
||||
assert encoder.encode(key, defMode=False) == substrate or \
|
||||
encoder.encode(key, defMode=True) == substrate, \
|
||||
'pkcs8 recode fails'
|
||||
|
||||
cnt = cnt + 1
|
||||
|
||||
print('*** %s PKCS#8 key(s) de/serialized' % cnt)
|
||||
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Generate SNMPGET request, parse response
|
||||
#
|
||||
from pyasn1.codec.ber import encoder, decoder
|
||||
from pyasn1_modules import rfc1157
|
||||
import sys, socket
|
||||
|
||||
if len(sys.argv) != 4:
|
||||
print("""Usage:
|
||||
$ %s <community> <host> <OID>""" % sys.argv[0])
|
||||
sys.exit(-1)
|
||||
|
||||
msg = rfc1157.Message()
|
||||
msg.setComponentByPosition(0)
|
||||
msg.setComponentByPosition(1, sys.argv[1])
|
||||
# pdu
|
||||
pdus = msg.setComponentByPosition(2).getComponentByPosition(2)
|
||||
pdu = pdus.setComponentByPosition(0).getComponentByPosition(0)
|
||||
pdu.setComponentByPosition(0, 123)
|
||||
pdu.setComponentByPosition(1, 0)
|
||||
pdu.setComponentByPosition(2, 0)
|
||||
vbl = pdu.setComponentByPosition(3).getComponentByPosition(3)
|
||||
vb = vbl.setComponentByPosition(0).getComponentByPosition(0)
|
||||
vb.setComponentByPosition(0, sys.argv[3])
|
||||
v = vb.setComponentByPosition(1).getComponentByPosition(1).setComponentByPosition(0).getComponentByPosition(0).setComponentByPosition(3).getComponentByPosition(3)
|
||||
|
||||
print('sending: %s' % msg.prettyPrint())
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.sendto(encoder.encode(msg), (sys.argv[2], 161))
|
||||
|
||||
substrate, _ = sock.recvfrom(2048)
|
||||
|
||||
rMsg, _ = decoder.decode(substrate, asn1Spec=msg)
|
||||
|
||||
print('received: %s' % rMsg.prettyPrint())
|
||||
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Read ASN.1/PEM X.509 certificates on stdin, parse each into plain text,
|
||||
# then build substrate from it
|
||||
#
|
||||
from pyasn1.codec.der import decoder, encoder
|
||||
from pyasn1_modules import rfc2459, pem
|
||||
import sys
|
||||
|
||||
if len(sys.argv) != 1:
|
||||
print("""Usage:
|
||||
$ cat CACertificate.pem | %s
|
||||
$ cat userCertificate.pem | %s""" % (sys.argv[0], sys.argv[0]))
|
||||
sys.exit(-1)
|
||||
|
||||
certType = rfc2459.Certificate()
|
||||
|
||||
certCnt = 0
|
||||
|
||||
while 1:
|
||||
idx, substrate = pem.readPemBlocksFromFile(
|
||||
sys.stdin, ('-----BEGIN CERTIFICATE-----',
|
||||
'-----END CERTIFICATE-----')
|
||||
)
|
||||
if not substrate:
|
||||
break
|
||||
|
||||
cert, rest = decoder.decode(substrate, asn1Spec=certType)
|
||||
|
||||
if rest: substrate = substrate[:-len(rest)]
|
||||
|
||||
print(cert.prettyPrint())
|
||||
|
||||
assert encoder.encode(cert, defMode=False) == substrate or \
|
||||
encoder.encode(cert, defMode=True) == substrate, \
|
||||
'cert recode fails'
|
||||
|
||||
certCnt = certCnt + 1
|
||||
|
||||
print('*** %s PEM cert(s) de/serialized' % certCnt)
|
||||
@@ -0,0 +1,13 @@
|
||||
Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,5 @@
|
||||
include README
|
||||
include LICENSE
|
||||
include *.py
|
||||
recursive-include rsa *.py
|
||||
recursive-include tests *.py
|
||||
@@ -0,0 +1,18 @@
|
||||
Metadata-Version: 1.1
|
||||
Name: rsa
|
||||
Version: 3.1.4
|
||||
Summary: Pure-Python RSA implementation
|
||||
Home-page: http://stuvel.eu/rsa
|
||||
Author: Sybren A. Stuvel
|
||||
Author-email: sybren@stuvel.eu
|
||||
License: ASL 2
|
||||
Description: UNKNOWN
|
||||
Platform: UNKNOWN
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Intended Audience :: Education
|
||||
Classifier: Intended Audience :: Information Technology
|
||||
Classifier: License :: OSI Approved :: Apache Software License
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Topic :: Security :: Cryptography
|
||||
@@ -0,0 +1,31 @@
|
||||
Pure Python RSA implementation
|
||||
==============================
|
||||
|
||||
`Python-RSA`_ is a pure-Python RSA implementation. It supports
|
||||
encryption and decryption, signing and verifying signatures, and key
|
||||
generation according to PKCS#1 version 1.5. It can be used as a Python
|
||||
library as well as on the commandline. The code was mostly written by
|
||||
Sybren A. Stüvel.
|
||||
|
||||
Documentation can be found at the Python-RSA homepage:
|
||||
http://stuvel.eu/rsa
|
||||
|
||||
Download and install using::
|
||||
|
||||
pip install rsa
|
||||
|
||||
or::
|
||||
|
||||
easy_install rsa
|
||||
|
||||
or download it from the `Python Package Index`_.
|
||||
|
||||
The source code is maintained in a `Mercurial repository`_ and is
|
||||
licensed under the `Apache License, version 2.0`_
|
||||
|
||||
|
||||
.. _`Python-RSA`: http://stuvel.eu/rsa
|
||||
.. _`Mercurial repository`: https://bitbucket.org/sybren/python-rsa
|
||||
.. _`Python Package Index`: http://pypi.python.org/pypi/rsa
|
||||
.. _`Apache License, version 2.0`: http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import time
|
||||
import rsa
|
||||
|
||||
poolsize = 8
|
||||
accurate = True
|
||||
|
||||
def run_speed_test(bitsize):
|
||||
|
||||
iterations = 0
|
||||
start = end = time.time()
|
||||
|
||||
# At least a number of iterations, and at least 2 seconds
|
||||
while iterations < 10 or end - start < 2:
|
||||
iterations += 1
|
||||
rsa.newkeys(bitsize, accurate=accurate, poolsize=poolsize)
|
||||
end = time.time()
|
||||
|
||||
duration = end - start
|
||||
dur_per_call = duration / iterations
|
||||
|
||||
print '%5i bit: %9.3f sec. (%i iterations over %.1f seconds)' % (bitsize,
|
||||
dur_per_call, iterations, duration)
|
||||
|
||||
for bitsize in (128, 256, 384, 512, 1024, 2048, 3072, 4096):
|
||||
run_speed_test(bitsize)
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import re
|
||||
import rsa
|
||||
|
||||
def _logon( username, password ):
|
||||
# Retrive the public key
|
||||
# network stuff # req = urllib2.Request(AAA_GET_KEY, headers={'User-Agent': CLIENT_ID})
|
||||
# network stuff # response = urllib2.urlopen(req)
|
||||
# network stuff # html = response.read()
|
||||
# network stuff # print response.info() # DEBUG
|
||||
# network stuff # print html # DEBUG
|
||||
|
||||
# replacement for network stuff #
|
||||
html="<x509PublicKey>30820122300d06092a864886f70d01010105000382010f003082010a0282010100dad8e3c084137bab285e869ae99a5de9752a095753680e9128adbe981e8141225704e558b8ee437836ec8c5460514efae61550bfdd883549981458bae388c9490b5ab43475068b169b32da446b0aae2dfbb3a5f425c74b284ced3f57ed33b30ec7b4b95a8216f8b063e34af2c84fef58bab381f3b79b80d06b687e0b5fc7aaeb311a88389ab7aa1422ae0b58956bb9e91c5cbf2b98422b05e1eacb82e29938566f6f05274294a8c596677c950ce97dcd003709d008f1ae6418ce5bf55ad2bf921318c6e31b324bdda4b4f12ff1fd86b5b71e647d1fc175aea137ba0ff869d5fbcf9ed0289fe7da3619c1204fc42d616462ac1b6a4e6ca2655d44bce039db519d0203010001</x509PublicKey>"
|
||||
# end replacement for network stuff #
|
||||
|
||||
# This shall pick the key
|
||||
hexstring = re.compile('<x509PublicKey[^>]*>([0-9a-fA-F]+)</x509PublicKey>')
|
||||
|
||||
# pick the key and convert it to der format
|
||||
hex_pub_der = hexstring.search(html).group(1)
|
||||
pub_der = hex_pub_der.decode('hex')
|
||||
|
||||
# Convert it to a public key
|
||||
pub_key = rsa.PublicKey.load_pkcs1_openssl_der(pub_der)
|
||||
|
||||
# encode the password
|
||||
enc_pass = rsa.encrypt(password, pub_key)
|
||||
|
||||
# and hex-encode it
|
||||
hex_pass = enc_pass.encode('hex')
|
||||
|
||||
# _logon('me', 'MyPass')
|
||||
|
||||
import timeit
|
||||
timeit.timeit('_logon( "me", "MyPass" )',
|
||||
setup='from __main__ import _logon',
|
||||
number=1000)
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
Metadata-Version: 1.1
|
||||
Name: rsa
|
||||
Version: 3.1.4
|
||||
Summary: Pure-Python RSA implementation
|
||||
Home-page: http://stuvel.eu/rsa
|
||||
Author: Sybren A. Stuvel
|
||||
Author-email: sybren@stuvel.eu
|
||||
License: ASL 2
|
||||
Description: UNKNOWN
|
||||
Platform: UNKNOWN
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Intended Audience :: Education
|
||||
Classifier: Intended Audience :: Information Technology
|
||||
Classifier: License :: OSI Approved :: Apache Software License
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Topic :: Security :: Cryptography
|
||||
@@ -0,0 +1,46 @@
|
||||
LICENSE
|
||||
MANIFEST.in
|
||||
README.rst
|
||||
create_timing_table.py
|
||||
playstuff.py
|
||||
run_tests.py
|
||||
setup.cfg
|
||||
setup.py
|
||||
rsa/__init__.py
|
||||
rsa/_compat.py
|
||||
rsa/_version133.py
|
||||
rsa/_version200.py
|
||||
rsa/asn1.py
|
||||
rsa/bigfile.py
|
||||
rsa/cli.py
|
||||
rsa/common.py
|
||||
rsa/core.py
|
||||
rsa/key.py
|
||||
rsa/parallel.py
|
||||
rsa/pem.py
|
||||
rsa/pkcs1.py
|
||||
rsa/prime.py
|
||||
rsa/randnum.py
|
||||
rsa/transform.py
|
||||
rsa/util.py
|
||||
rsa/varblock.py
|
||||
rsa.egg-info/PKG-INFO
|
||||
rsa.egg-info/SOURCES.txt
|
||||
rsa.egg-info/dependency_links.txt
|
||||
rsa.egg-info/entry_points.txt
|
||||
rsa.egg-info/requires.txt
|
||||
rsa.egg-info/top_level.txt
|
||||
tests/__init__.py
|
||||
tests/constants.py
|
||||
tests/py2kconstants.py
|
||||
tests/py3kconstants.py
|
||||
tests/test_bigfile.py
|
||||
tests/test_common.py
|
||||
tests/test_compat.py
|
||||
tests/test_integers.py
|
||||
tests/test_load_save_keys.py
|
||||
tests/test_pem.py
|
||||
tests/test_pkcs1.py
|
||||
tests/test_strings.py
|
||||
tests/test_transform.py
|
||||
tests/test_varblock.py
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
[console_scripts]
|
||||
pyrsa-encrypt = rsa.cli:encrypt
|
||||
pyrsa-keygen = rsa.cli:keygen
|
||||
pyrsa-priv2pub = rsa.util:private_to_public
|
||||
pyrsa-sign = rsa.cli:sign
|
||||
pyrsa-verify = rsa.cli:verify
|
||||
pyrsa-encrypt-bigfile = rsa.cli:encrypt_bigfile
|
||||
pyrsa-decrypt-bigfile = rsa.cli:decrypt_bigfile
|
||||
pyrsa-decrypt = rsa.cli:decrypt
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
pyasn1 >= 0.1.3
|
||||
@@ -0,0 +1 @@
|
||||
rsa
|
||||
@@ -0,0 +1,45 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""RSA module
|
||||
|
||||
Module for calculating large primes, and RSA encryption, decryption, signing
|
||||
and verification. Includes generating public and private keys.
|
||||
|
||||
WARNING: this implementation does not use random padding, compression of the
|
||||
cleartext input to prevent repetitions, or other common security improvements.
|
||||
Use with care.
|
||||
|
||||
If you want to have a more secure implementation, use the functions from the
|
||||
``rsa.pkcs1`` module.
|
||||
|
||||
"""
|
||||
|
||||
__author__ = "Sybren Stuvel, Barry Mead and Yesudeep Mangalapilly"
|
||||
__date__ = "2014-02-22"
|
||||
__version__ = '3.1.4'
|
||||
|
||||
from rsa.key import newkeys, PrivateKey, PublicKey
|
||||
from rsa.pkcs1 import encrypt, decrypt, sign, verify, DecryptionError, \
|
||||
VerificationError
|
||||
|
||||
# Do doctest if we're run directly
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
||||
__all__ = ["newkeys", "encrypt", "decrypt", "sign", "verify", 'PublicKey',
|
||||
'PrivateKey', 'DecryptionError', 'VerificationError']
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Python compatibility wrappers."""
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import sys
|
||||
from struct import pack
|
||||
|
||||
try:
|
||||
MAX_INT = sys.maxsize
|
||||
except AttributeError:
|
||||
MAX_INT = sys.maxint
|
||||
|
||||
MAX_INT64 = (1 << 63) - 1
|
||||
MAX_INT32 = (1 << 31) - 1
|
||||
MAX_INT16 = (1 << 15) - 1
|
||||
|
||||
# Determine the word size of the processor.
|
||||
if MAX_INT == MAX_INT64:
|
||||
# 64-bit processor.
|
||||
MACHINE_WORD_SIZE = 64
|
||||
elif MAX_INT == MAX_INT32:
|
||||
# 32-bit processor.
|
||||
MACHINE_WORD_SIZE = 32
|
||||
else:
|
||||
# Else we just assume 64-bit processor keeping up with modern times.
|
||||
MACHINE_WORD_SIZE = 64
|
||||
|
||||
|
||||
try:
|
||||
# < Python3
|
||||
unicode_type = unicode
|
||||
have_python3 = False
|
||||
except NameError:
|
||||
# Python3.
|
||||
unicode_type = str
|
||||
have_python3 = True
|
||||
|
||||
# Fake byte literals.
|
||||
if str is unicode_type:
|
||||
def byte_literal(s):
|
||||
return s.encode('latin1')
|
||||
else:
|
||||
def byte_literal(s):
|
||||
return s
|
||||
|
||||
# ``long`` is no more. Do type detection using this instead.
|
||||
try:
|
||||
integer_types = (int, long)
|
||||
except NameError:
|
||||
integer_types = (int,)
|
||||
|
||||
b = byte_literal
|
||||
|
||||
try:
|
||||
# Python 2.6 or higher.
|
||||
bytes_type = bytes
|
||||
except NameError:
|
||||
# Python 2.5
|
||||
bytes_type = str
|
||||
|
||||
|
||||
# To avoid calling b() multiple times in tight loops.
|
||||
ZERO_BYTE = b('\x00')
|
||||
EMPTY_BYTE = b('')
|
||||
|
||||
|
||||
def is_bytes(obj):
|
||||
"""
|
||||
Determines whether the given value is a byte string.
|
||||
|
||||
:param obj:
|
||||
The value to test.
|
||||
:returns:
|
||||
``True`` if ``value`` is a byte string; ``False`` otherwise.
|
||||
"""
|
||||
return isinstance(obj, bytes_type)
|
||||
|
||||
|
||||
def is_integer(obj):
|
||||
"""
|
||||
Determines whether the given value is an integer.
|
||||
|
||||
:param obj:
|
||||
The value to test.
|
||||
:returns:
|
||||
``True`` if ``value`` is an integer; ``False`` otherwise.
|
||||
"""
|
||||
return isinstance(obj, integer_types)
|
||||
|
||||
|
||||
def byte(num):
|
||||
"""
|
||||
Converts a number between 0 and 255 (both inclusive) to a base-256 (byte)
|
||||
representation.
|
||||
|
||||
Use it as a replacement for ``chr`` where you are expecting a byte
|
||||
because this will work on all current versions of Python::
|
||||
|
||||
:param num:
|
||||
An unsigned integer between 0 and 255 (both inclusive).
|
||||
:returns:
|
||||
A single byte.
|
||||
"""
|
||||
return pack("B", num)
|
||||
|
||||
|
||||
def get_word_alignment(num, force_arch=64,
|
||||
_machine_word_size=MACHINE_WORD_SIZE):
|
||||
"""
|
||||
Returns alignment details for the given number based on the platform
|
||||
Python is running on.
|
||||
|
||||
:param num:
|
||||
Unsigned integral number.
|
||||
:param force_arch:
|
||||
If you don't want to use 64-bit unsigned chunks, set this to
|
||||
anything other than 64. 32-bit chunks will be preferred then.
|
||||
Default 64 will be used when on a 64-bit machine.
|
||||
:param _machine_word_size:
|
||||
(Internal) The machine word size used for alignment.
|
||||
:returns:
|
||||
4-tuple::
|
||||
|
||||
(word_bits, word_bytes,
|
||||
max_uint, packing_format_type)
|
||||
"""
|
||||
max_uint64 = 0xffffffffffffffff
|
||||
max_uint32 = 0xffffffff
|
||||
max_uint16 = 0xffff
|
||||
max_uint8 = 0xff
|
||||
|
||||
if force_arch == 64 and _machine_word_size >= 64 and num > max_uint32:
|
||||
# 64-bit unsigned integer.
|
||||
return 64, 8, max_uint64, "Q"
|
||||
elif num > max_uint16:
|
||||
# 32-bit unsigned integer
|
||||
return 32, 4, max_uint32, "L"
|
||||
elif num > max_uint8:
|
||||
# 16-bit unsigned integer.
|
||||
return 16, 2, max_uint16, "H"
|
||||
else:
|
||||
# 8-bit unsigned integer.
|
||||
return 8, 1, max_uint8, "B"
|
||||
@@ -0,0 +1,442 @@
|
||||
"""RSA module
|
||||
pri = k[1] //Private part of keys d,p,q
|
||||
|
||||
Module for calculating large primes, and RSA encryption, decryption,
|
||||
signing and verification. Includes generating public and private keys.
|
||||
|
||||
WARNING: this code implements the mathematics of RSA. It is not suitable for
|
||||
real-world secure cryptography purposes. It has not been reviewed by a security
|
||||
expert. It does not include padding of data. There are many ways in which the
|
||||
output of this module, when used without any modification, can be sucessfully
|
||||
attacked.
|
||||
"""
|
||||
|
||||
__author__ = "Sybren Stuvel, Marloes de Boer and Ivo Tamboer"
|
||||
__date__ = "2010-02-05"
|
||||
__version__ = '1.3.3'
|
||||
|
||||
# NOTE: Python's modulo can return negative numbers. We compensate for
|
||||
# this behaviour using the abs() function
|
||||
|
||||
from cPickle import dumps, loads
|
||||
import base64
|
||||
import math
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
import types
|
||||
import zlib
|
||||
|
||||
from rsa._compat import byte
|
||||
|
||||
# Display a warning that this insecure version is imported.
|
||||
import warnings
|
||||
warnings.warn('Insecure version of the RSA module is imported as %s, be careful'
|
||||
% __name__)
|
||||
|
||||
def gcd(p, q):
|
||||
"""Returns the greatest common divisor of p and q
|
||||
|
||||
|
||||
>>> gcd(42, 6)
|
||||
6
|
||||
"""
|
||||
if p<q: return gcd(q, p)
|
||||
if q == 0: return p
|
||||
return gcd(q, abs(p%q))
|
||||
|
||||
def bytes2int(bytes):
|
||||
"""Converts a list of bytes or a string to an integer
|
||||
|
||||
>>> (128*256 + 64)*256 + + 15
|
||||
8405007
|
||||
>>> l = [128, 64, 15]
|
||||
>>> bytes2int(l)
|
||||
8405007
|
||||
"""
|
||||
|
||||
if not (type(bytes) is types.ListType or type(bytes) is types.StringType):
|
||||
raise TypeError("You must pass a string or a list")
|
||||
|
||||
# Convert byte stream to integer
|
||||
integer = 0
|
||||
for byte in bytes:
|
||||
integer *= 256
|
||||
if type(byte) is types.StringType: byte = ord(byte)
|
||||
integer += byte
|
||||
|
||||
return integer
|
||||
|
||||
def int2bytes(number):
|
||||
"""Converts a number to a string of bytes
|
||||
|
||||
>>> bytes2int(int2bytes(123456789))
|
||||
123456789
|
||||
"""
|
||||
|
||||
if not (type(number) is types.LongType or type(number) is types.IntType):
|
||||
raise TypeError("You must pass a long or an int")
|
||||
|
||||
string = ""
|
||||
|
||||
while number > 0:
|
||||
string = "%s%s" % (byte(number & 0xFF), string)
|
||||
number /= 256
|
||||
|
||||
return string
|
||||
|
||||
def fast_exponentiation(a, p, n):
|
||||
"""Calculates r = a^p mod n
|
||||
"""
|
||||
result = a % n
|
||||
remainders = []
|
||||
while p != 1:
|
||||
remainders.append(p & 1)
|
||||
p = p >> 1
|
||||
while remainders:
|
||||
rem = remainders.pop()
|
||||
result = ((a ** rem) * result ** 2) % n
|
||||
return result
|
||||
|
||||
def read_random_int(nbits):
|
||||
"""Reads a random integer of approximately nbits bits rounded up
|
||||
to whole bytes"""
|
||||
|
||||
nbytes = ceil(nbits/8.)
|
||||
randomdata = os.urandom(nbytes)
|
||||
return bytes2int(randomdata)
|
||||
|
||||
def ceil(x):
|
||||
"""ceil(x) -> int(math.ceil(x))"""
|
||||
|
||||
return int(math.ceil(x))
|
||||
|
||||
def randint(minvalue, maxvalue):
|
||||
"""Returns a random integer x with minvalue <= x <= maxvalue"""
|
||||
|
||||
# Safety - get a lot of random data even if the range is fairly
|
||||
# small
|
||||
min_nbits = 32
|
||||
|
||||
# The range of the random numbers we need to generate
|
||||
range = maxvalue - minvalue
|
||||
|
||||
# Which is this number of bytes
|
||||
rangebytes = ceil(math.log(range, 2) / 8.)
|
||||
|
||||
# Convert to bits, but make sure it's always at least min_nbits*2
|
||||
rangebits = max(rangebytes * 8, min_nbits * 2)
|
||||
|
||||
# Take a random number of bits between min_nbits and rangebits
|
||||
nbits = random.randint(min_nbits, rangebits)
|
||||
|
||||
return (read_random_int(nbits) % range) + minvalue
|
||||
|
||||
def fermat_little_theorem(p):
|
||||
"""Returns 1 if p may be prime, and something else if p definitely
|
||||
is not prime"""
|
||||
|
||||
a = randint(1, p-1)
|
||||
return fast_exponentiation(a, p-1, p)
|
||||
|
||||
def jacobi(a, b):
|
||||
"""Calculates the value of the Jacobi symbol (a/b)
|
||||
"""
|
||||
|
||||
if a % b == 0:
|
||||
return 0
|
||||
result = 1
|
||||
while a > 1:
|
||||
if a & 1:
|
||||
if ((a-1)*(b-1) >> 2) & 1:
|
||||
result = -result
|
||||
b, a = a, b % a
|
||||
else:
|
||||
if ((b ** 2 - 1) >> 3) & 1:
|
||||
result = -result
|
||||
a = a >> 1
|
||||
return result
|
||||
|
||||
def jacobi_witness(x, n):
|
||||
"""Returns False if n is an Euler pseudo-prime with base x, and
|
||||
True otherwise.
|
||||
"""
|
||||
|
||||
j = jacobi(x, n) % n
|
||||
f = fast_exponentiation(x, (n-1)/2, n)
|
||||
|
||||
if j == f: return False
|
||||
return True
|
||||
|
||||
def randomized_primality_testing(n, k):
|
||||
"""Calculates whether n is composite (which is always correct) or
|
||||
prime (which is incorrect with error probability 2**-k)
|
||||
|
||||
Returns False if the number if composite, and True if it's
|
||||
probably prime.
|
||||
"""
|
||||
|
||||
q = 0.5 # Property of the jacobi_witness function
|
||||
|
||||
# t = int(math.ceil(k / math.log(1/q, 2)))
|
||||
t = ceil(k / math.log(1/q, 2))
|
||||
for i in range(t+1):
|
||||
x = randint(1, n-1)
|
||||
if jacobi_witness(x, n): return False
|
||||
|
||||
return True
|
||||
|
||||
def is_prime(number):
|
||||
"""Returns True if the number is prime, and False otherwise.
|
||||
|
||||
>>> is_prime(42)
|
||||
0
|
||||
>>> is_prime(41)
|
||||
1
|
||||
"""
|
||||
|
||||
"""
|
||||
if not fermat_little_theorem(number) == 1:
|
||||
# Not prime, according to Fermat's little theorem
|
||||
return False
|
||||
"""
|
||||
|
||||
if randomized_primality_testing(number, 5):
|
||||
# Prime, according to Jacobi
|
||||
return True
|
||||
|
||||
# Not prime
|
||||
return False
|
||||
|
||||
|
||||
def getprime(nbits):
|
||||
"""Returns a prime number of max. 'math.ceil(nbits/8)*8' bits. In
|
||||
other words: nbits is rounded up to whole bytes.
|
||||
|
||||
>>> p = getprime(8)
|
||||
>>> is_prime(p-1)
|
||||
0
|
||||
>>> is_prime(p)
|
||||
1
|
||||
>>> is_prime(p+1)
|
||||
0
|
||||
"""
|
||||
|
||||
nbytes = int(math.ceil(nbits/8.))
|
||||
|
||||
while True:
|
||||
integer = read_random_int(nbits)
|
||||
|
||||
# Make sure it's odd
|
||||
integer |= 1
|
||||
|
||||
# Test for primeness
|
||||
if is_prime(integer): break
|
||||
|
||||
# Retry if not prime
|
||||
|
||||
return integer
|
||||
|
||||
def are_relatively_prime(a, b):
|
||||
"""Returns True if a and b are relatively prime, and False if they
|
||||
are not.
|
||||
|
||||
>>> are_relatively_prime(2, 3)
|
||||
1
|
||||
>>> are_relatively_prime(2, 4)
|
||||
0
|
||||
"""
|
||||
|
||||
d = gcd(a, b)
|
||||
return (d == 1)
|
||||
|
||||
def find_p_q(nbits):
|
||||
"""Returns a tuple of two different primes of nbits bits"""
|
||||
|
||||
p = getprime(nbits)
|
||||
while True:
|
||||
q = getprime(nbits)
|
||||
if not q == p: break
|
||||
|
||||
return (p, q)
|
||||
|
||||
def extended_euclid_gcd(a, b):
|
||||
"""Returns a tuple (d, i, j) such that d = gcd(a, b) = ia + jb
|
||||
"""
|
||||
|
||||
if b == 0:
|
||||
return (a, 1, 0)
|
||||
|
||||
q = abs(a % b)
|
||||
r = long(a / b)
|
||||
(d, k, l) = extended_euclid_gcd(b, q)
|
||||
|
||||
return (d, l, k - l*r)
|
||||
|
||||
# Main function: calculate encryption and decryption keys
|
||||
def calculate_keys(p, q, nbits):
|
||||
"""Calculates an encryption and a decryption key for p and q, and
|
||||
returns them as a tuple (e, d)"""
|
||||
|
||||
n = p * q
|
||||
phi_n = (p-1) * (q-1)
|
||||
|
||||
while True:
|
||||
# Make sure e has enough bits so we ensure "wrapping" through
|
||||
# modulo n
|
||||
e = getprime(max(8, nbits/2))
|
||||
if are_relatively_prime(e, n) and are_relatively_prime(e, phi_n): break
|
||||
|
||||
(d, i, j) = extended_euclid_gcd(e, phi_n)
|
||||
|
||||
if not d == 1:
|
||||
raise Exception("e (%d) and phi_n (%d) are not relatively prime" % (e, phi_n))
|
||||
|
||||
if not (e * i) % phi_n == 1:
|
||||
raise Exception("e (%d) and i (%d) are not mult. inv. modulo phi_n (%d)" % (e, i, phi_n))
|
||||
|
||||
return (e, i)
|
||||
|
||||
|
||||
def gen_keys(nbits):
|
||||
"""Generate RSA keys of nbits bits. Returns (p, q, e, d).
|
||||
|
||||
Note: this can take a long time, depending on the key size.
|
||||
"""
|
||||
|
||||
while True:
|
||||
(p, q) = find_p_q(nbits)
|
||||
(e, d) = calculate_keys(p, q, nbits)
|
||||
|
||||
# For some reason, d is sometimes negative. We don't know how
|
||||
# to fix it (yet), so we keep trying until everything is shiny
|
||||
if d > 0: break
|
||||
|
||||
return (p, q, e, d)
|
||||
|
||||
def gen_pubpriv_keys(nbits):
|
||||
"""Generates public and private keys, and returns them as (pub,
|
||||
priv).
|
||||
|
||||
The public key consists of a dict {e: ..., , n: ....). The private
|
||||
key consists of a dict {d: ...., p: ...., q: ....).
|
||||
"""
|
||||
|
||||
(p, q, e, d) = gen_keys(nbits)
|
||||
|
||||
return ( {'e': e, 'n': p*q}, {'d': d, 'p': p, 'q': q} )
|
||||
|
||||
def encrypt_int(message, ekey, n):
|
||||
"""Encrypts a message using encryption key 'ekey', working modulo
|
||||
n"""
|
||||
|
||||
if type(message) is types.IntType:
|
||||
return encrypt_int(long(message), ekey, n)
|
||||
|
||||
if not type(message) is types.LongType:
|
||||
raise TypeError("You must pass a long or an int")
|
||||
|
||||
if message > 0 and \
|
||||
math.floor(math.log(message, 2)) > math.floor(math.log(n, 2)):
|
||||
raise OverflowError("The message is too long")
|
||||
|
||||
return fast_exponentiation(message, ekey, n)
|
||||
|
||||
def decrypt_int(cyphertext, dkey, n):
|
||||
"""Decrypts a cypher text using the decryption key 'dkey', working
|
||||
modulo n"""
|
||||
|
||||
return encrypt_int(cyphertext, dkey, n)
|
||||
|
||||
def sign_int(message, dkey, n):
|
||||
"""Signs 'message' using key 'dkey', working modulo n"""
|
||||
|
||||
return decrypt_int(message, dkey, n)
|
||||
|
||||
def verify_int(signed, ekey, n):
|
||||
"""verifies 'signed' using key 'ekey', working modulo n"""
|
||||
|
||||
return encrypt_int(signed, ekey, n)
|
||||
|
||||
def picklechops(chops):
|
||||
"""Pickles and base64encodes it's argument chops"""
|
||||
|
||||
value = zlib.compress(dumps(chops))
|
||||
encoded = base64.encodestring(value)
|
||||
return encoded.strip()
|
||||
|
||||
def unpicklechops(string):
|
||||
"""base64decodes and unpickes it's argument string into chops"""
|
||||
|
||||
return loads(zlib.decompress(base64.decodestring(string)))
|
||||
|
||||
def chopstring(message, key, n, funcref):
|
||||
"""Splits 'message' into chops that are at most as long as n,
|
||||
converts these into integers, and calls funcref(integer, key, n)
|
||||
for each chop.
|
||||
|
||||
Used by 'encrypt' and 'sign'.
|
||||
"""
|
||||
|
||||
msglen = len(message)
|
||||
mbits = msglen * 8
|
||||
nbits = int(math.floor(math.log(n, 2)))
|
||||
nbytes = nbits / 8
|
||||
blocks = msglen / nbytes
|
||||
|
||||
if msglen % nbytes > 0:
|
||||
blocks += 1
|
||||
|
||||
cypher = []
|
||||
|
||||
for bindex in range(blocks):
|
||||
offset = bindex * nbytes
|
||||
block = message[offset:offset+nbytes]
|
||||
value = bytes2int(block)
|
||||
cypher.append(funcref(value, key, n))
|
||||
|
||||
return picklechops(cypher)
|
||||
|
||||
def gluechops(chops, key, n, funcref):
|
||||
"""Glues chops back together into a string. calls
|
||||
funcref(integer, key, n) for each chop.
|
||||
|
||||
Used by 'decrypt' and 'verify'.
|
||||
"""
|
||||
message = ""
|
||||
|
||||
chops = unpicklechops(chops)
|
||||
|
||||
for cpart in chops:
|
||||
mpart = funcref(cpart, key, n)
|
||||
message += int2bytes(mpart)
|
||||
|
||||
return message
|
||||
|
||||
def encrypt(message, key):
|
||||
"""Encrypts a string 'message' with the public key 'key'"""
|
||||
|
||||
return chopstring(message, key['e'], key['n'], encrypt_int)
|
||||
|
||||
def sign(message, key):
|
||||
"""Signs a string 'message' with the private key 'key'"""
|
||||
|
||||
return chopstring(message, key['d'], key['p']*key['q'], decrypt_int)
|
||||
|
||||
def decrypt(cypher, key):
|
||||
"""Decrypts a cypher with the private key 'key'"""
|
||||
|
||||
return gluechops(cypher, key['d'], key['p']*key['q'], decrypt_int)
|
||||
|
||||
def verify(cypher, key):
|
||||
"""Verifies a cypher with the public key 'key'"""
|
||||
|
||||
return gluechops(cypher, key['e'], key['n'], encrypt_int)
|
||||
|
||||
# Do doctest if we're not imported
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
||||
__all__ = ["gen_pubpriv_keys", "encrypt", "decrypt", "sign", "verify"]
|
||||
|
||||
@@ -0,0 +1,529 @@
|
||||
"""RSA module
|
||||
|
||||
Module for calculating large primes, and RSA encryption, decryption,
|
||||
signing and verification. Includes generating public and private keys.
|
||||
|
||||
WARNING: this implementation does not use random padding, compression of the
|
||||
cleartext input to prevent repetitions, or other common security improvements.
|
||||
Use with care.
|
||||
|
||||
"""
|
||||
|
||||
__author__ = "Sybren Stuvel, Marloes de Boer, Ivo Tamboer, and Barry Mead"
|
||||
__date__ = "2010-02-08"
|
||||
__version__ = '2.0'
|
||||
|
||||
import math
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
import types
|
||||
from rsa._compat import byte
|
||||
|
||||
# Display a warning that this insecure version is imported.
|
||||
import warnings
|
||||
warnings.warn('Insecure version of the RSA module is imported as %s' % __name__)
|
||||
|
||||
|
||||
def bit_size(number):
|
||||
"""Returns the number of bits required to hold a specific long number"""
|
||||
|
||||
return int(math.ceil(math.log(number,2)))
|
||||
|
||||
def gcd(p, q):
|
||||
"""Returns the greatest common divisor of p and q
|
||||
>>> gcd(48, 180)
|
||||
12
|
||||
"""
|
||||
# Iterateive Version is faster and uses much less stack space
|
||||
while q != 0:
|
||||
if p < q: (p,q) = (q,p)
|
||||
(p,q) = (q, p % q)
|
||||
return p
|
||||
|
||||
|
||||
def bytes2int(bytes):
|
||||
"""Converts a list of bytes or a string to an integer
|
||||
|
||||
>>> (((128 * 256) + 64) * 256) + 15
|
||||
8405007
|
||||
>>> l = [128, 64, 15]
|
||||
>>> bytes2int(l) #same as bytes2int('\x80@\x0f')
|
||||
8405007
|
||||
"""
|
||||
|
||||
if not (type(bytes) is types.ListType or type(bytes) is types.StringType):
|
||||
raise TypeError("You must pass a string or a list")
|
||||
|
||||
# Convert byte stream to integer
|
||||
integer = 0
|
||||
for byte in bytes:
|
||||
integer *= 256
|
||||
if type(byte) is types.StringType: byte = ord(byte)
|
||||
integer += byte
|
||||
|
||||
return integer
|
||||
|
||||
def int2bytes(number):
|
||||
"""
|
||||
Converts a number to a string of bytes
|
||||
"""
|
||||
|
||||
if not (type(number) is types.LongType or type(number) is types.IntType):
|
||||
raise TypeError("You must pass a long or an int")
|
||||
|
||||
string = ""
|
||||
|
||||
while number > 0:
|
||||
string = "%s%s" % (byte(number & 0xFF), string)
|
||||
number /= 256
|
||||
|
||||
return string
|
||||
|
||||
def to64(number):
|
||||
"""Converts a number in the range of 0 to 63 into base 64 digit
|
||||
character in the range of '0'-'9', 'A'-'Z', 'a'-'z','-','_'.
|
||||
|
||||
>>> to64(10)
|
||||
'A'
|
||||
"""
|
||||
|
||||
if not (type(number) is types.LongType or type(number) is types.IntType):
|
||||
raise TypeError("You must pass a long or an int")
|
||||
|
||||
if 0 <= number <= 9: #00-09 translates to '0' - '9'
|
||||
return byte(number + 48)
|
||||
|
||||
if 10 <= number <= 35:
|
||||
return byte(number + 55) #10-35 translates to 'A' - 'Z'
|
||||
|
||||
if 36 <= number <= 61:
|
||||
return byte(number + 61) #36-61 translates to 'a' - 'z'
|
||||
|
||||
if number == 62: # 62 translates to '-' (minus)
|
||||
return byte(45)
|
||||
|
||||
if number == 63: # 63 translates to '_' (underscore)
|
||||
return byte(95)
|
||||
|
||||
raise ValueError('Invalid Base64 value: %i' % number)
|
||||
|
||||
|
||||
def from64(number):
|
||||
"""Converts an ordinal character value in the range of
|
||||
0-9,A-Z,a-z,-,_ to a number in the range of 0-63.
|
||||
|
||||
>>> from64(49)
|
||||
1
|
||||
"""
|
||||
|
||||
if not (type(number) is types.LongType or type(number) is types.IntType):
|
||||
raise TypeError("You must pass a long or an int")
|
||||
|
||||
if 48 <= number <= 57: #ord('0') - ord('9') translates to 0-9
|
||||
return(number - 48)
|
||||
|
||||
if 65 <= number <= 90: #ord('A') - ord('Z') translates to 10-35
|
||||
return(number - 55)
|
||||
|
||||
if 97 <= number <= 122: #ord('a') - ord('z') translates to 36-61
|
||||
return(number - 61)
|
||||
|
||||
if number == 45: #ord('-') translates to 62
|
||||
return(62)
|
||||
|
||||
if number == 95: #ord('_') translates to 63
|
||||
return(63)
|
||||
|
||||
raise ValueError('Invalid Base64 value: %i' % number)
|
||||
|
||||
|
||||
def int2str64(number):
|
||||
"""Converts a number to a string of base64 encoded characters in
|
||||
the range of '0'-'9','A'-'Z,'a'-'z','-','_'.
|
||||
|
||||
>>> int2str64(123456789)
|
||||
'7MyqL'
|
||||
"""
|
||||
|
||||
if not (type(number) is types.LongType or type(number) is types.IntType):
|
||||
raise TypeError("You must pass a long or an int")
|
||||
|
||||
string = ""
|
||||
|
||||
while number > 0:
|
||||
string = "%s%s" % (to64(number & 0x3F), string)
|
||||
number /= 64
|
||||
|
||||
return string
|
||||
|
||||
|
||||
def str642int(string):
|
||||
"""Converts a base64 encoded string into an integer.
|
||||
The chars of this string in in the range '0'-'9','A'-'Z','a'-'z','-','_'
|
||||
|
||||
>>> str642int('7MyqL')
|
||||
123456789
|
||||
"""
|
||||
|
||||
if not (type(string) is types.ListType or type(string) is types.StringType):
|
||||
raise TypeError("You must pass a string or a list")
|
||||
|
||||
integer = 0
|
||||
for byte in string:
|
||||
integer *= 64
|
||||
if type(byte) is types.StringType: byte = ord(byte)
|
||||
integer += from64(byte)
|
||||
|
||||
return integer
|
||||
|
||||
def read_random_int(nbits):
|
||||
"""Reads a random integer of approximately nbits bits rounded up
|
||||
to whole bytes"""
|
||||
|
||||
nbytes = int(math.ceil(nbits/8.))
|
||||
randomdata = os.urandom(nbytes)
|
||||
return bytes2int(randomdata)
|
||||
|
||||
def randint(minvalue, maxvalue):
|
||||
"""Returns a random integer x with minvalue <= x <= maxvalue"""
|
||||
|
||||
# Safety - get a lot of random data even if the range is fairly
|
||||
# small
|
||||
min_nbits = 32
|
||||
|
||||
# The range of the random numbers we need to generate
|
||||
range = (maxvalue - minvalue) + 1
|
||||
|
||||
# Which is this number of bytes
|
||||
rangebytes = ((bit_size(range) + 7) / 8)
|
||||
|
||||
# Convert to bits, but make sure it's always at least min_nbits*2
|
||||
rangebits = max(rangebytes * 8, min_nbits * 2)
|
||||
|
||||
# Take a random number of bits between min_nbits and rangebits
|
||||
nbits = random.randint(min_nbits, rangebits)
|
||||
|
||||
return (read_random_int(nbits) % range) + minvalue
|
||||
|
||||
def jacobi(a, b):
|
||||
"""Calculates the value of the Jacobi symbol (a/b)
|
||||
where both a and b are positive integers, and b is odd
|
||||
"""
|
||||
|
||||
if a == 0: return 0
|
||||
result = 1
|
||||
while a > 1:
|
||||
if a & 1:
|
||||
if ((a-1)*(b-1) >> 2) & 1:
|
||||
result = -result
|
||||
a, b = b % a, a
|
||||
else:
|
||||
if (((b * b) - 1) >> 3) & 1:
|
||||
result = -result
|
||||
a >>= 1
|
||||
if a == 0: return 0
|
||||
return result
|
||||
|
||||
def jacobi_witness(x, n):
|
||||
"""Returns False if n is an Euler pseudo-prime with base x, and
|
||||
True otherwise.
|
||||
"""
|
||||
|
||||
j = jacobi(x, n) % n
|
||||
f = pow(x, (n-1)/2, n)
|
||||
|
||||
if j == f: return False
|
||||
return True
|
||||
|
||||
def randomized_primality_testing(n, k):
|
||||
"""Calculates whether n is composite (which is always correct) or
|
||||
prime (which is incorrect with error probability 2**-k)
|
||||
|
||||
Returns False if the number is composite, and True if it's
|
||||
probably prime.
|
||||
"""
|
||||
|
||||
# 50% of Jacobi-witnesses can report compositness of non-prime numbers
|
||||
|
||||
for i in range(k):
|
||||
x = randint(1, n-1)
|
||||
if jacobi_witness(x, n): return False
|
||||
|
||||
return True
|
||||
|
||||
def is_prime(number):
|
||||
"""Returns True if the number is prime, and False otherwise.
|
||||
|
||||
>>> is_prime(42)
|
||||
0
|
||||
>>> is_prime(41)
|
||||
1
|
||||
"""
|
||||
|
||||
if randomized_primality_testing(number, 6):
|
||||
# Prime, according to Jacobi
|
||||
return True
|
||||
|
||||
# Not prime
|
||||
return False
|
||||
|
||||
|
||||
def getprime(nbits):
|
||||
"""Returns a prime number of max. 'math.ceil(nbits/8)*8' bits. In
|
||||
other words: nbits is rounded up to whole bytes.
|
||||
|
||||
>>> p = getprime(8)
|
||||
>>> is_prime(p-1)
|
||||
0
|
||||
>>> is_prime(p)
|
||||
1
|
||||
>>> is_prime(p+1)
|
||||
0
|
||||
"""
|
||||
|
||||
while True:
|
||||
integer = read_random_int(nbits)
|
||||
|
||||
# Make sure it's odd
|
||||
integer |= 1
|
||||
|
||||
# Test for primeness
|
||||
if is_prime(integer): break
|
||||
|
||||
# Retry if not prime
|
||||
|
||||
return integer
|
||||
|
||||
def are_relatively_prime(a, b):
|
||||
"""Returns True if a and b are relatively prime, and False if they
|
||||
are not.
|
||||
|
||||
>>> are_relatively_prime(2, 3)
|
||||
1
|
||||
>>> are_relatively_prime(2, 4)
|
||||
0
|
||||
"""
|
||||
|
||||
d = gcd(a, b)
|
||||
return (d == 1)
|
||||
|
||||
def find_p_q(nbits):
|
||||
"""Returns a tuple of two different primes of nbits bits"""
|
||||
pbits = nbits + (nbits/16) #Make sure that p and q aren't too close
|
||||
qbits = nbits - (nbits/16) #or the factoring programs can factor n
|
||||
p = getprime(pbits)
|
||||
while True:
|
||||
q = getprime(qbits)
|
||||
#Make sure p and q are different.
|
||||
if not q == p: break
|
||||
return (p, q)
|
||||
|
||||
def extended_gcd(a, b):
|
||||
"""Returns a tuple (r, i, j) such that r = gcd(a, b) = ia + jb
|
||||
"""
|
||||
# r = gcd(a,b) i = multiplicitive inverse of a mod b
|
||||
# or j = multiplicitive inverse of b mod a
|
||||
# Neg return values for i or j are made positive mod b or a respectively
|
||||
# Iterateive Version is faster and uses much less stack space
|
||||
x = 0
|
||||
y = 1
|
||||
lx = 1
|
||||
ly = 0
|
||||
oa = a #Remember original a/b to remove
|
||||
ob = b #negative values from return results
|
||||
while b != 0:
|
||||
q = long(a/b)
|
||||
(a, b) = (b, a % b)
|
||||
(x, lx) = ((lx - (q * x)),x)
|
||||
(y, ly) = ((ly - (q * y)),y)
|
||||
if (lx < 0): lx += ob #If neg wrap modulo orignal b
|
||||
if (ly < 0): ly += oa #If neg wrap modulo orignal a
|
||||
return (a, lx, ly) #Return only positive values
|
||||
|
||||
# Main function: calculate encryption and decryption keys
|
||||
def calculate_keys(p, q, nbits):
|
||||
"""Calculates an encryption and a decryption key for p and q, and
|
||||
returns them as a tuple (e, d)"""
|
||||
|
||||
n = p * q
|
||||
phi_n = (p-1) * (q-1)
|
||||
|
||||
while True:
|
||||
# Make sure e has enough bits so we ensure "wrapping" through
|
||||
# modulo n
|
||||
e = max(65537,getprime(nbits/4))
|
||||
if are_relatively_prime(e, n) and are_relatively_prime(e, phi_n): break
|
||||
|
||||
(d, i, j) = extended_gcd(e, phi_n)
|
||||
|
||||
if not d == 1:
|
||||
raise Exception("e (%d) and phi_n (%d) are not relatively prime" % (e, phi_n))
|
||||
if (i < 0):
|
||||
raise Exception("New extended_gcd shouldn't return negative values")
|
||||
if not (e * i) % phi_n == 1:
|
||||
raise Exception("e (%d) and i (%d) are not mult. inv. modulo phi_n (%d)" % (e, i, phi_n))
|
||||
|
||||
return (e, i)
|
||||
|
||||
|
||||
def gen_keys(nbits):
|
||||
"""Generate RSA keys of nbits bits. Returns (p, q, e, d).
|
||||
|
||||
Note: this can take a long time, depending on the key size.
|
||||
"""
|
||||
|
||||
(p, q) = find_p_q(nbits)
|
||||
(e, d) = calculate_keys(p, q, nbits)
|
||||
|
||||
return (p, q, e, d)
|
||||
|
||||
def newkeys(nbits):
|
||||
"""Generates public and private keys, and returns them as (pub,
|
||||
priv).
|
||||
|
||||
The public key consists of a dict {e: ..., , n: ....). The private
|
||||
key consists of a dict {d: ...., p: ...., q: ....).
|
||||
"""
|
||||
nbits = max(9,nbits) # Don't let nbits go below 9 bits
|
||||
(p, q, e, d) = gen_keys(nbits)
|
||||
|
||||
return ( {'e': e, 'n': p*q}, {'d': d, 'p': p, 'q': q} )
|
||||
|
||||
def encrypt_int(message, ekey, n):
|
||||
"""Encrypts a message using encryption key 'ekey', working modulo n"""
|
||||
|
||||
if type(message) is types.IntType:
|
||||
message = long(message)
|
||||
|
||||
if not type(message) is types.LongType:
|
||||
raise TypeError("You must pass a long or int")
|
||||
|
||||
if message < 0 or message > n:
|
||||
raise OverflowError("The message is too long")
|
||||
|
||||
#Note: Bit exponents start at zero (bit counts start at 1) this is correct
|
||||
safebit = bit_size(n) - 2 #compute safe bit (MSB - 1)
|
||||
message += (1 << safebit) #add safebit to ensure folding
|
||||
|
||||
return pow(message, ekey, n)
|
||||
|
||||
def decrypt_int(cyphertext, dkey, n):
|
||||
"""Decrypts a cypher text using the decryption key 'dkey', working
|
||||
modulo n"""
|
||||
|
||||
message = pow(cyphertext, dkey, n)
|
||||
|
||||
safebit = bit_size(n) - 2 #compute safe bit (MSB - 1)
|
||||
message -= (1 << safebit) #remove safebit before decode
|
||||
|
||||
return message
|
||||
|
||||
def encode64chops(chops):
|
||||
"""base64encodes chops and combines them into a ',' delimited string"""
|
||||
|
||||
chips = [] #chips are character chops
|
||||
|
||||
for value in chops:
|
||||
chips.append(int2str64(value))
|
||||
|
||||
#delimit chops with comma
|
||||
encoded = ','.join(chips)
|
||||
|
||||
return encoded
|
||||
|
||||
def decode64chops(string):
|
||||
"""base64decodes and makes a ',' delimited string into chops"""
|
||||
|
||||
chips = string.split(',') #split chops at commas
|
||||
|
||||
chops = []
|
||||
|
||||
for string in chips: #make char chops (chips) into chops
|
||||
chops.append(str642int(string))
|
||||
|
||||
return chops
|
||||
|
||||
def chopstring(message, key, n, funcref):
|
||||
"""Chops the 'message' into integers that fit into n,
|
||||
leaving room for a safebit to be added to ensure that all
|
||||
messages fold during exponentiation. The MSB of the number n
|
||||
is not independant modulo n (setting it could cause overflow), so
|
||||
use the next lower bit for the safebit. Therefore reserve 2-bits
|
||||
in the number n for non-data bits. Calls specified encryption
|
||||
function for each chop.
|
||||
|
||||
Used by 'encrypt' and 'sign'.
|
||||
"""
|
||||
|
||||
msglen = len(message)
|
||||
mbits = msglen * 8
|
||||
#Set aside 2-bits so setting of safebit won't overflow modulo n.
|
||||
nbits = bit_size(n) - 2 # leave room for safebit
|
||||
nbytes = nbits / 8
|
||||
blocks = msglen / nbytes
|
||||
|
||||
if msglen % nbytes > 0:
|
||||
blocks += 1
|
||||
|
||||
cypher = []
|
||||
|
||||
for bindex in range(blocks):
|
||||
offset = bindex * nbytes
|
||||
block = message[offset:offset+nbytes]
|
||||
value = bytes2int(block)
|
||||
cypher.append(funcref(value, key, n))
|
||||
|
||||
return encode64chops(cypher) #Encode encrypted ints to base64 strings
|
||||
|
||||
def gluechops(string, key, n, funcref):
|
||||
"""Glues chops back together into a string. calls
|
||||
funcref(integer, key, n) for each chop.
|
||||
|
||||
Used by 'decrypt' and 'verify'.
|
||||
"""
|
||||
message = ""
|
||||
|
||||
chops = decode64chops(string) #Decode base64 strings into integer chops
|
||||
|
||||
for cpart in chops:
|
||||
mpart = funcref(cpart, key, n) #Decrypt each chop
|
||||
message += int2bytes(mpart) #Combine decrypted strings into a msg
|
||||
|
||||
return message
|
||||
|
||||
def encrypt(message, key):
|
||||
"""Encrypts a string 'message' with the public key 'key'"""
|
||||
if 'n' not in key:
|
||||
raise Exception("You must use the public key with encrypt")
|
||||
|
||||
return chopstring(message, key['e'], key['n'], encrypt_int)
|
||||
|
||||
def sign(message, key):
|
||||
"""Signs a string 'message' with the private key 'key'"""
|
||||
if 'p' not in key:
|
||||
raise Exception("You must use the private key with sign")
|
||||
|
||||
return chopstring(message, key['d'], key['p']*key['q'], encrypt_int)
|
||||
|
||||
def decrypt(cypher, key):
|
||||
"""Decrypts a string 'cypher' with the private key 'key'"""
|
||||
if 'p' not in key:
|
||||
raise Exception("You must use the private key with decrypt")
|
||||
|
||||
return gluechops(cypher, key['d'], key['p']*key['q'], decrypt_int)
|
||||
|
||||
def verify(cypher, key):
|
||||
"""Verifies a string 'cypher' with the public key 'key'"""
|
||||
if 'n' not in key:
|
||||
raise Exception("You must use the public key with verify")
|
||||
|
||||
return gluechops(cypher, key['e'], key['n'], decrypt_int)
|
||||
|
||||
# Do doctest if we're not imported
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
||||
__all__ = ["newkeys", "encrypt", "decrypt", "sign", "verify"]
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
'''ASN.1 definitions.
|
||||
|
||||
Not all ASN.1-handling code use these definitions, but when it does, they should be here.
|
||||
'''
|
||||
|
||||
from pyasn1.type import univ, namedtype, tag
|
||||
|
||||
class PubKeyHeader(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('oid', univ.ObjectIdentifier()),
|
||||
namedtype.NamedType('parameters', univ.Null()),
|
||||
)
|
||||
|
||||
class OpenSSLPubKey(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('header', PubKeyHeader()),
|
||||
|
||||
# This little hack (the implicit tag) allows us to get a Bit String as Octet String
|
||||
namedtype.NamedType('key', univ.OctetString().subtype(
|
||||
implicitTag=tag.Tag(tagClass=0, tagFormat=0, tagId=3))),
|
||||
)
|
||||
|
||||
|
||||
class AsnPubKey(univ.Sequence):
|
||||
'''ASN.1 contents of DER encoded public key:
|
||||
|
||||
RSAPublicKey ::= SEQUENCE {
|
||||
modulus INTEGER, -- n
|
||||
publicExponent INTEGER, -- e
|
||||
'''
|
||||
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('modulus', univ.Integer()),
|
||||
namedtype.NamedType('publicExponent', univ.Integer()),
|
||||
)
|
||||
@@ -0,0 +1,87 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
'''Large file support
|
||||
|
||||
- break a file into smaller blocks, and encrypt them, and store the
|
||||
encrypted blocks in another file.
|
||||
|
||||
- take such an encrypted files, decrypt its blocks, and reconstruct the
|
||||
original file.
|
||||
|
||||
The encrypted file format is as follows, where || denotes byte concatenation:
|
||||
|
||||
FILE := VERSION || BLOCK || BLOCK ...
|
||||
|
||||
BLOCK := LENGTH || DATA
|
||||
|
||||
LENGTH := varint-encoded length of the subsequent data. Varint comes from
|
||||
Google Protobuf, and encodes an integer into a variable number of bytes.
|
||||
Each byte uses the 7 lowest bits to encode the value. The highest bit set
|
||||
to 1 indicates the next byte is also part of the varint. The last byte will
|
||||
have this bit set to 0.
|
||||
|
||||
This file format is called the VARBLOCK format, in line with the varint format
|
||||
used to denote the block sizes.
|
||||
|
||||
'''
|
||||
|
||||
from rsa import key, common, pkcs1, varblock
|
||||
from rsa._compat import byte
|
||||
|
||||
def encrypt_bigfile(infile, outfile, pub_key):
|
||||
'''Encrypts a file, writing it to 'outfile' in VARBLOCK format.
|
||||
|
||||
:param infile: file-like object to read the cleartext from
|
||||
:param outfile: file-like object to write the crypto in VARBLOCK format to
|
||||
:param pub_key: :py:class:`rsa.PublicKey` to encrypt with
|
||||
|
||||
'''
|
||||
|
||||
if not isinstance(pub_key, key.PublicKey):
|
||||
raise TypeError('Public key required, but got %r' % pub_key)
|
||||
|
||||
key_bytes = common.bit_size(pub_key.n) // 8
|
||||
blocksize = key_bytes - 11 # keep space for PKCS#1 padding
|
||||
|
||||
# Write the version number to the VARBLOCK file
|
||||
outfile.write(byte(varblock.VARBLOCK_VERSION))
|
||||
|
||||
# Encrypt and write each block
|
||||
for block in varblock.yield_fixedblocks(infile, blocksize):
|
||||
crypto = pkcs1.encrypt(block, pub_key)
|
||||
|
||||
varblock.write_varint(outfile, len(crypto))
|
||||
outfile.write(crypto)
|
||||
|
||||
def decrypt_bigfile(infile, outfile, priv_key):
|
||||
'''Decrypts an encrypted VARBLOCK file, writing it to 'outfile'
|
||||
|
||||
:param infile: file-like object to read the crypto in VARBLOCK format from
|
||||
:param outfile: file-like object to write the cleartext to
|
||||
:param priv_key: :py:class:`rsa.PrivateKey` to decrypt with
|
||||
|
||||
'''
|
||||
|
||||
if not isinstance(priv_key, key.PrivateKey):
|
||||
raise TypeError('Private key required, but got %r' % priv_key)
|
||||
|
||||
for block in varblock.yield_varblocks(infile):
|
||||
cleartext = pkcs1.decrypt(block, priv_key)
|
||||
outfile.write(cleartext)
|
||||
|
||||
__all__ = ['encrypt_bigfile', 'decrypt_bigfile']
|
||||
|
||||
@@ -0,0 +1,379 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
'''Commandline scripts.
|
||||
|
||||
These scripts are called by the executables defined in setup.py.
|
||||
'''
|
||||
|
||||
from __future__ import with_statement, print_function
|
||||
|
||||
import abc
|
||||
import sys
|
||||
from optparse import OptionParser
|
||||
|
||||
import rsa
|
||||
import rsa.bigfile
|
||||
import rsa.pkcs1
|
||||
|
||||
HASH_METHODS = sorted(rsa.pkcs1.HASH_METHODS.keys())
|
||||
|
||||
def keygen():
|
||||
'''Key generator.'''
|
||||
|
||||
# Parse the CLI options
|
||||
parser = OptionParser(usage='usage: %prog [options] keysize',
|
||||
description='Generates a new RSA keypair of "keysize" bits.')
|
||||
|
||||
parser.add_option('--pubout', type='string',
|
||||
help='Output filename for the public key. The public key is '
|
||||
'not saved if this option is not present. You can use '
|
||||
'pyrsa-priv2pub to create the public key file later.')
|
||||
|
||||
parser.add_option('-o', '--out', type='string',
|
||||
help='Output filename for the private key. The key is '
|
||||
'written to stdout if this option is not present.')
|
||||
|
||||
parser.add_option('--form',
|
||||
help='key format of the private and public keys - default PEM',
|
||||
choices=('PEM', 'DER'), default='PEM')
|
||||
|
||||
(cli, cli_args) = parser.parse_args(sys.argv[1:])
|
||||
|
||||
if len(cli_args) != 1:
|
||||
parser.print_help()
|
||||
raise SystemExit(1)
|
||||
|
||||
try:
|
||||
keysize = int(cli_args[0])
|
||||
except ValueError:
|
||||
parser.print_help()
|
||||
print('Not a valid number: %s' % cli_args[0], file=sys.stderr)
|
||||
raise SystemExit(1)
|
||||
|
||||
print('Generating %i-bit key' % keysize, file=sys.stderr)
|
||||
(pub_key, priv_key) = rsa.newkeys(keysize)
|
||||
|
||||
|
||||
# Save public key
|
||||
if cli.pubout:
|
||||
print('Writing public key to %s' % cli.pubout, file=sys.stderr)
|
||||
data = pub_key.save_pkcs1(format=cli.form)
|
||||
with open(cli.pubout, 'wb') as outfile:
|
||||
outfile.write(data)
|
||||
|
||||
# Save private key
|
||||
data = priv_key.save_pkcs1(format=cli.form)
|
||||
|
||||
if cli.out:
|
||||
print('Writing private key to %s' % cli.out, file=sys.stderr)
|
||||
with open(cli.out, 'wb') as outfile:
|
||||
outfile.write(data)
|
||||
else:
|
||||
print('Writing private key to stdout', file=sys.stderr)
|
||||
sys.stdout.write(data)
|
||||
|
||||
|
||||
class CryptoOperation(object):
|
||||
'''CLI callable that operates with input, output, and a key.'''
|
||||
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
keyname = 'public' # or 'private'
|
||||
usage = 'usage: %%prog [options] %(keyname)s_key'
|
||||
description = None
|
||||
operation = 'decrypt'
|
||||
operation_past = 'decrypted'
|
||||
operation_progressive = 'decrypting'
|
||||
input_help = 'Name of the file to %(operation)s. Reads from stdin if ' \
|
||||
'not specified.'
|
||||
output_help = 'Name of the file to write the %(operation_past)s file ' \
|
||||
'to. Written to stdout if this option is not present.'
|
||||
expected_cli_args = 1
|
||||
has_output = True
|
||||
|
||||
key_class = rsa.PublicKey
|
||||
|
||||
def __init__(self):
|
||||
self.usage = self.usage % self.__class__.__dict__
|
||||
self.input_help = self.input_help % self.__class__.__dict__
|
||||
self.output_help = self.output_help % self.__class__.__dict__
|
||||
|
||||
@abc.abstractmethod
|
||||
def perform_operation(self, indata, key, cli_args=None):
|
||||
'''Performs the program's operation.
|
||||
|
||||
Implement in a subclass.
|
||||
|
||||
:returns: the data to write to the output.
|
||||
'''
|
||||
|
||||
def __call__(self):
|
||||
'''Runs the program.'''
|
||||
|
||||
(cli, cli_args) = self.parse_cli()
|
||||
|
||||
key = self.read_key(cli_args[0], cli.keyform)
|
||||
|
||||
indata = self.read_infile(cli.input)
|
||||
|
||||
print(self.operation_progressive.title(), file=sys.stderr)
|
||||
outdata = self.perform_operation(indata, key, cli_args)
|
||||
|
||||
if self.has_output:
|
||||
self.write_outfile(outdata, cli.output)
|
||||
|
||||
def parse_cli(self):
|
||||
'''Parse the CLI options
|
||||
|
||||
:returns: (cli_opts, cli_args)
|
||||
'''
|
||||
|
||||
parser = OptionParser(usage=self.usage, description=self.description)
|
||||
|
||||
parser.add_option('-i', '--input', type='string', help=self.input_help)
|
||||
|
||||
if self.has_output:
|
||||
parser.add_option('-o', '--output', type='string', help=self.output_help)
|
||||
|
||||
parser.add_option('--keyform',
|
||||
help='Key format of the %s key - default PEM' % self.keyname,
|
||||
choices=('PEM', 'DER'), default='PEM')
|
||||
|
||||
(cli, cli_args) = parser.parse_args(sys.argv[1:])
|
||||
|
||||
if len(cli_args) != self.expected_cli_args:
|
||||
parser.print_help()
|
||||
raise SystemExit(1)
|
||||
|
||||
return (cli, cli_args)
|
||||
|
||||
def read_key(self, filename, keyform):
|
||||
'''Reads a public or private key.'''
|
||||
|
||||
print('Reading %s key from %s' % (self.keyname, filename), file=sys.stderr)
|
||||
with open(filename, 'rb') as keyfile:
|
||||
keydata = keyfile.read()
|
||||
|
||||
return self.key_class.load_pkcs1(keydata, keyform)
|
||||
|
||||
def read_infile(self, inname):
|
||||
'''Read the input file'''
|
||||
|
||||
if inname:
|
||||
print('Reading input from %s' % inname, file=sys.stderr)
|
||||
with open(inname, 'rb') as infile:
|
||||
return infile.read()
|
||||
|
||||
print('Reading input from stdin', file=sys.stderr)
|
||||
return sys.stdin.read()
|
||||
|
||||
def write_outfile(self, outdata, outname):
|
||||
'''Write the output file'''
|
||||
|
||||
if outname:
|
||||
print('Writing output to %s' % outname, file=sys.stderr)
|
||||
with open(outname, 'wb') as outfile:
|
||||
outfile.write(outdata)
|
||||
else:
|
||||
print('Writing output to stdout', file=sys.stderr)
|
||||
sys.stdout.write(outdata)
|
||||
|
||||
class EncryptOperation(CryptoOperation):
|
||||
'''Encrypts a file.'''
|
||||
|
||||
keyname = 'public'
|
||||
description = ('Encrypts a file. The file must be shorter than the key '
|
||||
'length in order to be encrypted. For larger files, use the '
|
||||
'pyrsa-encrypt-bigfile command.')
|
||||
operation = 'encrypt'
|
||||
operation_past = 'encrypted'
|
||||
operation_progressive = 'encrypting'
|
||||
|
||||
|
||||
def perform_operation(self, indata, pub_key, cli_args=None):
|
||||
'''Encrypts files.'''
|
||||
|
||||
return rsa.encrypt(indata, pub_key)
|
||||
|
||||
class DecryptOperation(CryptoOperation):
|
||||
'''Decrypts a file.'''
|
||||
|
||||
keyname = 'private'
|
||||
description = ('Decrypts a file. The original file must be shorter than '
|
||||
'the key length in order to have been encrypted. For larger '
|
||||
'files, use the pyrsa-decrypt-bigfile command.')
|
||||
operation = 'decrypt'
|
||||
operation_past = 'decrypted'
|
||||
operation_progressive = 'decrypting'
|
||||
key_class = rsa.PrivateKey
|
||||
|
||||
def perform_operation(self, indata, priv_key, cli_args=None):
|
||||
'''Decrypts files.'''
|
||||
|
||||
return rsa.decrypt(indata, priv_key)
|
||||
|
||||
class SignOperation(CryptoOperation):
|
||||
'''Signs a file.'''
|
||||
|
||||
keyname = 'private'
|
||||
usage = 'usage: %%prog [options] private_key hash_method'
|
||||
description = ('Signs a file, outputs the signature. Choose the hash '
|
||||
'method from %s' % ', '.join(HASH_METHODS))
|
||||
operation = 'sign'
|
||||
operation_past = 'signature'
|
||||
operation_progressive = 'Signing'
|
||||
key_class = rsa.PrivateKey
|
||||
expected_cli_args = 2
|
||||
|
||||
output_help = ('Name of the file to write the signature to. Written '
|
||||
'to stdout if this option is not present.')
|
||||
|
||||
def perform_operation(self, indata, priv_key, cli_args):
|
||||
'''Decrypts files.'''
|
||||
|
||||
hash_method = cli_args[1]
|
||||
if hash_method not in HASH_METHODS:
|
||||
raise SystemExit('Invalid hash method, choose one of %s' %
|
||||
', '.join(HASH_METHODS))
|
||||
|
||||
return rsa.sign(indata, priv_key, hash_method)
|
||||
|
||||
class VerifyOperation(CryptoOperation):
|
||||
'''Verify a signature.'''
|
||||
|
||||
keyname = 'public'
|
||||
usage = 'usage: %%prog [options] public_key signature_file'
|
||||
description = ('Verifies a signature, exits with status 0 upon success, '
|
||||
'prints an error message and exits with status 1 upon error.')
|
||||
operation = 'verify'
|
||||
operation_past = 'verified'
|
||||
operation_progressive = 'Verifying'
|
||||
key_class = rsa.PublicKey
|
||||
expected_cli_args = 2
|
||||
has_output = False
|
||||
|
||||
def perform_operation(self, indata, pub_key, cli_args):
|
||||
'''Decrypts files.'''
|
||||
|
||||
signature_file = cli_args[1]
|
||||
|
||||
with open(signature_file, 'rb') as sigfile:
|
||||
signature = sigfile.read()
|
||||
|
||||
try:
|
||||
rsa.verify(indata, signature, pub_key)
|
||||
except rsa.VerificationError:
|
||||
raise SystemExit('Verification failed.')
|
||||
|
||||
print('Verification OK', file=sys.stderr)
|
||||
|
||||
|
||||
class BigfileOperation(CryptoOperation):
|
||||
'''CryptoOperation that doesn't read the entire file into memory.'''
|
||||
|
||||
def __init__(self):
|
||||
CryptoOperation.__init__(self)
|
||||
|
||||
self.file_objects = []
|
||||
|
||||
def __del__(self):
|
||||
'''Closes any open file handles.'''
|
||||
|
||||
for fobj in self.file_objects:
|
||||
fobj.close()
|
||||
|
||||
def __call__(self):
|
||||
'''Runs the program.'''
|
||||
|
||||
(cli, cli_args) = self.parse_cli()
|
||||
|
||||
key = self.read_key(cli_args[0], cli.keyform)
|
||||
|
||||
# Get the file handles
|
||||
infile = self.get_infile(cli.input)
|
||||
outfile = self.get_outfile(cli.output)
|
||||
|
||||
# Call the operation
|
||||
print(self.operation_progressive.title(), file=sys.stderr)
|
||||
self.perform_operation(infile, outfile, key, cli_args)
|
||||
|
||||
def get_infile(self, inname):
|
||||
'''Returns the input file object'''
|
||||
|
||||
if inname:
|
||||
print('Reading input from %s' % inname, file=sys.stderr)
|
||||
fobj = open(inname, 'rb')
|
||||
self.file_objects.append(fobj)
|
||||
else:
|
||||
print('Reading input from stdin', file=sys.stderr)
|
||||
fobj = sys.stdin
|
||||
|
||||
return fobj
|
||||
|
||||
def get_outfile(self, outname):
|
||||
'''Returns the output file object'''
|
||||
|
||||
if outname:
|
||||
print('Will write output to %s' % outname, file=sys.stderr)
|
||||
fobj = open(outname, 'wb')
|
||||
self.file_objects.append(fobj)
|
||||
else:
|
||||
print('Will write output to stdout', file=sys.stderr)
|
||||
fobj = sys.stdout
|
||||
|
||||
return fobj
|
||||
|
||||
class EncryptBigfileOperation(BigfileOperation):
|
||||
'''Encrypts a file to VARBLOCK format.'''
|
||||
|
||||
keyname = 'public'
|
||||
description = ('Encrypts a file to an encrypted VARBLOCK file. The file '
|
||||
'can be larger than the key length, but the output file is only '
|
||||
'compatible with Python-RSA.')
|
||||
operation = 'encrypt'
|
||||
operation_past = 'encrypted'
|
||||
operation_progressive = 'encrypting'
|
||||
|
||||
def perform_operation(self, infile, outfile, pub_key, cli_args=None):
|
||||
'''Encrypts files to VARBLOCK.'''
|
||||
|
||||
return rsa.bigfile.encrypt_bigfile(infile, outfile, pub_key)
|
||||
|
||||
class DecryptBigfileOperation(BigfileOperation):
|
||||
'''Decrypts a file in VARBLOCK format.'''
|
||||
|
||||
keyname = 'private'
|
||||
description = ('Decrypts an encrypted VARBLOCK file that was encrypted '
|
||||
'with pyrsa-encrypt-bigfile')
|
||||
operation = 'decrypt'
|
||||
operation_past = 'decrypted'
|
||||
operation_progressive = 'decrypting'
|
||||
key_class = rsa.PrivateKey
|
||||
|
||||
def perform_operation(self, infile, outfile, priv_key, cli_args=None):
|
||||
'''Decrypts a VARBLOCK file.'''
|
||||
|
||||
return rsa.bigfile.decrypt_bigfile(infile, outfile, priv_key)
|
||||
|
||||
|
||||
encrypt = EncryptOperation()
|
||||
decrypt = DecryptOperation()
|
||||
sign = SignOperation()
|
||||
verify = VerifyOperation()
|
||||
encrypt_bigfile = EncryptBigfileOperation()
|
||||
decrypt_bigfile = DecryptBigfileOperation()
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
'''Common functionality shared by several modules.'''
|
||||
|
||||
|
||||
def bit_size(num):
|
||||
'''
|
||||
Number of bits needed to represent a integer excluding any prefix
|
||||
0 bits.
|
||||
|
||||
As per definition from http://wiki.python.org/moin/BitManipulation and
|
||||
to match the behavior of the Python 3 API.
|
||||
|
||||
Usage::
|
||||
|
||||
>>> bit_size(1023)
|
||||
10
|
||||
>>> bit_size(1024)
|
||||
11
|
||||
>>> bit_size(1025)
|
||||
11
|
||||
|
||||
:param num:
|
||||
Integer value. If num is 0, returns 0. Only the absolute value of the
|
||||
number is considered. Therefore, signed integers will be abs(num)
|
||||
before the number's bit length is determined.
|
||||
:returns:
|
||||
Returns the number of bits in the integer.
|
||||
'''
|
||||
if num == 0:
|
||||
return 0
|
||||
if num < 0:
|
||||
num = -num
|
||||
|
||||
# Make sure this is an int and not a float.
|
||||
num & 1
|
||||
|
||||
hex_num = "%x" % num
|
||||
return ((len(hex_num) - 1) * 4) + {
|
||||
'0':0, '1':1, '2':2, '3':2,
|
||||
'4':3, '5':3, '6':3, '7':3,
|
||||
'8':4, '9':4, 'a':4, 'b':4,
|
||||
'c':4, 'd':4, 'e':4, 'f':4,
|
||||
}[hex_num[0]]
|
||||
|
||||
|
||||
def _bit_size(number):
|
||||
'''
|
||||
Returns the number of bits required to hold a specific long number.
|
||||
'''
|
||||
if number < 0:
|
||||
raise ValueError('Only nonnegative numbers possible: %s' % number)
|
||||
|
||||
if number == 0:
|
||||
return 0
|
||||
|
||||
# This works, even with very large numbers. When using math.log(number, 2),
|
||||
# you'll get rounding errors and it'll fail.
|
||||
bits = 0
|
||||
while number:
|
||||
bits += 1
|
||||
number >>= 1
|
||||
|
||||
return bits
|
||||
|
||||
|
||||
def byte_size(number):
|
||||
'''
|
||||
Returns the number of bytes required to hold a specific long number.
|
||||
|
||||
The number of bytes is rounded up.
|
||||
|
||||
Usage::
|
||||
|
||||
>>> byte_size(1 << 1023)
|
||||
128
|
||||
>>> byte_size((1 << 1024) - 1)
|
||||
128
|
||||
>>> byte_size(1 << 1024)
|
||||
129
|
||||
|
||||
:param number:
|
||||
An unsigned integer
|
||||
:returns:
|
||||
The number of bytes required to hold a specific long number.
|
||||
'''
|
||||
quanta, mod = divmod(bit_size(number), 8)
|
||||
if mod or number == 0:
|
||||
quanta += 1
|
||||
return quanta
|
||||
#return int(math.ceil(bit_size(number) / 8.0))
|
||||
|
||||
|
||||
def extended_gcd(a, b):
|
||||
'''Returns a tuple (r, i, j) such that r = gcd(a, b) = ia + jb
|
||||
'''
|
||||
# r = gcd(a,b) i = multiplicitive inverse of a mod b
|
||||
# or j = multiplicitive inverse of b mod a
|
||||
# Neg return values for i or j are made positive mod b or a respectively
|
||||
# Iterateive Version is faster and uses much less stack space
|
||||
x = 0
|
||||
y = 1
|
||||
lx = 1
|
||||
ly = 0
|
||||
oa = a #Remember original a/b to remove
|
||||
ob = b #negative values from return results
|
||||
while b != 0:
|
||||
q = a // b
|
||||
(a, b) = (b, a % b)
|
||||
(x, lx) = ((lx - (q * x)),x)
|
||||
(y, ly) = ((ly - (q * y)),y)
|
||||
if (lx < 0): lx += ob #If neg wrap modulo orignal b
|
||||
if (ly < 0): ly += oa #If neg wrap modulo orignal a
|
||||
return (a, lx, ly) #Return only positive values
|
||||
|
||||
|
||||
def inverse(x, n):
|
||||
'''Returns x^-1 (mod n)
|
||||
|
||||
>>> inverse(7, 4)
|
||||
3
|
||||
>>> (inverse(143, 4) * 143) % 4
|
||||
1
|
||||
'''
|
||||
|
||||
(divider, inv, _) = extended_gcd(x, n)
|
||||
|
||||
if divider != 1:
|
||||
raise ValueError("x (%d) and n (%d) are not relatively prime" % (x, n))
|
||||
|
||||
return inv
|
||||
|
||||
|
||||
def crt(a_values, modulo_values):
|
||||
'''Chinese Remainder Theorem.
|
||||
|
||||
Calculates x such that x = a[i] (mod m[i]) for each i.
|
||||
|
||||
:param a_values: the a-values of the above equation
|
||||
:param modulo_values: the m-values of the above equation
|
||||
:returns: x such that x = a[i] (mod m[i]) for each i
|
||||
|
||||
|
||||
>>> crt([2, 3], [3, 5])
|
||||
8
|
||||
|
||||
>>> crt([2, 3, 2], [3, 5, 7])
|
||||
23
|
||||
|
||||
>>> crt([2, 3, 0], [7, 11, 15])
|
||||
135
|
||||
'''
|
||||
|
||||
m = 1
|
||||
x = 0
|
||||
|
||||
for modulo in modulo_values:
|
||||
m *= modulo
|
||||
|
||||
for (m_i, a_i) in zip(modulo_values, a_values):
|
||||
M_i = m // m_i
|
||||
inv = inverse(M_i, m_i)
|
||||
|
||||
x = (x + a_i * M_i * inv) % m
|
||||
|
||||
return x
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
'''Core mathematical operations.
|
||||
|
||||
This is the actual core RSA implementation, which is only defined
|
||||
mathematically on integers.
|
||||
'''
|
||||
|
||||
|
||||
from rsa._compat import is_integer
|
||||
|
||||
def assert_int(var, name):
|
||||
|
||||
if is_integer(var):
|
||||
return
|
||||
|
||||
raise TypeError('%s should be an integer, not %s' % (name, var.__class__))
|
||||
|
||||
def encrypt_int(message, ekey, n):
|
||||
'''Encrypts a message using encryption key 'ekey', working modulo n'''
|
||||
|
||||
assert_int(message, 'message')
|
||||
assert_int(ekey, 'ekey')
|
||||
assert_int(n, 'n')
|
||||
|
||||
if message < 0:
|
||||
raise ValueError('Only non-negative numbers are supported')
|
||||
|
||||
if message > n:
|
||||
raise OverflowError("The message %i is too long for n=%i" % (message, n))
|
||||
|
||||
return pow(message, ekey, n)
|
||||
|
||||
def decrypt_int(cyphertext, dkey, n):
|
||||
'''Decrypts a cypher text using the decryption key 'dkey', working
|
||||
modulo n'''
|
||||
|
||||
assert_int(cyphertext, 'cyphertext')
|
||||
assert_int(dkey, 'dkey')
|
||||
assert_int(n, 'n')
|
||||
|
||||
message = pow(cyphertext, dkey, n)
|
||||
return message
|
||||
|
||||
@@ -0,0 +1,612 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
'''RSA key generation code.
|
||||
|
||||
Create new keys with the newkeys() function. It will give you a PublicKey and a
|
||||
PrivateKey object.
|
||||
|
||||
Loading and saving keys requires the pyasn1 module. This module is imported as
|
||||
late as possible, such that other functionality will remain working in absence
|
||||
of pyasn1.
|
||||
|
||||
'''
|
||||
|
||||
import logging
|
||||
from rsa._compat import b, bytes_type
|
||||
|
||||
import rsa.prime
|
||||
import rsa.pem
|
||||
import rsa.common
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
class AbstractKey(object):
|
||||
'''Abstract superclass for private and public keys.'''
|
||||
|
||||
@classmethod
|
||||
def load_pkcs1(cls, keyfile, format='PEM'):
|
||||
r'''Loads a key in PKCS#1 DER or PEM format.
|
||||
|
||||
:param keyfile: contents of a DER- or PEM-encoded file that contains
|
||||
the public key.
|
||||
:param format: the format of the file to load; 'PEM' or 'DER'
|
||||
|
||||
:return: a PublicKey object
|
||||
|
||||
'''
|
||||
|
||||
methods = {
|
||||
'PEM': cls._load_pkcs1_pem,
|
||||
'DER': cls._load_pkcs1_der,
|
||||
}
|
||||
|
||||
if format not in methods:
|
||||
formats = ', '.join(sorted(methods.keys()))
|
||||
raise ValueError('Unsupported format: %r, try one of %s' % (format,
|
||||
formats))
|
||||
|
||||
method = methods[format]
|
||||
return method(keyfile)
|
||||
|
||||
def save_pkcs1(self, format='PEM'):
|
||||
'''Saves the public key in PKCS#1 DER or PEM format.
|
||||
|
||||
:param format: the format to save; 'PEM' or 'DER'
|
||||
:returns: the DER- or PEM-encoded public key.
|
||||
|
||||
'''
|
||||
|
||||
methods = {
|
||||
'PEM': self._save_pkcs1_pem,
|
||||
'DER': self._save_pkcs1_der,
|
||||
}
|
||||
|
||||
if format not in methods:
|
||||
formats = ', '.join(sorted(methods.keys()))
|
||||
raise ValueError('Unsupported format: %r, try one of %s' % (format,
|
||||
formats))
|
||||
|
||||
method = methods[format]
|
||||
return method()
|
||||
|
||||
class PublicKey(AbstractKey):
|
||||
'''Represents a public RSA key.
|
||||
|
||||
This key is also known as the 'encryption key'. It contains the 'n' and 'e'
|
||||
values.
|
||||
|
||||
Supports attributes as well as dictionary-like access. Attribute accesss is
|
||||
faster, though.
|
||||
|
||||
>>> PublicKey(5, 3)
|
||||
PublicKey(5, 3)
|
||||
|
||||
>>> key = PublicKey(5, 3)
|
||||
>>> key.n
|
||||
5
|
||||
>>> key['n']
|
||||
5
|
||||
>>> key.e
|
||||
3
|
||||
>>> key['e']
|
||||
3
|
||||
|
||||
'''
|
||||
|
||||
__slots__ = ('n', 'e')
|
||||
|
||||
def __init__(self, n, e):
|
||||
self.n = n
|
||||
self.e = e
|
||||
|
||||
def __getitem__(self, key):
|
||||
return getattr(self, key)
|
||||
|
||||
def __repr__(self):
|
||||
return 'PublicKey(%i, %i)' % (self.n, self.e)
|
||||
|
||||
def __eq__(self, other):
|
||||
if other is None:
|
||||
return False
|
||||
|
||||
if not isinstance(other, PublicKey):
|
||||
return False
|
||||
|
||||
return self.n == other.n and self.e == other.e
|
||||
|
||||
def __ne__(self, other):
|
||||
return not (self == other)
|
||||
|
||||
@classmethod
|
||||
def _load_pkcs1_der(cls, keyfile):
|
||||
r'''Loads a key in PKCS#1 DER format.
|
||||
|
||||
@param keyfile: contents of a DER-encoded file that contains the public
|
||||
key.
|
||||
@return: a PublicKey object
|
||||
|
||||
First let's construct a DER encoded key:
|
||||
|
||||
>>> import base64
|
||||
>>> b64der = 'MAwCBQCNGmYtAgMBAAE='
|
||||
>>> der = base64.decodestring(b64der)
|
||||
|
||||
This loads the file:
|
||||
|
||||
>>> PublicKey._load_pkcs1_der(der)
|
||||
PublicKey(2367317549, 65537)
|
||||
|
||||
'''
|
||||
|
||||
from pyasn1.codec.der import decoder
|
||||
from rsa.asn1 import AsnPubKey
|
||||
|
||||
(priv, _) = decoder.decode(keyfile, asn1Spec=AsnPubKey())
|
||||
return cls(n=int(priv['modulus']), e=int(priv['publicExponent']))
|
||||
|
||||
def _save_pkcs1_der(self):
|
||||
'''Saves the public key in PKCS#1 DER format.
|
||||
|
||||
@returns: the DER-encoded public key.
|
||||
'''
|
||||
|
||||
from pyasn1.codec.der import encoder
|
||||
from rsa.asn1 import AsnPubKey
|
||||
|
||||
# Create the ASN object
|
||||
asn_key = AsnPubKey()
|
||||
asn_key.setComponentByName('modulus', self.n)
|
||||
asn_key.setComponentByName('publicExponent', self.e)
|
||||
|
||||
return encoder.encode(asn_key)
|
||||
|
||||
@classmethod
|
||||
def _load_pkcs1_pem(cls, keyfile):
|
||||
'''Loads a PKCS#1 PEM-encoded public key file.
|
||||
|
||||
The contents of the file before the "-----BEGIN RSA PUBLIC KEY-----" and
|
||||
after the "-----END RSA PUBLIC KEY-----" lines is ignored.
|
||||
|
||||
@param keyfile: contents of a PEM-encoded file that contains the public
|
||||
key.
|
||||
@return: a PublicKey object
|
||||
'''
|
||||
|
||||
der = rsa.pem.load_pem(keyfile, 'RSA PUBLIC KEY')
|
||||
return cls._load_pkcs1_der(der)
|
||||
|
||||
def _save_pkcs1_pem(self):
|
||||
'''Saves a PKCS#1 PEM-encoded public key file.
|
||||
|
||||
@return: contents of a PEM-encoded file that contains the public key.
|
||||
'''
|
||||
|
||||
der = self._save_pkcs1_der()
|
||||
return rsa.pem.save_pem(der, 'RSA PUBLIC KEY')
|
||||
|
||||
@classmethod
|
||||
def load_pkcs1_openssl_pem(cls, keyfile):
|
||||
'''Loads a PKCS#1.5 PEM-encoded public key file from OpenSSL.
|
||||
|
||||
These files can be recognised in that they start with BEGIN PUBLIC KEY
|
||||
rather than BEGIN RSA PUBLIC KEY.
|
||||
|
||||
The contents of the file before the "-----BEGIN PUBLIC KEY-----" and
|
||||
after the "-----END PUBLIC KEY-----" lines is ignored.
|
||||
|
||||
@param keyfile: contents of a PEM-encoded file that contains the public
|
||||
key, from OpenSSL.
|
||||
@return: a PublicKey object
|
||||
'''
|
||||
|
||||
der = rsa.pem.load_pem(keyfile, 'PUBLIC KEY')
|
||||
return cls.load_pkcs1_openssl_der(der)
|
||||
|
||||
@classmethod
|
||||
def load_pkcs1_openssl_der(cls, keyfile):
|
||||
'''Loads a PKCS#1 DER-encoded public key file from OpenSSL.
|
||||
|
||||
@param keyfile: contents of a DER-encoded file that contains the public
|
||||
key, from OpenSSL.
|
||||
@return: a PublicKey object
|
||||
'''
|
||||
|
||||
from rsa.asn1 import OpenSSLPubKey
|
||||
from pyasn1.codec.der import decoder
|
||||
from pyasn1.type import univ
|
||||
|
||||
(keyinfo, _) = decoder.decode(keyfile, asn1Spec=OpenSSLPubKey())
|
||||
|
||||
if keyinfo['header']['oid'] != univ.ObjectIdentifier('1.2.840.113549.1.1.1'):
|
||||
raise TypeError("This is not a DER-encoded OpenSSL-compatible public key")
|
||||
|
||||
return cls._load_pkcs1_der(keyinfo['key'][1:])
|
||||
|
||||
|
||||
|
||||
|
||||
class PrivateKey(AbstractKey):
|
||||
'''Represents a private RSA key.
|
||||
|
||||
This key is also known as the 'decryption key'. It contains the 'n', 'e',
|
||||
'd', 'p', 'q' and other values.
|
||||
|
||||
Supports attributes as well as dictionary-like access. Attribute accesss is
|
||||
faster, though.
|
||||
|
||||
>>> PrivateKey(3247, 65537, 833, 191, 17)
|
||||
PrivateKey(3247, 65537, 833, 191, 17)
|
||||
|
||||
exp1, exp2 and coef don't have to be given, they will be calculated:
|
||||
|
||||
>>> pk = PrivateKey(3727264081, 65537, 3349121513, 65063, 57287)
|
||||
>>> pk.exp1
|
||||
55063
|
||||
>>> pk.exp2
|
||||
10095
|
||||
>>> pk.coef
|
||||
50797
|
||||
|
||||
If you give exp1, exp2 or coef, they will be used as-is:
|
||||
|
||||
>>> pk = PrivateKey(1, 2, 3, 4, 5, 6, 7, 8)
|
||||
>>> pk.exp1
|
||||
6
|
||||
>>> pk.exp2
|
||||
7
|
||||
>>> pk.coef
|
||||
8
|
||||
|
||||
'''
|
||||
|
||||
__slots__ = ('n', 'e', 'd', 'p', 'q', 'exp1', 'exp2', 'coef')
|
||||
|
||||
def __init__(self, n, e, d, p, q, exp1=None, exp2=None, coef=None):
|
||||
self.n = n
|
||||
self.e = e
|
||||
self.d = d
|
||||
self.p = p
|
||||
self.q = q
|
||||
|
||||
# Calculate the other values if they aren't supplied
|
||||
if exp1 is None:
|
||||
self.exp1 = int(d % (p - 1))
|
||||
else:
|
||||
self.exp1 = exp1
|
||||
|
||||
if exp1 is None:
|
||||
self.exp2 = int(d % (q - 1))
|
||||
else:
|
||||
self.exp2 = exp2
|
||||
|
||||
if coef is None:
|
||||
self.coef = rsa.common.inverse(q, p)
|
||||
else:
|
||||
self.coef = coef
|
||||
|
||||
def __getitem__(self, key):
|
||||
return getattr(self, key)
|
||||
|
||||
def __repr__(self):
|
||||
return 'PrivateKey(%(n)i, %(e)i, %(d)i, %(p)i, %(q)i)' % self
|
||||
|
||||
def __eq__(self, other):
|
||||
if other is None:
|
||||
return False
|
||||
|
||||
if not isinstance(other, PrivateKey):
|
||||
return False
|
||||
|
||||
return (self.n == other.n and
|
||||
self.e == other.e and
|
||||
self.d == other.d and
|
||||
self.p == other.p and
|
||||
self.q == other.q and
|
||||
self.exp1 == other.exp1 and
|
||||
self.exp2 == other.exp2 and
|
||||
self.coef == other.coef)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not (self == other)
|
||||
|
||||
@classmethod
|
||||
def _load_pkcs1_der(cls, keyfile):
|
||||
r'''Loads a key in PKCS#1 DER format.
|
||||
|
||||
@param keyfile: contents of a DER-encoded file that contains the private
|
||||
key.
|
||||
@return: a PrivateKey object
|
||||
|
||||
First let's construct a DER encoded key:
|
||||
|
||||
>>> import base64
|
||||
>>> b64der = 'MC4CAQACBQDeKYlRAgMBAAECBQDHn4npAgMA/icCAwDfxwIDANcXAgInbwIDAMZt'
|
||||
>>> der = base64.decodestring(b64der)
|
||||
|
||||
This loads the file:
|
||||
|
||||
>>> PrivateKey._load_pkcs1_der(der)
|
||||
PrivateKey(3727264081, 65537, 3349121513, 65063, 57287)
|
||||
|
||||
'''
|
||||
|
||||
from pyasn1.codec.der import decoder
|
||||
(priv, _) = decoder.decode(keyfile)
|
||||
|
||||
# ASN.1 contents of DER encoded private key:
|
||||
#
|
||||
# RSAPrivateKey ::= SEQUENCE {
|
||||
# version Version,
|
||||
# modulus INTEGER, -- n
|
||||
# publicExponent INTEGER, -- e
|
||||
# privateExponent INTEGER, -- d
|
||||
# prime1 INTEGER, -- p
|
||||
# prime2 INTEGER, -- q
|
||||
# exponent1 INTEGER, -- d mod (p-1)
|
||||
# exponent2 INTEGER, -- d mod (q-1)
|
||||
# coefficient INTEGER, -- (inverse of q) mod p
|
||||
# otherPrimeInfos OtherPrimeInfos OPTIONAL
|
||||
# }
|
||||
|
||||
if priv[0] != 0:
|
||||
raise ValueError('Unable to read this file, version %s != 0' % priv[0])
|
||||
|
||||
as_ints = tuple(int(x) for x in priv[1:9])
|
||||
return cls(*as_ints)
|
||||
|
||||
def _save_pkcs1_der(self):
|
||||
'''Saves the private key in PKCS#1 DER format.
|
||||
|
||||
@returns: the DER-encoded private key.
|
||||
'''
|
||||
|
||||
from pyasn1.type import univ, namedtype
|
||||
from pyasn1.codec.der import encoder
|
||||
|
||||
class AsnPrivKey(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('version', univ.Integer()),
|
||||
namedtype.NamedType('modulus', univ.Integer()),
|
||||
namedtype.NamedType('publicExponent', univ.Integer()),
|
||||
namedtype.NamedType('privateExponent', univ.Integer()),
|
||||
namedtype.NamedType('prime1', univ.Integer()),
|
||||
namedtype.NamedType('prime2', univ.Integer()),
|
||||
namedtype.NamedType('exponent1', univ.Integer()),
|
||||
namedtype.NamedType('exponent2', univ.Integer()),
|
||||
namedtype.NamedType('coefficient', univ.Integer()),
|
||||
)
|
||||
|
||||
# Create the ASN object
|
||||
asn_key = AsnPrivKey()
|
||||
asn_key.setComponentByName('version', 0)
|
||||
asn_key.setComponentByName('modulus', self.n)
|
||||
asn_key.setComponentByName('publicExponent', self.e)
|
||||
asn_key.setComponentByName('privateExponent', self.d)
|
||||
asn_key.setComponentByName('prime1', self.p)
|
||||
asn_key.setComponentByName('prime2', self.q)
|
||||
asn_key.setComponentByName('exponent1', self.exp1)
|
||||
asn_key.setComponentByName('exponent2', self.exp2)
|
||||
asn_key.setComponentByName('coefficient', self.coef)
|
||||
|
||||
return encoder.encode(asn_key)
|
||||
|
||||
@classmethod
|
||||
def _load_pkcs1_pem(cls, keyfile):
|
||||
'''Loads a PKCS#1 PEM-encoded private key file.
|
||||
|
||||
The contents of the file before the "-----BEGIN RSA PRIVATE KEY-----" and
|
||||
after the "-----END RSA PRIVATE KEY-----" lines is ignored.
|
||||
|
||||
@param keyfile: contents of a PEM-encoded file that contains the private
|
||||
key.
|
||||
@return: a PrivateKey object
|
||||
'''
|
||||
|
||||
der = rsa.pem.load_pem(keyfile, b('RSA PRIVATE KEY'))
|
||||
return cls._load_pkcs1_der(der)
|
||||
|
||||
def _save_pkcs1_pem(self):
|
||||
'''Saves a PKCS#1 PEM-encoded private key file.
|
||||
|
||||
@return: contents of a PEM-encoded file that contains the private key.
|
||||
'''
|
||||
|
||||
der = self._save_pkcs1_der()
|
||||
return rsa.pem.save_pem(der, b('RSA PRIVATE KEY'))
|
||||
|
||||
def find_p_q(nbits, getprime_func=rsa.prime.getprime, accurate=True):
|
||||
''''Returns a tuple of two different primes of nbits bits each.
|
||||
|
||||
The resulting p * q has exacty 2 * nbits bits, and the returned p and q
|
||||
will not be equal.
|
||||
|
||||
:param nbits: the number of bits in each of p and q.
|
||||
:param getprime_func: the getprime function, defaults to
|
||||
:py:func:`rsa.prime.getprime`.
|
||||
|
||||
*Introduced in Python-RSA 3.1*
|
||||
|
||||
:param accurate: whether to enable accurate mode or not.
|
||||
:returns: (p, q), where p > q
|
||||
|
||||
>>> (p, q) = find_p_q(128)
|
||||
>>> from rsa import common
|
||||
>>> common.bit_size(p * q)
|
||||
256
|
||||
|
||||
When not in accurate mode, the number of bits can be slightly less
|
||||
|
||||
>>> (p, q) = find_p_q(128, accurate=False)
|
||||
>>> from rsa import common
|
||||
>>> common.bit_size(p * q) <= 256
|
||||
True
|
||||
>>> common.bit_size(p * q) > 240
|
||||
True
|
||||
|
||||
'''
|
||||
|
||||
total_bits = nbits * 2
|
||||
|
||||
# Make sure that p and q aren't too close or the factoring programs can
|
||||
# factor n.
|
||||
shift = nbits // 16
|
||||
pbits = nbits + shift
|
||||
qbits = nbits - shift
|
||||
|
||||
# Choose the two initial primes
|
||||
log.debug('find_p_q(%i): Finding p', nbits)
|
||||
p = getprime_func(pbits)
|
||||
log.debug('find_p_q(%i): Finding q', nbits)
|
||||
q = getprime_func(qbits)
|
||||
|
||||
def is_acceptable(p, q):
|
||||
'''Returns True iff p and q are acceptable:
|
||||
|
||||
- p and q differ
|
||||
- (p * q) has the right nr of bits (when accurate=True)
|
||||
'''
|
||||
|
||||
if p == q:
|
||||
return False
|
||||
|
||||
if not accurate:
|
||||
return True
|
||||
|
||||
# Make sure we have just the right amount of bits
|
||||
found_size = rsa.common.bit_size(p * q)
|
||||
return total_bits == found_size
|
||||
|
||||
# Keep choosing other primes until they match our requirements.
|
||||
change_p = False
|
||||
while not is_acceptable(p, q):
|
||||
# Change p on one iteration and q on the other
|
||||
if change_p:
|
||||
p = getprime_func(pbits)
|
||||
else:
|
||||
q = getprime_func(qbits)
|
||||
|
||||
change_p = not change_p
|
||||
|
||||
# We want p > q as described on
|
||||
# http://www.di-mgt.com.au/rsa_alg.html#crt
|
||||
return (max(p, q), min(p, q))
|
||||
|
||||
def calculate_keys(p, q, nbits):
|
||||
'''Calculates an encryption and a decryption key given p and q, and
|
||||
returns them as a tuple (e, d)
|
||||
|
||||
'''
|
||||
|
||||
phi_n = (p - 1) * (q - 1)
|
||||
|
||||
# A very common choice for e is 65537
|
||||
e = 65537
|
||||
|
||||
try:
|
||||
d = rsa.common.inverse(e, phi_n)
|
||||
except ValueError:
|
||||
raise ValueError("e (%d) and phi_n (%d) are not relatively prime" %
|
||||
(e, phi_n))
|
||||
|
||||
if (e * d) % phi_n != 1:
|
||||
raise ValueError("e (%d) and d (%d) are not mult. inv. modulo "
|
||||
"phi_n (%d)" % (e, d, phi_n))
|
||||
|
||||
return (e, d)
|
||||
|
||||
def gen_keys(nbits, getprime_func, accurate=True):
|
||||
'''Generate RSA keys of nbits bits. Returns (p, q, e, d).
|
||||
|
||||
Note: this can take a long time, depending on the key size.
|
||||
|
||||
:param nbits: the total number of bits in ``p`` and ``q``. Both ``p`` and
|
||||
``q`` will use ``nbits/2`` bits.
|
||||
:param getprime_func: either :py:func:`rsa.prime.getprime` or a function
|
||||
with similar signature.
|
||||
'''
|
||||
|
||||
(p, q) = find_p_q(nbits // 2, getprime_func, accurate)
|
||||
(e, d) = calculate_keys(p, q, nbits // 2)
|
||||
|
||||
return (p, q, e, d)
|
||||
|
||||
def newkeys(nbits, accurate=True, poolsize=1):
|
||||
'''Generates public and private keys, and returns them as (pub, priv).
|
||||
|
||||
The public key is also known as the 'encryption key', and is a
|
||||
:py:class:`rsa.PublicKey` object. The private key is also known as the
|
||||
'decryption key' and is a :py:class:`rsa.PrivateKey` object.
|
||||
|
||||
:param nbits: the number of bits required to store ``n = p*q``.
|
||||
:param accurate: when True, ``n`` will have exactly the number of bits you
|
||||
asked for. However, this makes key generation much slower. When False,
|
||||
`n`` may have slightly less bits.
|
||||
:param poolsize: the number of processes to use to generate the prime
|
||||
numbers. If set to a number > 1, a parallel algorithm will be used.
|
||||
This requires Python 2.6 or newer.
|
||||
|
||||
:returns: a tuple (:py:class:`rsa.PublicKey`, :py:class:`rsa.PrivateKey`)
|
||||
|
||||
The ``poolsize`` parameter was added in *Python-RSA 3.1* and requires
|
||||
Python 2.6 or newer.
|
||||
|
||||
'''
|
||||
|
||||
if nbits < 16:
|
||||
raise ValueError('Key too small')
|
||||
|
||||
if poolsize < 1:
|
||||
raise ValueError('Pool size (%i) should be >= 1' % poolsize)
|
||||
|
||||
# Determine which getprime function to use
|
||||
if poolsize > 1:
|
||||
from rsa import parallel
|
||||
import functools
|
||||
|
||||
getprime_func = functools.partial(parallel.getprime, poolsize=poolsize)
|
||||
else: getprime_func = rsa.prime.getprime
|
||||
|
||||
# Generate the key components
|
||||
(p, q, e, d) = gen_keys(nbits, getprime_func)
|
||||
|
||||
# Create the key objects
|
||||
n = p * q
|
||||
|
||||
return (
|
||||
PublicKey(n, e),
|
||||
PrivateKey(n, e, d, p, q)
|
||||
)
|
||||
|
||||
__all__ = ['PublicKey', 'PrivateKey', 'newkeys']
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
|
||||
try:
|
||||
for count in range(100):
|
||||
(failures, tests) = doctest.testmod()
|
||||
if failures:
|
||||
break
|
||||
|
||||
if (count and count % 10 == 0) or count == 1:
|
||||
print('%i times' % count)
|
||||
except KeyboardInterrupt:
|
||||
print('Aborted')
|
||||
else:
|
||||
print('Doctests done')
|
||||
@@ -0,0 +1,94 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
'''Functions for parallel computation on multiple cores.
|
||||
|
||||
Introduced in Python-RSA 3.1.
|
||||
|
||||
.. note::
|
||||
|
||||
Requires Python 2.6 or newer.
|
||||
|
||||
'''
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import multiprocessing as mp
|
||||
|
||||
import rsa.prime
|
||||
import rsa.randnum
|
||||
|
||||
def _find_prime(nbits, pipe):
|
||||
while True:
|
||||
integer = rsa.randnum.read_random_int(nbits)
|
||||
|
||||
# Make sure it's odd
|
||||
integer |= 1
|
||||
|
||||
# Test for primeness
|
||||
if rsa.prime.is_prime(integer):
|
||||
pipe.send(integer)
|
||||
return
|
||||
|
||||
def getprime(nbits, poolsize):
|
||||
'''Returns a prime number that can be stored in 'nbits' bits.
|
||||
|
||||
Works in multiple threads at the same time.
|
||||
|
||||
>>> p = getprime(128, 3)
|
||||
>>> rsa.prime.is_prime(p-1)
|
||||
False
|
||||
>>> rsa.prime.is_prime(p)
|
||||
True
|
||||
>>> rsa.prime.is_prime(p+1)
|
||||
False
|
||||
|
||||
>>> from rsa import common
|
||||
>>> common.bit_size(p) == 128
|
||||
True
|
||||
|
||||
'''
|
||||
|
||||
(pipe_recv, pipe_send) = mp.Pipe(duplex=False)
|
||||
|
||||
# Create processes
|
||||
procs = [mp.Process(target=_find_prime, args=(nbits, pipe_send))
|
||||
for _ in range(poolsize)]
|
||||
[p.start() for p in procs]
|
||||
|
||||
result = pipe_recv.recv()
|
||||
|
||||
[p.terminate() for p in procs]
|
||||
|
||||
return result
|
||||
|
||||
__all__ = ['getprime']
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('Running doctests 1000x or until failure')
|
||||
import doctest
|
||||
|
||||
for count in range(100):
|
||||
(failures, tests) = doctest.testmod()
|
||||
if failures:
|
||||
break
|
||||
|
||||
if count and count % 10 == 0:
|
||||
print('%i times' % count)
|
||||
|
||||
print('Doctests done')
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
'''Functions that load and write PEM-encoded files.'''
|
||||
|
||||
import base64
|
||||
from rsa._compat import b, is_bytes
|
||||
|
||||
def _markers(pem_marker):
|
||||
'''
|
||||
Returns the start and end PEM markers
|
||||
'''
|
||||
|
||||
if is_bytes(pem_marker):
|
||||
pem_marker = pem_marker.decode('utf-8')
|
||||
|
||||
return (b('-----BEGIN %s-----' % pem_marker),
|
||||
b('-----END %s-----' % pem_marker))
|
||||
|
||||
def load_pem(contents, pem_marker):
|
||||
'''Loads a PEM file.
|
||||
|
||||
@param contents: the contents of the file to interpret
|
||||
@param pem_marker: the marker of the PEM content, such as 'RSA PRIVATE KEY'
|
||||
when your file has '-----BEGIN RSA PRIVATE KEY-----' and
|
||||
'-----END RSA PRIVATE KEY-----' markers.
|
||||
|
||||
@return the base64-decoded content between the start and end markers.
|
||||
|
||||
@raise ValueError: when the content is invalid, for example when the start
|
||||
marker cannot be found.
|
||||
|
||||
'''
|
||||
|
||||
(pem_start, pem_end) = _markers(pem_marker)
|
||||
|
||||
pem_lines = []
|
||||
in_pem_part = False
|
||||
|
||||
for line in contents.splitlines():
|
||||
line = line.strip()
|
||||
|
||||
# Skip empty lines
|
||||
if not line:
|
||||
continue
|
||||
|
||||
# Handle start marker
|
||||
if line == pem_start:
|
||||
if in_pem_part:
|
||||
raise ValueError('Seen start marker "%s" twice' % pem_start)
|
||||
|
||||
in_pem_part = True
|
||||
continue
|
||||
|
||||
# Skip stuff before first marker
|
||||
if not in_pem_part:
|
||||
continue
|
||||
|
||||
# Handle end marker
|
||||
if in_pem_part and line == pem_end:
|
||||
in_pem_part = False
|
||||
break
|
||||
|
||||
# Load fields
|
||||
if b(':') in line:
|
||||
continue
|
||||
|
||||
pem_lines.append(line)
|
||||
|
||||
# Do some sanity checks
|
||||
if not pem_lines:
|
||||
raise ValueError('No PEM start marker "%s" found' % pem_start)
|
||||
|
||||
if in_pem_part:
|
||||
raise ValueError('No PEM end marker "%s" found' % pem_end)
|
||||
|
||||
# Base64-decode the contents
|
||||
pem = b('').join(pem_lines)
|
||||
return base64.decodestring(pem)
|
||||
|
||||
|
||||
def save_pem(contents, pem_marker):
|
||||
'''Saves a PEM file.
|
||||
|
||||
@param contents: the contents to encode in PEM format
|
||||
@param pem_marker: the marker of the PEM content, such as 'RSA PRIVATE KEY'
|
||||
when your file has '-----BEGIN RSA PRIVATE KEY-----' and
|
||||
'-----END RSA PRIVATE KEY-----' markers.
|
||||
|
||||
@return the base64-encoded content between the start and end markers.
|
||||
|
||||
'''
|
||||
|
||||
(pem_start, pem_end) = _markers(pem_marker)
|
||||
|
||||
b64 = base64.encodestring(contents).replace(b('\n'), b(''))
|
||||
pem_lines = [pem_start]
|
||||
|
||||
for block_start in range(0, len(b64), 64):
|
||||
block = b64[block_start:block_start + 64]
|
||||
pem_lines.append(block)
|
||||
|
||||
pem_lines.append(pem_end)
|
||||
pem_lines.append(b(''))
|
||||
|
||||
return b('\n').join(pem_lines)
|
||||
|
||||
@@ -0,0 +1,391 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
'''Functions for PKCS#1 version 1.5 encryption and signing
|
||||
|
||||
This module implements certain functionality from PKCS#1 version 1.5. For a
|
||||
very clear example, read http://www.di-mgt.com.au/rsa_alg.html#pkcs1schemes
|
||||
|
||||
At least 8 bytes of random padding is used when encrypting a message. This makes
|
||||
these methods much more secure than the ones in the ``rsa`` module.
|
||||
|
||||
WARNING: this module leaks information when decryption or verification fails.
|
||||
The exceptions that are raised contain the Python traceback information, which
|
||||
can be used to deduce where in the process the failure occurred. DO NOT PASS
|
||||
SUCH INFORMATION to your users.
|
||||
'''
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
|
||||
from rsa._compat import b
|
||||
from rsa import common, transform, core, varblock
|
||||
|
||||
# ASN.1 codes that describe the hash algorithm used.
|
||||
HASH_ASN1 = {
|
||||
'MD5': b('\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05\x05\x00\x04\x10'),
|
||||
'SHA-1': b('\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14'),
|
||||
'SHA-256': b('\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20'),
|
||||
'SHA-384': b('\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00\x04\x30'),
|
||||
'SHA-512': b('\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40'),
|
||||
}
|
||||
|
||||
HASH_METHODS = {
|
||||
'MD5': hashlib.md5,
|
||||
'SHA-1': hashlib.sha1,
|
||||
'SHA-256': hashlib.sha256,
|
||||
'SHA-384': hashlib.sha384,
|
||||
'SHA-512': hashlib.sha512,
|
||||
}
|
||||
|
||||
class CryptoError(Exception):
|
||||
'''Base class for all exceptions in this module.'''
|
||||
|
||||
class DecryptionError(CryptoError):
|
||||
'''Raised when decryption fails.'''
|
||||
|
||||
class VerificationError(CryptoError):
|
||||
'''Raised when verification fails.'''
|
||||
|
||||
def _pad_for_encryption(message, target_length):
|
||||
r'''Pads the message for encryption, returning the padded message.
|
||||
|
||||
:return: 00 02 RANDOM_DATA 00 MESSAGE
|
||||
|
||||
>>> block = _pad_for_encryption('hello', 16)
|
||||
>>> len(block)
|
||||
16
|
||||
>>> block[0:2]
|
||||
'\x00\x02'
|
||||
>>> block[-6:]
|
||||
'\x00hello'
|
||||
|
||||
'''
|
||||
|
||||
max_msglength = target_length - 11
|
||||
msglength = len(message)
|
||||
|
||||
if msglength > max_msglength:
|
||||
raise OverflowError('%i bytes needed for message, but there is only'
|
||||
' space for %i' % (msglength, max_msglength))
|
||||
|
||||
# Get random padding
|
||||
padding = b('')
|
||||
padding_length = target_length - msglength - 3
|
||||
|
||||
# We remove 0-bytes, so we'll end up with less padding than we've asked for,
|
||||
# so keep adding data until we're at the correct length.
|
||||
while len(padding) < padding_length:
|
||||
needed_bytes = padding_length - len(padding)
|
||||
|
||||
# Always read at least 8 bytes more than we need, and trim off the rest
|
||||
# after removing the 0-bytes. This increases the chance of getting
|
||||
# enough bytes, especially when needed_bytes is small
|
||||
new_padding = os.urandom(needed_bytes + 5)
|
||||
new_padding = new_padding.replace(b('\x00'), b(''))
|
||||
padding = padding + new_padding[:needed_bytes]
|
||||
|
||||
assert len(padding) == padding_length
|
||||
|
||||
return b('').join([b('\x00\x02'),
|
||||
padding,
|
||||
b('\x00'),
|
||||
message])
|
||||
|
||||
|
||||
def _pad_for_signing(message, target_length):
|
||||
r'''Pads the message for signing, returning the padded message.
|
||||
|
||||
The padding is always a repetition of FF bytes.
|
||||
|
||||
:return: 00 01 PADDING 00 MESSAGE
|
||||
|
||||
>>> block = _pad_for_signing('hello', 16)
|
||||
>>> len(block)
|
||||
16
|
||||
>>> block[0:2]
|
||||
'\x00\x01'
|
||||
>>> block[-6:]
|
||||
'\x00hello'
|
||||
>>> block[2:-6]
|
||||
'\xff\xff\xff\xff\xff\xff\xff\xff'
|
||||
|
||||
'''
|
||||
|
||||
max_msglength = target_length - 11
|
||||
msglength = len(message)
|
||||
|
||||
if msglength > max_msglength:
|
||||
raise OverflowError('%i bytes needed for message, but there is only'
|
||||
' space for %i' % (msglength, max_msglength))
|
||||
|
||||
padding_length = target_length - msglength - 3
|
||||
|
||||
return b('').join([b('\x00\x01'),
|
||||
padding_length * b('\xff'),
|
||||
b('\x00'),
|
||||
message])
|
||||
|
||||
|
||||
def encrypt(message, pub_key):
|
||||
'''Encrypts the given message using PKCS#1 v1.5
|
||||
|
||||
:param message: the message to encrypt. Must be a byte string no longer than
|
||||
``k-11`` bytes, where ``k`` is the number of bytes needed to encode
|
||||
the ``n`` component of the public key.
|
||||
:param pub_key: the :py:class:`rsa.PublicKey` to encrypt with.
|
||||
:raise OverflowError: when the message is too large to fit in the padded
|
||||
block.
|
||||
|
||||
>>> from rsa import key, common
|
||||
>>> (pub_key, priv_key) = key.newkeys(256)
|
||||
>>> message = 'hello'
|
||||
>>> crypto = encrypt(message, pub_key)
|
||||
|
||||
The crypto text should be just as long as the public key 'n' component:
|
||||
|
||||
>>> len(crypto) == common.byte_size(pub_key.n)
|
||||
True
|
||||
|
||||
'''
|
||||
|
||||
keylength = common.byte_size(pub_key.n)
|
||||
padded = _pad_for_encryption(message, keylength)
|
||||
|
||||
payload = transform.bytes2int(padded)
|
||||
encrypted = core.encrypt_int(payload, pub_key.e, pub_key.n)
|
||||
block = transform.int2bytes(encrypted, keylength)
|
||||
|
||||
return block
|
||||
|
||||
def decrypt(crypto, priv_key):
|
||||
r'''Decrypts the given message using PKCS#1 v1.5
|
||||
|
||||
The decryption is considered 'failed' when the resulting cleartext doesn't
|
||||
start with the bytes 00 02, or when the 00 byte between the padding and
|
||||
the message cannot be found.
|
||||
|
||||
:param crypto: the crypto text as returned by :py:func:`rsa.encrypt`
|
||||
:param priv_key: the :py:class:`rsa.PrivateKey` to decrypt with.
|
||||
:raise DecryptionError: when the decryption fails. No details are given as
|
||||
to why the code thinks the decryption fails, as this would leak
|
||||
information about the private key.
|
||||
|
||||
|
||||
>>> import rsa
|
||||
>>> (pub_key, priv_key) = rsa.newkeys(256)
|
||||
|
||||
It works with strings:
|
||||
|
||||
>>> crypto = encrypt('hello', pub_key)
|
||||
>>> decrypt(crypto, priv_key)
|
||||
'hello'
|
||||
|
||||
And with binary data:
|
||||
|
||||
>>> crypto = encrypt('\x00\x00\x00\x00\x01', pub_key)
|
||||
>>> decrypt(crypto, priv_key)
|
||||
'\x00\x00\x00\x00\x01'
|
||||
|
||||
Altering the encrypted information will *likely* cause a
|
||||
:py:class:`rsa.pkcs1.DecryptionError`. If you want to be *sure*, use
|
||||
:py:func:`rsa.sign`.
|
||||
|
||||
|
||||
.. warning::
|
||||
|
||||
Never display the stack trace of a
|
||||
:py:class:`rsa.pkcs1.DecryptionError` exception. It shows where in the
|
||||
code the exception occurred, and thus leaks information about the key.
|
||||
It's only a tiny bit of information, but every bit makes cracking the
|
||||
keys easier.
|
||||
|
||||
>>> crypto = encrypt('hello', pub_key)
|
||||
>>> crypto = crypto[0:5] + 'X' + crypto[6:] # change a byte
|
||||
>>> decrypt(crypto, priv_key)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
DecryptionError: Decryption failed
|
||||
|
||||
'''
|
||||
|
||||
blocksize = common.byte_size(priv_key.n)
|
||||
encrypted = transform.bytes2int(crypto)
|
||||
decrypted = core.decrypt_int(encrypted, priv_key.d, priv_key.n)
|
||||
cleartext = transform.int2bytes(decrypted, blocksize)
|
||||
|
||||
# If we can't find the cleartext marker, decryption failed.
|
||||
if cleartext[0:2] != b('\x00\x02'):
|
||||
raise DecryptionError('Decryption failed')
|
||||
|
||||
# Find the 00 separator between the padding and the message
|
||||
try:
|
||||
sep_idx = cleartext.index(b('\x00'), 2)
|
||||
except ValueError:
|
||||
raise DecryptionError('Decryption failed')
|
||||
|
||||
return cleartext[sep_idx+1:]
|
||||
|
||||
def sign(message, priv_key, hash):
|
||||
'''Signs the message with the private key.
|
||||
|
||||
Hashes the message, then signs the hash with the given key. This is known
|
||||
as a "detached signature", because the message itself isn't altered.
|
||||
|
||||
:param message: the message to sign. Can be an 8-bit string or a file-like
|
||||
object. If ``message`` has a ``read()`` method, it is assumed to be a
|
||||
file-like object.
|
||||
:param priv_key: the :py:class:`rsa.PrivateKey` to sign with
|
||||
:param hash: the hash method used on the message. Use 'MD5', 'SHA-1',
|
||||
'SHA-256', 'SHA-384' or 'SHA-512'.
|
||||
:return: a message signature block.
|
||||
:raise OverflowError: if the private key is too small to contain the
|
||||
requested hash.
|
||||
|
||||
'''
|
||||
|
||||
# Get the ASN1 code for this hash method
|
||||
if hash not in HASH_ASN1:
|
||||
raise ValueError('Invalid hash method: %s' % hash)
|
||||
asn1code = HASH_ASN1[hash]
|
||||
|
||||
# Calculate the hash
|
||||
hash = _hash(message, hash)
|
||||
|
||||
# Encrypt the hash with the private key
|
||||
cleartext = asn1code + hash
|
||||
keylength = common.byte_size(priv_key.n)
|
||||
padded = _pad_for_signing(cleartext, keylength)
|
||||
|
||||
payload = transform.bytes2int(padded)
|
||||
encrypted = core.encrypt_int(payload, priv_key.d, priv_key.n)
|
||||
block = transform.int2bytes(encrypted, keylength)
|
||||
|
||||
return block
|
||||
|
||||
def verify(message, signature, pub_key):
|
||||
'''Verifies that the signature matches the message.
|
||||
|
||||
The hash method is detected automatically from the signature.
|
||||
|
||||
:param message: the signed message. Can be an 8-bit string or a file-like
|
||||
object. If ``message`` has a ``read()`` method, it is assumed to be a
|
||||
file-like object.
|
||||
:param signature: the signature block, as created with :py:func:`rsa.sign`.
|
||||
:param pub_key: the :py:class:`rsa.PublicKey` of the person signing the message.
|
||||
:raise VerificationError: when the signature doesn't match the message.
|
||||
|
||||
.. warning::
|
||||
|
||||
Never display the stack trace of a
|
||||
:py:class:`rsa.pkcs1.VerificationError` exception. It shows where in
|
||||
the code the exception occurred, and thus leaks information about the
|
||||
key. It's only a tiny bit of information, but every bit makes cracking
|
||||
the keys easier.
|
||||
|
||||
'''
|
||||
|
||||
blocksize = common.byte_size(pub_key.n)
|
||||
encrypted = transform.bytes2int(signature)
|
||||
decrypted = core.decrypt_int(encrypted, pub_key.e, pub_key.n)
|
||||
clearsig = transform.int2bytes(decrypted, blocksize)
|
||||
|
||||
# If we can't find the signature marker, verification failed.
|
||||
if clearsig[0:2] != b('\x00\x01'):
|
||||
raise VerificationError('Verification failed')
|
||||
|
||||
# Find the 00 separator between the padding and the payload
|
||||
try:
|
||||
sep_idx = clearsig.index(b('\x00'), 2)
|
||||
except ValueError:
|
||||
raise VerificationError('Verification failed')
|
||||
|
||||
# Get the hash and the hash method
|
||||
(method_name, signature_hash) = _find_method_hash(clearsig[sep_idx+1:])
|
||||
message_hash = _hash(message, method_name)
|
||||
|
||||
# Compare the real hash to the hash in the signature
|
||||
if message_hash != signature_hash:
|
||||
raise VerificationError('Verification failed')
|
||||
|
||||
return True
|
||||
|
||||
def _hash(message, method_name):
|
||||
'''Returns the message digest.
|
||||
|
||||
:param message: the signed message. Can be an 8-bit string or a file-like
|
||||
object. If ``message`` has a ``read()`` method, it is assumed to be a
|
||||
file-like object.
|
||||
:param method_name: the hash method, must be a key of
|
||||
:py:const:`HASH_METHODS`.
|
||||
|
||||
'''
|
||||
|
||||
if method_name not in HASH_METHODS:
|
||||
raise ValueError('Invalid hash method: %s' % method_name)
|
||||
|
||||
method = HASH_METHODS[method_name]
|
||||
hasher = method()
|
||||
|
||||
if hasattr(message, 'read') and hasattr(message.read, '__call__'):
|
||||
# read as 1K blocks
|
||||
for block in varblock.yield_fixedblocks(message, 1024):
|
||||
hasher.update(block)
|
||||
else:
|
||||
# hash the message object itself.
|
||||
hasher.update(message)
|
||||
|
||||
return hasher.digest()
|
||||
|
||||
|
||||
def _find_method_hash(method_hash):
|
||||
'''Finds the hash method and the hash itself.
|
||||
|
||||
:param method_hash: ASN1 code for the hash method concatenated with the
|
||||
hash itself.
|
||||
|
||||
:return: tuple (method, hash) where ``method`` is the used hash method, and
|
||||
``hash`` is the hash itself.
|
||||
|
||||
:raise VerificationFailed: when the hash method cannot be found
|
||||
|
||||
'''
|
||||
|
||||
for (hashname, asn1code) in HASH_ASN1.items():
|
||||
if not method_hash.startswith(asn1code):
|
||||
continue
|
||||
|
||||
return (hashname, method_hash[len(asn1code):])
|
||||
|
||||
raise VerificationError('Verification failed')
|
||||
|
||||
|
||||
__all__ = ['encrypt', 'decrypt', 'sign', 'verify',
|
||||
'DecryptionError', 'VerificationError', 'CryptoError']
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('Running doctests 1000x or until failure')
|
||||
import doctest
|
||||
|
||||
for count in range(1000):
|
||||
(failures, tests) = doctest.testmod()
|
||||
if failures:
|
||||
break
|
||||
|
||||
if count and count % 100 == 0:
|
||||
print('%i times' % count)
|
||||
|
||||
print('Doctests done')
|
||||
@@ -0,0 +1,166 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
'''Numerical functions related to primes.
|
||||
|
||||
Implementation based on the book Algorithm Design by Michael T. Goodrich and
|
||||
Roberto Tamassia, 2002.
|
||||
'''
|
||||
|
||||
__all__ = [ 'getprime', 'are_relatively_prime']
|
||||
|
||||
import rsa.randnum
|
||||
|
||||
def gcd(p, q):
|
||||
'''Returns the greatest common divisor of p and q
|
||||
|
||||
>>> gcd(48, 180)
|
||||
12
|
||||
'''
|
||||
|
||||
while q != 0:
|
||||
if p < q: (p,q) = (q,p)
|
||||
(p,q) = (q, p % q)
|
||||
return p
|
||||
|
||||
|
||||
def jacobi(a, b):
|
||||
'''Calculates the value of the Jacobi symbol (a/b) where both a and b are
|
||||
positive integers, and b is odd
|
||||
|
||||
:returns: -1, 0 or 1
|
||||
'''
|
||||
|
||||
assert a > 0
|
||||
assert b > 0
|
||||
|
||||
if a == 0: return 0
|
||||
result = 1
|
||||
while a > 1:
|
||||
if a & 1:
|
||||
if ((a-1)*(b-1) >> 2) & 1:
|
||||
result = -result
|
||||
a, b = b % a, a
|
||||
else:
|
||||
if (((b * b) - 1) >> 3) & 1:
|
||||
result = -result
|
||||
a >>= 1
|
||||
if a == 0: return 0
|
||||
return result
|
||||
|
||||
def jacobi_witness(x, n):
|
||||
'''Returns False if n is an Euler pseudo-prime with base x, and
|
||||
True otherwise.
|
||||
'''
|
||||
|
||||
j = jacobi(x, n) % n
|
||||
|
||||
f = pow(x, n >> 1, n)
|
||||
|
||||
if j == f: return False
|
||||
return True
|
||||
|
||||
def randomized_primality_testing(n, k):
|
||||
'''Calculates whether n is composite (which is always correct) or
|
||||
prime (which is incorrect with error probability 2**-k)
|
||||
|
||||
Returns False if the number is composite, and True if it's
|
||||
probably prime.
|
||||
'''
|
||||
|
||||
# 50% of Jacobi-witnesses can report compositness of non-prime numbers
|
||||
|
||||
# The implemented algorithm using the Jacobi witness function has error
|
||||
# probability q <= 0.5, according to Goodrich et. al
|
||||
#
|
||||
# q = 0.5
|
||||
# t = int(math.ceil(k / log(1 / q, 2)))
|
||||
# So t = k / log(2, 2) = k / 1 = k
|
||||
# this means we can use range(k) rather than range(t)
|
||||
|
||||
for _ in range(k):
|
||||
x = rsa.randnum.randint(n-1)
|
||||
if jacobi_witness(x, n): return False
|
||||
|
||||
return True
|
||||
|
||||
def is_prime(number):
|
||||
'''Returns True if the number is prime, and False otherwise.
|
||||
|
||||
>>> is_prime(42)
|
||||
False
|
||||
>>> is_prime(41)
|
||||
True
|
||||
'''
|
||||
|
||||
return randomized_primality_testing(number, 6)
|
||||
|
||||
def getprime(nbits):
|
||||
'''Returns a prime number that can be stored in 'nbits' bits.
|
||||
|
||||
>>> p = getprime(128)
|
||||
>>> is_prime(p-1)
|
||||
False
|
||||
>>> is_prime(p)
|
||||
True
|
||||
>>> is_prime(p+1)
|
||||
False
|
||||
|
||||
>>> from rsa import common
|
||||
>>> common.bit_size(p) == 128
|
||||
True
|
||||
|
||||
'''
|
||||
|
||||
while True:
|
||||
integer = rsa.randnum.read_random_int(nbits)
|
||||
|
||||
# Make sure it's odd
|
||||
integer |= 1
|
||||
|
||||
# Test for primeness
|
||||
if is_prime(integer):
|
||||
return integer
|
||||
|
||||
# Retry if not prime
|
||||
|
||||
|
||||
def are_relatively_prime(a, b):
|
||||
'''Returns True if a and b are relatively prime, and False if they
|
||||
are not.
|
||||
|
||||
>>> are_relatively_prime(2, 3)
|
||||
1
|
||||
>>> are_relatively_prime(2, 4)
|
||||
0
|
||||
'''
|
||||
|
||||
d = gcd(a, b)
|
||||
return (d == 1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('Running doctests 1000x or until failure')
|
||||
import doctest
|
||||
|
||||
for count in range(1000):
|
||||
(failures, tests) = doctest.testmod()
|
||||
if failures:
|
||||
break
|
||||
|
||||
if count and count % 100 == 0:
|
||||
print('%i times' % count)
|
||||
|
||||
print('Doctests done')
|
||||
@@ -0,0 +1,85 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
'''Functions for generating random numbers.'''
|
||||
|
||||
# Source inspired by code by Yesudeep Mangalapilly <yesudeep@gmail.com>
|
||||
|
||||
import os
|
||||
|
||||
from rsa import common, transform
|
||||
from rsa._compat import byte
|
||||
|
||||
def read_random_bits(nbits):
|
||||
'''Reads 'nbits' random bits.
|
||||
|
||||
If nbits isn't a whole number of bytes, an extra byte will be appended with
|
||||
only the lower bits set.
|
||||
'''
|
||||
|
||||
nbytes, rbits = divmod(nbits, 8)
|
||||
|
||||
# Get the random bytes
|
||||
randomdata = os.urandom(nbytes)
|
||||
|
||||
# Add the remaining random bits
|
||||
if rbits > 0:
|
||||
randomvalue = ord(os.urandom(1))
|
||||
randomvalue >>= (8 - rbits)
|
||||
randomdata = byte(randomvalue) + randomdata
|
||||
|
||||
return randomdata
|
||||
|
||||
|
||||
def read_random_int(nbits):
|
||||
'''Reads a random integer of approximately nbits bits.
|
||||
'''
|
||||
|
||||
randomdata = read_random_bits(nbits)
|
||||
value = transform.bytes2int(randomdata)
|
||||
|
||||
# Ensure that the number is large enough to just fill out the required
|
||||
# number of bits.
|
||||
value |= 1 << (nbits - 1)
|
||||
|
||||
return value
|
||||
|
||||
def randint(maxvalue):
|
||||
'''Returns a random integer x with 1 <= x <= maxvalue
|
||||
|
||||
May take a very long time in specific situations. If maxvalue needs N bits
|
||||
to store, the closer maxvalue is to (2 ** N) - 1, the faster this function
|
||||
is.
|
||||
'''
|
||||
|
||||
bit_size = common.bit_size(maxvalue)
|
||||
|
||||
tries = 0
|
||||
while True:
|
||||
value = read_random_int(bit_size)
|
||||
if value <= maxvalue:
|
||||
break
|
||||
|
||||
if tries and tries % 10 == 0:
|
||||
# After a lot of tries to get the right number of bits but still
|
||||
# smaller than maxvalue, decrease the number of bits by 1. That'll
|
||||
# dramatically increase the chances to get a large enough number.
|
||||
bit_size -= 1
|
||||
tries += 1
|
||||
|
||||
return value
|
||||
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
'''Data transformation functions.
|
||||
|
||||
From bytes to a number, number to bytes, etc.
|
||||
'''
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
try:
|
||||
# We'll use psyco if available on 32-bit architectures to speed up code.
|
||||
# Using psyco (if available) cuts down the execution time on Python 2.5
|
||||
# at least by half.
|
||||
import psyco
|
||||
psyco.full()
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
import binascii
|
||||
from struct import pack
|
||||
from rsa import common
|
||||
from rsa._compat import is_integer, b, byte, get_word_alignment, ZERO_BYTE, EMPTY_BYTE
|
||||
|
||||
|
||||
def bytes2int(raw_bytes):
|
||||
r'''Converts a list of bytes or an 8-bit string to an integer.
|
||||
|
||||
When using unicode strings, encode it to some encoding like UTF8 first.
|
||||
|
||||
>>> (((128 * 256) + 64) * 256) + 15
|
||||
8405007
|
||||
>>> bytes2int('\x80@\x0f')
|
||||
8405007
|
||||
|
||||
'''
|
||||
|
||||
return int(binascii.hexlify(raw_bytes), 16)
|
||||
|
||||
|
||||
def _int2bytes(number, block_size=None):
|
||||
r'''Converts a number to a string of bytes.
|
||||
|
||||
Usage::
|
||||
|
||||
>>> _int2bytes(123456789)
|
||||
'\x07[\xcd\x15'
|
||||
>>> bytes2int(_int2bytes(123456789))
|
||||
123456789
|
||||
|
||||
>>> _int2bytes(123456789, 6)
|
||||
'\x00\x00\x07[\xcd\x15'
|
||||
>>> bytes2int(_int2bytes(123456789, 128))
|
||||
123456789
|
||||
|
||||
>>> _int2bytes(123456789, 3)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
OverflowError: Needed 4 bytes for number, but block size is 3
|
||||
|
||||
@param number: the number to convert
|
||||
@param block_size: the number of bytes to output. If the number encoded to
|
||||
bytes is less than this, the block will be zero-padded. When not given,
|
||||
the returned block is not padded.
|
||||
|
||||
@throws OverflowError when block_size is given and the number takes up more
|
||||
bytes than fit into the block.
|
||||
'''
|
||||
# Type checking
|
||||
if not is_integer(number):
|
||||
raise TypeError("You must pass an integer for 'number', not %s" %
|
||||
number.__class__)
|
||||
|
||||
if number < 0:
|
||||
raise ValueError('Negative numbers cannot be used: %i' % number)
|
||||
|
||||
# Do some bounds checking
|
||||
if number == 0:
|
||||
needed_bytes = 1
|
||||
raw_bytes = [ZERO_BYTE]
|
||||
else:
|
||||
needed_bytes = common.byte_size(number)
|
||||
raw_bytes = []
|
||||
|
||||
# You cannot compare None > 0 in Python 3x. It will fail with a TypeError.
|
||||
if block_size and block_size > 0:
|
||||
if needed_bytes > block_size:
|
||||
raise OverflowError('Needed %i bytes for number, but block size '
|
||||
'is %i' % (needed_bytes, block_size))
|
||||
|
||||
# Convert the number to bytes.
|
||||
while number > 0:
|
||||
raw_bytes.insert(0, byte(number & 0xFF))
|
||||
number >>= 8
|
||||
|
||||
# Pad with zeroes to fill the block
|
||||
if block_size and block_size > 0:
|
||||
padding = (block_size - needed_bytes) * ZERO_BYTE
|
||||
else:
|
||||
padding = EMPTY_BYTE
|
||||
|
||||
return padding + EMPTY_BYTE.join(raw_bytes)
|
||||
|
||||
|
||||
def bytes_leading(raw_bytes, needle=ZERO_BYTE):
|
||||
'''
|
||||
Finds the number of prefixed byte occurrences in the haystack.
|
||||
|
||||
Useful when you want to deal with padding.
|
||||
|
||||
:param raw_bytes:
|
||||
Raw bytes.
|
||||
:param needle:
|
||||
The byte to count. Default \000.
|
||||
:returns:
|
||||
The number of leading needle bytes.
|
||||
'''
|
||||
leading = 0
|
||||
# Indexing keeps compatibility between Python 2.x and Python 3.x
|
||||
_byte = needle[0]
|
||||
for x in raw_bytes:
|
||||
if x == _byte:
|
||||
leading += 1
|
||||
else:
|
||||
break
|
||||
return leading
|
||||
|
||||
|
||||
def int2bytes(number, fill_size=None, chunk_size=None, overflow=False):
|
||||
'''
|
||||
Convert an unsigned integer to bytes (base-256 representation)::
|
||||
|
||||
Does not preserve leading zeros if you don't specify a chunk size or
|
||||
fill size.
|
||||
|
||||
.. NOTE:
|
||||
You must not specify both fill_size and chunk_size. Only one
|
||||
of them is allowed.
|
||||
|
||||
:param number:
|
||||
Integer value
|
||||
:param fill_size:
|
||||
If the optional fill size is given the length of the resulting
|
||||
byte string is expected to be the fill size and will be padded
|
||||
with prefix zero bytes to satisfy that length.
|
||||
:param chunk_size:
|
||||
If optional chunk size is given and greater than zero, pad the front of
|
||||
the byte string with binary zeros so that the length is a multiple of
|
||||
``chunk_size``.
|
||||
:param overflow:
|
||||
``False`` (default). If this is ``True``, no ``OverflowError``
|
||||
will be raised when the fill_size is shorter than the length
|
||||
of the generated byte sequence. Instead the byte sequence will
|
||||
be returned as is.
|
||||
:returns:
|
||||
Raw bytes (base-256 representation).
|
||||
:raises:
|
||||
``OverflowError`` when fill_size is given and the number takes up more
|
||||
bytes than fit into the block. This requires the ``overflow``
|
||||
argument to this function to be set to ``False`` otherwise, no
|
||||
error will be raised.
|
||||
'''
|
||||
if number < 0:
|
||||
raise ValueError("Number must be an unsigned integer: %d" % number)
|
||||
|
||||
if fill_size and chunk_size:
|
||||
raise ValueError("You can either fill or pad chunks, but not both")
|
||||
|
||||
# Ensure these are integers.
|
||||
number & 1
|
||||
|
||||
raw_bytes = b('')
|
||||
|
||||
# Pack the integer one machine word at a time into bytes.
|
||||
num = number
|
||||
word_bits, _, max_uint, pack_type = get_word_alignment(num)
|
||||
pack_format = ">%s" % pack_type
|
||||
while num > 0:
|
||||
raw_bytes = pack(pack_format, num & max_uint) + raw_bytes
|
||||
num >>= word_bits
|
||||
# Obtain the index of the first non-zero byte.
|
||||
zero_leading = bytes_leading(raw_bytes)
|
||||
if number == 0:
|
||||
raw_bytes = ZERO_BYTE
|
||||
# De-padding.
|
||||
raw_bytes = raw_bytes[zero_leading:]
|
||||
|
||||
length = len(raw_bytes)
|
||||
if fill_size and fill_size > 0:
|
||||
if not overflow and length > fill_size:
|
||||
raise OverflowError(
|
||||
"Need %d bytes for number, but fill size is %d" %
|
||||
(length, fill_size)
|
||||
)
|
||||
raw_bytes = raw_bytes.rjust(fill_size, ZERO_BYTE)
|
||||
elif chunk_size and chunk_size > 0:
|
||||
remainder = length % chunk_size
|
||||
if remainder:
|
||||
padding_size = chunk_size - remainder
|
||||
raw_bytes = raw_bytes.rjust(length + padding_size, ZERO_BYTE)
|
||||
return raw_bytes
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
'''Utility functions.'''
|
||||
|
||||
from __future__ import with_statement, print_function
|
||||
|
||||
import sys
|
||||
from optparse import OptionParser
|
||||
|
||||
import rsa.key
|
||||
|
||||
def private_to_public():
|
||||
'''Reads a private key and outputs the corresponding public key.'''
|
||||
|
||||
# Parse the CLI options
|
||||
parser = OptionParser(usage='usage: %prog [options]',
|
||||
description='Reads a private key and outputs the '
|
||||
'corresponding public key. Both private and public keys use '
|
||||
'the format described in PKCS#1 v1.5')
|
||||
|
||||
parser.add_option('-i', '--input', dest='infilename', type='string',
|
||||
help='Input filename. Reads from stdin if not specified')
|
||||
parser.add_option('-o', '--output', dest='outfilename', type='string',
|
||||
help='Output filename. Writes to stdout of not specified')
|
||||
|
||||
parser.add_option('--inform', dest='inform',
|
||||
help='key format of input - default PEM',
|
||||
choices=('PEM', 'DER'), default='PEM')
|
||||
|
||||
parser.add_option('--outform', dest='outform',
|
||||
help='key format of output - default PEM',
|
||||
choices=('PEM', 'DER'), default='PEM')
|
||||
|
||||
(cli, cli_args) = parser.parse_args(sys.argv)
|
||||
|
||||
# Read the input data
|
||||
if cli.infilename:
|
||||
print('Reading private key from %s in %s format' % \
|
||||
(cli.infilename, cli.inform), file=sys.stderr)
|
||||
with open(cli.infilename, 'rb') as infile:
|
||||
in_data = infile.read()
|
||||
else:
|
||||
print('Reading private key from stdin in %s format' % cli.inform,
|
||||
file=sys.stderr)
|
||||
in_data = sys.stdin.read().encode('ascii')
|
||||
|
||||
assert type(in_data) == bytes, type(in_data)
|
||||
|
||||
|
||||
# Take the public fields and create a public key
|
||||
priv_key = rsa.key.PrivateKey.load_pkcs1(in_data, cli.inform)
|
||||
pub_key = rsa.key.PublicKey(priv_key.n, priv_key.e)
|
||||
|
||||
# Save to the output file
|
||||
out_data = pub_key.save_pkcs1(cli.outform)
|
||||
|
||||
if cli.outfilename:
|
||||
print('Writing public key to %s in %s format' % \
|
||||
(cli.outfilename, cli.outform), file=sys.stderr)
|
||||
with open(cli.outfilename, 'wb') as outfile:
|
||||
outfile.write(out_data)
|
||||
else:
|
||||
print('Writing public key to stdout in %s format' % cli.outform,
|
||||
file=sys.stderr)
|
||||
sys.stdout.write(out_data.decode('ascii'))
|
||||
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
'''VARBLOCK file support
|
||||
|
||||
The VARBLOCK file format is as follows, where || denotes byte concatenation:
|
||||
|
||||
FILE := VERSION || BLOCK || BLOCK ...
|
||||
|
||||
BLOCK := LENGTH || DATA
|
||||
|
||||
LENGTH := varint-encoded length of the subsequent data. Varint comes from
|
||||
Google Protobuf, and encodes an integer into a variable number of bytes.
|
||||
Each byte uses the 7 lowest bits to encode the value. The highest bit set
|
||||
to 1 indicates the next byte is also part of the varint. The last byte will
|
||||
have this bit set to 0.
|
||||
|
||||
This file format is called the VARBLOCK format, in line with the varint format
|
||||
used to denote the block sizes.
|
||||
|
||||
'''
|
||||
|
||||
from rsa._compat import byte, b
|
||||
|
||||
|
||||
ZERO_BYTE = b('\x00')
|
||||
VARBLOCK_VERSION = 1
|
||||
|
||||
def read_varint(infile):
|
||||
'''Reads a varint from the file.
|
||||
|
||||
When the first byte to be read indicates EOF, (0, 0) is returned. When an
|
||||
EOF occurs when at least one byte has been read, an EOFError exception is
|
||||
raised.
|
||||
|
||||
@param infile: the file-like object to read from. It should have a read()
|
||||
method.
|
||||
@returns (varint, length), the read varint and the number of read bytes.
|
||||
'''
|
||||
|
||||
varint = 0
|
||||
read_bytes = 0
|
||||
|
||||
while True:
|
||||
char = infile.read(1)
|
||||
if len(char) == 0:
|
||||
if read_bytes == 0:
|
||||
return (0, 0)
|
||||
raise EOFError('EOF while reading varint, value is %i so far' %
|
||||
varint)
|
||||
|
||||
byte = ord(char)
|
||||
varint += (byte & 0x7F) << (7 * read_bytes)
|
||||
|
||||
read_bytes += 1
|
||||
|
||||
if not byte & 0x80:
|
||||
return (varint, read_bytes)
|
||||
|
||||
|
||||
def write_varint(outfile, value):
|
||||
'''Writes a varint to a file.
|
||||
|
||||
@param outfile: the file-like object to write to. It should have a write()
|
||||
method.
|
||||
@returns the number of written bytes.
|
||||
'''
|
||||
|
||||
# there is a big difference between 'write the value 0' (this case) and
|
||||
# 'there is nothing left to write' (the false-case of the while loop)
|
||||
|
||||
if value == 0:
|
||||
outfile.write(ZERO_BYTE)
|
||||
return 1
|
||||
|
||||
written_bytes = 0
|
||||
while value > 0:
|
||||
to_write = value & 0x7f
|
||||
value = value >> 7
|
||||
|
||||
if value > 0:
|
||||
to_write |= 0x80
|
||||
|
||||
outfile.write(byte(to_write))
|
||||
written_bytes += 1
|
||||
|
||||
return written_bytes
|
||||
|
||||
|
||||
def yield_varblocks(infile):
|
||||
'''Generator, yields each block in the input file.
|
||||
|
||||
@param infile: file to read, is expected to have the VARBLOCK format as
|
||||
described in the module's docstring.
|
||||
@yields the contents of each block.
|
||||
'''
|
||||
|
||||
# Check the version number
|
||||
first_char = infile.read(1)
|
||||
if len(first_char) == 0:
|
||||
raise EOFError('Unable to read VARBLOCK version number')
|
||||
|
||||
version = ord(first_char)
|
||||
if version != VARBLOCK_VERSION:
|
||||
raise ValueError('VARBLOCK version %i not supported' % version)
|
||||
|
||||
while True:
|
||||
(block_size, read_bytes) = read_varint(infile)
|
||||
|
||||
# EOF at block boundary, that's fine.
|
||||
if read_bytes == 0 and block_size == 0:
|
||||
break
|
||||
|
||||
block = infile.read(block_size)
|
||||
|
||||
read_size = len(block)
|
||||
if read_size != block_size:
|
||||
raise EOFError('Block size is %i, but could read only %i bytes' %
|
||||
(block_size, read_size))
|
||||
|
||||
yield block
|
||||
|
||||
|
||||
def yield_fixedblocks(infile, blocksize):
|
||||
'''Generator, yields each block of ``blocksize`` bytes in the input file.
|
||||
|
||||
:param infile: file to read and separate in blocks.
|
||||
:returns: a generator that yields the contents of each block
|
||||
'''
|
||||
|
||||
while True:
|
||||
block = infile.read(blocksize)
|
||||
|
||||
read_bytes = len(block)
|
||||
if read_bytes == 0:
|
||||
break
|
||||
|
||||
yield block
|
||||
|
||||
if read_bytes < blocksize:
|
||||
break
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
import unittest2 as unittest
|
||||
|
||||
current_path = os.path.abspath(os.path.dirname(__file__))
|
||||
tests_path = os.path.join(current_path, 'tests')
|
||||
sys.path[0:0] = [
|
||||
current_path,
|
||||
tests_path,
|
||||
]
|
||||
|
||||
all_tests = [f[:-3] for f in os.listdir(tests_path)
|
||||
if f.startswith('test_') and f.endswith(".py")]
|
||||
|
||||
def get_suite(tests):
|
||||
tests = sorted(tests)
|
||||
suite = unittest.TestSuite()
|
||||
loader = unittest.TestLoader()
|
||||
for test in tests:
|
||||
suite.addTest(loader.loadTestsFromName(test))
|
||||
return suite
|
||||
|
||||
if __name__ == '__main__':
|
||||
"""
|
||||
To run all tests:
|
||||
$ python run_tests.py
|
||||
To run a single test:
|
||||
$ python run_tests.py app
|
||||
To run a couple of tests:
|
||||
$ python run_tests.py app config sessions
|
||||
To run code coverage:
|
||||
$ coverage run run_tests.py
|
||||
$ coverage report -m
|
||||
"""
|
||||
tests = sys.argv[1:]
|
||||
if not tests:
|
||||
tests = all_tests
|
||||
tests = ['%s' % t for t in tests]
|
||||
suite = get_suite(tests)
|
||||
unittest.TextTestRunner(verbosity=1).run(suite)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user