https://github.com/edjcase/motoko_asn1
A Motoko library for encoding and decoding ASN.1/DER values
https://github.com/edjcase/motoko_asn1
Last synced: 5 months ago
JSON representation
A Motoko library for encoding and decoding ASN.1/DER values
- Host: GitHub
- URL: https://github.com/edjcase/motoko_asn1
- Owner: edjCase
- License: mit
- Created: 2025-04-03T21:10:27.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2025-04-11T17:55:17.000Z (about 1 year ago)
- Last Synced: 2025-04-11T18:48:35.354Z (about 1 year ago)
- Language: Motoko
- Size: 25.4 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Motoko ASN.1
[](https://mops.one/asn1)
[](https://github.com/yourusername/motoko_asn1/blob/main/LICENSE)
A Motoko implementation of ASN.1 (Abstract Syntax Notation One) encoding and decoding.
## ⚠️ Partial Implementation
This library implements the core ASN.1 DER encoding and decoding functionality, but is missing several ASN.1 types:
**Missing Types (by usage frequency):**
1. ENUMERATED - Used in protocols like SNMP, LDAP
2. BMPString - Common in certificates and internationalized applications
3. NumericString - Used in telephony and financial protocols
4. VisibleString/ISO646String - Legacy systems and restricted environments
5. TeletexString/T61String - Older X.509 certificates
6. REAL - Scientific and technical applications
7. DATE, DATE-TIME - Modern alternatives to UTCTime/GeneralizedTime
8. RELATIVE-OID - X.500 directory services
9. Other less common types (EXTERNAL, GraphicString, UniversalString, etc.)
## Package
### MOPS
```bash
mops add asn1
```
To set up MOPS package manager, follow the instructions from the [MOPS Site](https://mops.one)
## Quick Start
### Example 1: Encoding ASN.1
```motoko
import ASN1 "mo:asn1";
// Create an ASN.1 SEQUENCE value
let sequence = #sequence([
#integer(123),
#utf8String("Hello ASN.1"),
#boolean(true)
]);
// Encode to DER format
let bytes : [Nat8] = ASN1.toBytes(sequence, #der);
...
```
OR use a buffer
```motoko
import ASN1 "mo:asn1";
import Buffer "mo:buffer";
// Create an ASN.1 SEQUENCE value
let sequence = #sequence([
#integer(123),
#utf8String("Hello ASN.1"),
#boolean(true)
]);
let list = List.empty();
// Encode to DER format
ASN1.toBytesBuffer(Buffer.fromList(list), sequence, #der);
// 'list' now contains DER bytes
...
```
### Example 2: Decoding to ASN.1
```motoko
import ASN1 "mo:asn1";
import Result "mo:core/Result";
import Debug "mo:core/Debug";
// Assuming 'derBytes' contains DER-encoded data
let derBytes : [Nat8] = [...];
// Decode from DER
let value : ASN1.ASN1Value = switch (ASN1.fromBytes(derBytes.vals(), #der)) {
case (#err(msg)) return #err(msg);
case (#ok(value)) value;
};
```
### Example 3: Pretty-Printing ASN.1 Values
```motoko
import ASN1 "mo:asn1";
import Debug "mo:core/Debug";
// Create an ASN.1 structure
let certificate = #sequence([
#objectIdentifier([1, 2, 840, 113549, 1, 1, 11]), // sha256WithRSAEncryption
#utf8String("Example Certificate"),
#contextSpecific({
tagNumber = 0;
constructed = true;
value = ?#sequence([
#utctime("220101000000Z"),
#utctime("230101000000Z")
])
})
]);
// Print a human-readable representation
let prettyText = ASN1.toText(certificate);
Debug.print(prettyText);
// Output:
// SEQUENCE {
// OBJECT IDENTIFIER: 1.2.840.113549.1.1.11
// UTF8String: Example Certificate
// [0] CONSTRUCTED {
// SEQUENCE {
// UTCTime: 220101000000Z
// UTCTime: 230101000000Z
// }
// }
// }
```
## API Reference
### Types
```motoko
public type TagClass = {
#universal;
#application;
#contextSpecific;
#private_;
};
public type ASN1Value = {
#boolean : Bool;
#integer : Int;
#bitString : BitString;
#octetString : [Nat8];
#null_;
#objectIdentifier : [Nat];
#utf8String : Text;
#printableString : Text;
#ia5String : Text;
#utctime : Text;
#generalizedTime : Text;
#sequence : [ASN1Value];
#set : [ASN1Value];
// Context-specific types
#contextSpecific : ContextSpecificASN1Value;
// Unknown types - store raw data
#unknown : UnknownASN1Value;
};
public type BitString = {
data : [Nat8];
// Number of unused bits in the last byte (0-7)
unusedBits : Nat8;
};
public type ContextSpecificASN1Value = {
tagNumber : Nat;
constructed : Bool;
value : ?ASN1Value;
};
public type UnknownASN1Value = {
tagClass : TagClass;
tagNumber : Nat;
constructed : Bool;
data : [Nat8];
};
public type Encoding = {
#der;
};
```
### Functions
```motoko
// Main encoding/decoding functions
public func fromBytes(bytes : [Nat8], encoding : Encoding) : Result.Result;
public func toBytes(value : ASN1Value, encoding : Encoding) : [Nat8];
public func toBytesToBuffer(buffer : Buffer.Buffer, value : ASN1Value, encoding : Encoding);
// Utility function for pretty-printing
public func toText(value : ASN1Value) : Text;
```
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.