readme.md
1# asn1crypto
2
3A fast, pure Python library for parsing and serializing ASN.1 structures.
4
5 - [Features](#features)
6 - [Why Another Python ASN.1 Library?](#why-another-python-asn1-library)
7 - [Related Crypto Libraries](#related-crypto-libraries)
8 - [Current Release](#current-release)
9 - [Dependencies](#dependencies)
10 - [Installation](#installation)
11 - [License](#license)
12 - [Documentation](#documentation)
13 - [Continuous Integration](#continuous-integration)
14 - [Testing](#testing)
15 - [Development](#development)
16 - [CI Tasks](#ci-tasks)
17
18[![GitHub Actions CI](https://github.com/wbond/asn1crypto/workflows/CI/badge.svg)](https://github.com/wbond/asn1crypto/actions?workflow=CI)
19[![Travis CI](https://api.travis-ci.org/wbond/asn1crypto.svg?branch=master)](https://travis-ci.org/wbond/asn1crypto)
20[![AppVeyor](https://ci.appveyor.com/api/projects/status/github/wbond/asn1crypto?branch=master&svg=true)](https://ci.appveyor.com/project/wbond/asn1crypto)
21[![CircleCI](https://circleci.com/gh/wbond/asn1crypto.svg?style=shield)](https://circleci.com/gh/wbond/asn1crypto)
22[![PyPI](https://img.shields.io/pypi/v/asn1crypto.svg)](https://pypi.org/project/asn1crypto/)
23
24## Features
25
26In addition to an ASN.1 BER/DER decoder and DER serializer, the project includes
27a bunch of ASN.1 structures for use with various common cryptography standards:
28
29| Standard | Module | Source |
30| ---------------------- | ------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
31| X.509 | [`asn1crypto.x509`](asn1crypto/x509.py) | [RFC 5280](https://tools.ietf.org/html/rfc5280) |
32| CRL | [`asn1crypto.crl`](asn1crypto/crl.py) | [RFC 5280](https://tools.ietf.org/html/rfc5280) |
33| CSR | [`asn1crypto.csr`](asn1crypto/csr.py) | [RFC 2986](https://tools.ietf.org/html/rfc2986), [RFC 2985](https://tools.ietf.org/html/rfc2985) |
34| OCSP | [`asn1crypto.ocsp`](asn1crypto/ocsp.py) | [RFC 6960](https://tools.ietf.org/html/rfc6960) |
35| PKCS#12 | [`asn1crypto.pkcs12`](asn1crypto/pkcs12.py) | [RFC 7292](https://tools.ietf.org/html/rfc7292) |
36| PKCS#8 | [`asn1crypto.keys`](asn1crypto/keys.py) | [RFC 5208](https://tools.ietf.org/html/rfc5208) |
37| PKCS#1 v2.1 (RSA keys) | [`asn1crypto.keys`](asn1crypto/keys.py) | [RFC 3447](https://tools.ietf.org/html/rfc3447) |
38| DSA keys | [`asn1crypto.keys`](asn1crypto/keys.py) | [RFC 3279](https://tools.ietf.org/html/rfc3279) |
39| Elliptic curve keys | [`asn1crypto.keys`](asn1crypto/keys.py) | [SECG SEC1 V2](http://www.secg.org/sec1-v2.pdf) |
40| PKCS#3 v1.4 | [`asn1crypto.algos`](asn1crypto/algos.py) | [PKCS#3 v1.4](ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-3.asc) |
41| PKCS#5 v2.1 | [`asn1crypto.algos`](asn1crypto/algos.py) | [PKCS#5 v2.1](http://www.emc.com/collateral/white-papers/h11302-pkcs5v2-1-password-based-cryptography-standard-wp.pdf) |
42| CMS (and PKCS#7) | [`asn1crypto.cms`](asn1crypto/cms.py) | [RFC 5652](https://tools.ietf.org/html/rfc5652), [RFC 2315](https://tools.ietf.org/html/rfc2315) |
43| TSP | [`asn1crypto.tsp`](asn1crypto/tsp.py) | [RFC 3161](https://tools.ietf.org/html/rfc3161) |
44| PDF signatures | [`asn1crypto.pdf`](asn1crypto/pdf.py) | [PDF 1.7](http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/PDF32000_2008.pdf) |
45
46## Why Another Python ASN.1 Library?
47
48Python has long had the [pyasn1](https://pypi.org/project/pyasn1/) and
49[pyasn1_modules](https://pypi.org/project/pyasn1-modules/) available for
50parsing and serializing ASN.1 structures. While the project does include a
51comprehensive set of tools for parsing and serializing, the performance of the
52library can be very poor, especially when dealing with bit fields and parsing
53large structures such as CRLs.
54
55After spending extensive time using *pyasn1*, the following issues were
56identified:
57
58 1. Poor performance
59 2. Verbose, non-pythonic API
60 3. Out-dated and incomplete definitions in *pyasn1-modules*
61 4. No simple way to map data to native Python data structures
62 5. No mechanism for overridden universal ASN.1 types
63
64The *pyasn1* API is largely method driven, and uses extensive configuration
65objects and lowerCamelCase names. There were no consistent options for
66converting types of native Python data structures. Since the project supports
67out-dated versions of Python, many newer language features are unavailable
68for use.
69
70Time was spent trying to profile issues with the performance, however the
71architecture made it hard to pin down the primary source of the poor
72performance. Attempts were made to improve performance by utilizing unreleased
73patches and delaying parsing using the `Any` type. Even with such changes, the
74performance was still unacceptably slow.
75
76Finally, a number of structures in the cryptographic space use universal data
77types such as `BitString` and `OctetString`, but interpret the data as other
78types. For instance, signatures are really byte strings, but are encoded as
79`BitString`. Elliptic curve keys use both `BitString` and `OctetString` to
80represent integers. Parsing these structures as the base universal types and
81then re-interpreting them wastes computation.
82
83*asn1crypto* uses the following techniques to improve performance, especially
84when extracting one or two fields from large, complex structures:
85
86 - Delayed parsing of byte string values
87 - Persistence of original ASN.1 encoded data until a value is changed
88 - Lazy loading of child fields
89 - Utilization of high-level Python stdlib modules
90
91While there is no extensive performance test suite, the
92`CRLTests.test_parse_crl` test case was used to parse a 21MB CRL file on a
93late 2013 rMBP. *asn1crypto* parsed the certificate serial numbers in just
94under 8 seconds. With *pyasn1*, using definitions from *pyasn1-modules*, the
95same parsing took over 4,100 seconds.
96
97For smaller structures the performance difference can range from a few times
98faster to an order of magnitude or more.
99
100## Related Crypto Libraries
101
102*asn1crypto* is part of the modularcrypto family of Python packages:
103
104 - [asn1crypto](https://github.com/wbond/asn1crypto)
105 - [oscrypto](https://github.com/wbond/oscrypto)
106 - [csrbuilder](https://github.com/wbond/csrbuilder)
107 - [certbuilder](https://github.com/wbond/certbuilder)
108 - [crlbuilder](https://github.com/wbond/crlbuilder)
109 - [ocspbuilder](https://github.com/wbond/ocspbuilder)
110 - [certvalidator](https://github.com/wbond/certvalidator)
111
112## Current Release
113
1141.4.0 - [changelog](changelog.md)
115
116## Dependencies
117
118Python 2.6, 2.7, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8 or pypy. *No third-party
119packages required.*
120
121## Installation
122
123```bash
124pip install asn1crypto
125```
126
127## License
128
129*asn1crypto* is licensed under the terms of the MIT license. See the
130[LICENSE](LICENSE) file for the exact license text.
131
132## Documentation
133
134The documentation for *asn1crypto* is composed of tutorials on basic usage and
135links to the source for the various pre-defined type classes.
136
137### Tutorials
138
139 - [Universal Types with BER/DER Decoder and DER Encoder](docs/universal_types.md)
140 - [PEM Encoder and Decoder](docs/pem.md)
141
142### Reference
143
144 - [Universal types](asn1crypto/core.py), `asn1crypto.core`
145 - [Digest, HMAC, signed digest and encryption algorithms](asn1crypto/algos.py), `asn1crypto.algos`
146 - [Private and public keys](asn1crypto/keys.py), `asn1crypto.keys`
147 - [X509 certificates](asn1crypto/x509.py), `asn1crypto.x509`
148 - [Certificate revocation lists (CRLs)](asn1crypto/crl.py), `asn1crypto.crl`
149 - [Online certificate status protocol (OCSP)](asn1crypto/ocsp.py), `asn1crypto.ocsp`
150 - [Certificate signing requests (CSRs)](asn1crypto/csr.py), `asn1crypto.csr`
151 - [Private key/certificate containers (PKCS#12)](asn1crypto/pkcs12.py), `asn1crypto.pkcs12`
152 - [Cryptographic message syntax (CMS, PKCS#7)](asn1crypto/cms.py), `asn1crypto.cms`
153 - [Time stamp protocol (TSP)](asn1crypto/tsp.py), `asn1crypto.tsp`
154 - [PDF signatures](asn1crypto/pdf.py), `asn1crypto.pdf`
155
156## Continuous Integration
157
158Various combinations of platforms and versions of Python are tested via:
159
160 - [AppVeyor](https://ci.appveyor.com/project/wbond/asn1crypto/history)
161 - [CircleCI](https://circleci.com/gh/wbond/asn1crypto)
162 - [GitHub Actions](https://github.com/wbond/asn1crypto/actions)
163 - [Travis CI](https://travis-ci.org/wbond/asn1crypto/builds)
164
165## Testing
166
167Tests are written using `unittest` and require no third-party packages.
168
169Depending on what type of source is available for the package, the following
170commands can be used to run the test suite.
171
172### Git Repository
173
174When working within a Git working copy, or an archive of the Git repository,
175the full test suite is run via:
176
177```bash
178python run.py tests
179```
180
181To run only some tests, pass a regular expression as a parameter to `tests`.
182
183```bash
184python run.py tests ocsp
185```
186
187### PyPi Source Distribution
188
189When working within an extracted source distribution (aka `.tar.gz`) from
190PyPi, the full test suite is run via:
191
192```bash
193python setup.py test
194```
195
196### Package
197
198When the package has been installed via pip (or another method), the package
199`asn1crypto_tests` may be installed and invoked to run the full test suite:
200
201```bash
202pip install asn1crypto_tests
203python -m asn1crypto_tests
204```
205
206## Development
207
208To install the package used for linting, execute:
209
210```bash
211pip install --user -r requires/lint
212```
213
214The following command will run the linter:
215
216```bash
217python run.py lint
218```
219
220Support for code coverage can be installed via:
221
222```bash
223pip install --user -r requires/coverage
224```
225
226Coverage is measured by running:
227
228```bash
229python run.py coverage
230```
231
232To change the version number of the package, run:
233
234```bash
235python run.py version {pep440_version}
236```
237
238To install the necessary packages for releasing a new version on PyPI, run:
239
240```bash
241pip install --user -r requires/release
242```
243
244Releases are created by:
245
246 - Making a git tag in [PEP 440](https://www.python.org/dev/peps/pep-0440/#examples-of-compliant-version-schemes) format
247 - Running the command:
248
249 ```bash
250 python run.py release
251 ```
252
253Existing releases can be found at https://pypi.org/project/asn1crypto/.
254
255## CI Tasks
256
257A task named `deps` exists to download and stage all necessary testing
258dependencies. On posix platforms, `curl` is used for downloads and on Windows
259PowerShell with `Net.WebClient` is used. This configuration sidesteps issues
260related to getting pip to work properly and messing with `site-packages` for
261the version of Python being used.
262
263The `ci` task runs `lint` (if flake8 is available for the version of Python) and
264`coverage` (or `tests` if coverage is not available for the version of Python).
265If the current directory is a clean git working copy, the coverage data is
266submitted to codecov.io.
267
268```bash
269python run.py deps
270python run.py ci
271```
272