blob: f27740b9bd734982637910bf403bda5fa2ab1f3e [file] [log] [blame]
Scott Baker611f6bd2019-10-18 13:45:19 -07001// Package asn1tools provides tools for managing ASN1 marshaled data.
2package asn1tools
3
4import (
5 "github.com/jcmturner/gofork/encoding/asn1"
6)
7
8// MarshalLengthBytes returns the ASN1 encoded bytes for the length 'l'
9//
10// There are two forms: short (for lengths between 0 and 127), and long definite (for lengths between 0 and 2^1008 -1).
11//
12// Short form: One octet. Bit 8 has value "0" and bits 7-1 give the length.
13//
14// Long form: Two to 127 octets. Bit 8 of first octet has value "1" and bits 7-1 give the number of additional length octets. Second and following octets give the length, base 256, most significant digit first.
15func MarshalLengthBytes(l int) []byte {
16 if l <= 127 {
17 return []byte{byte(l)}
18 }
19 var b []byte
20 p := 1
21 for i := 1; i < 127; {
22 b = append([]byte{byte((l % (p * 256)) / p)}, b...)
23 p = p * 256
24 l = l - l%p
25 if l <= 0 {
26 break
27 }
28 }
29 return append([]byte{byte(128 + len(b))}, b...)
30}
31
32// GetLengthFromASN returns the length of a slice of ASN1 encoded bytes from the ASN1 length header it contains.
33func GetLengthFromASN(b []byte) int {
34 if int(b[1]) <= 127 {
35 return int(b[1])
36 }
37 // The bytes that indicate the length
38 lb := b[2 : 2+int(b[1])-128]
39 base := 1
40 l := 0
41 for i := len(lb) - 1; i >= 0; i-- {
42 l += int(lb[i]) * base
43 base = base * 256
44 }
45 return l
46}
47
48// GetNumberBytesInLengthHeader returns the number of bytes in the ASn1 header that indicate the length.
49func GetNumberBytesInLengthHeader(b []byte) int {
50 if int(b[1]) <= 127 {
51 return 1
52 }
53 // The bytes that indicate the length
54 return 1 + int(b[1]) - 128
55}
56
57// AddASNAppTag adds an ASN1 encoding application tag value to the raw bytes provided.
58func AddASNAppTag(b []byte, tag int) []byte {
59 r := asn1.RawValue{
60 Class: asn1.ClassApplication,
61 IsCompound: true,
62 Tag: tag,
63 Bytes: b,
64 }
65 ab, _ := asn1.Marshal(r)
66 return ab
67}
68
69/*
70// The Marshal method of golang's asn1 package does not enable you to define wrapping the output in an application tag.
71// This method adds that wrapping tag.
72func AddASNAppTag(b []byte, tag int) []byte {
73 // The ASN1 wrapping consists of 2 bytes:
74 // 1st byte -> Identifier Octet - Application Tag
75 // 2nd byte -> The length (this will be the size indicated in the input bytes + 2 for the additional bytes we add here.
76 // Application Tag:
77 //| Bit: | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
78 //| Value: | 0 | 1 | 1 | From the RFC spec 4120 |
79 //| Explanation | Defined by the ASN1 encoding rules for an application tag | A value of 1 indicates a constructed type | The ASN Application tag value |
80 // Therefore the value of the byte is an integer = ( Application tag value + 96 )
81 //b = append(MarshalLengthBytes(int(b[1])+2), b...)
82 b = append(MarshalLengthBytes(len(b)), b...)
83 b = append([]byte{byte(96 + tag)}, b...)
84 return b
85}
86*/