-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathexample.go
More file actions
105 lines (94 loc) · 2.56 KB
/
example.go
File metadata and controls
105 lines (94 loc) · 2.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
//go:build ignore
package main
import (
"encoding/pem"
"fmt"
"math"
"os"
"golang.org/x/crypto/cryptobyte"
)
const (
propertyTrustAnchorID = 0
propertyTrustAnchorGroupInclusions = 1
)
type TrustAnchorID []uint64
func addBase128(out *cryptobyte.Builder, v uint64) {
// Count how many bytes are needed.
var l int
for n := v; n != 0; n >>= 7 {
l++
}
// Special-case: zero is encoded with one, not zero bytes.
if v == 0 {
l = 1
}
for ; l > 0; l-- {
b := byte(v>>uint(7*(l-1))) & 0x7f
if l > 1 {
b |= 0x80
}
out.AddUint8(b)
}
}
func addTrustAnchorID(out *cryptobyte.Builder, id TrustAnchorID) {
for _, v := range id {
addBase128(out, v)
}
}
type TrustAnchorRange struct {
Base TrustAnchorID
Min, Max uint64
}
type CertificatePropertyList struct {
TrustAnchorID TrustAnchorID
TrustAnchorGroupInclusions []TrustAnchorRange
}
func (l *CertificatePropertyList) Marshal() ([]byte, error) {
b := cryptobyte.NewBuilder(nil)
b.AddUint16LengthPrefixed(func(props *cryptobyte.Builder) {
if len(l.TrustAnchorID) != 0 {
props.AddUint16(propertyTrustAnchorID)
props.AddUint16LengthPrefixed(func(child *cryptobyte.Builder) {
// No extra length prefix because we said that the `data` field
// simply is the trust anchor ID.
addTrustAnchorID(child, l.TrustAnchorID)
})
}
if len(l.TrustAnchorGroupInclusions) != 0 {
props.AddUint16(propertyTrustAnchorGroupInclusions)
// TLS's presentation language leads to many redundant length prefixes.
// First we have a length prefix for the property's `data` field.
props.AddUint16LengthPrefixed(func(child *cryptobyte.Builder) {
// Now the TrustAnchorRangeList needs a length prefix.
child.AddUint16LengthPrefixed(func(list *cryptobyte.Builder) {
for _, r := range l.TrustAnchorGroupInclusions {
// The ID is encoded as a TrustAnchorID, so it needs a length prefix,
// or the parsing will be ambiguous.
list.AddUint8LengthPrefixed(func(id *cryptobyte.Builder) {
addTrustAnchorID(id, r.Base)
})
list.AddUint64(r.Min)
list.AddUint64(r.Max)
}
})
})
}
})
return b.Bytes()
}
func main() {
props := CertificatePropertyList{
TrustAnchorID: []uint64{32473, 1},
TrustAnchorGroupInclusions: []TrustAnchorRange{
{Base: []uint64{2187, 2}, Min: 100, Max: 200},
{Base: []uint64{32473, 3}, Min: 42, Max: math.MaxUint64},
},
}
b, err := props.Marshal()
if err != nil {
panic(err)
}
fmt.Printf("hex: %x\n", b)
fmt.Printf("PEM:\n")
pem.Encode(os.Stdout, &pem.Block{Type: "CERTIFICATE PROPERTIES", Bytes: b})
}