-
-
Notifications
You must be signed in to change notification settings - Fork 585
/
idp.go
102 lines (90 loc) · 3.07 KB
/
idp.go
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
package idp
import (
"crypto/x509/pkix"
"encoding/asn1"
"errors"
"fmt"
)
var idpOID = asn1.ObjectIdentifier{2, 5, 29, 28} // id-ce-issuingDistributionPoint
// issuingDistributionPoint represents the ASN.1 IssuingDistributionPoint
// SEQUENCE as defined in RFC 5280 Section 5.2.5. We only use three of the
// fields, so the others are omitted.
type issuingDistributionPoint struct {
DistributionPoint distributionPointName `asn1:"optional,tag:0"`
OnlyContainsUserCerts bool `asn1:"optional,tag:1"`
OnlyContainsCACerts bool `asn1:"optional,tag:2"`
}
// distributionPointName represents the ASN.1 DistributionPointName CHOICE as
// defined in RFC 5280 Section 4.2.1.13. We only use one of the fields, so the
// others are omitted.
type distributionPointName struct {
// Technically, FullName is of type GeneralNames, which is of type SEQUENCE OF
// GeneralName. But GeneralName itself is of type CHOICE, and the asn1.Marhsal
// function doesn't support marshalling structs to CHOICEs, so we have to use
// asn1.RawValue and encode the GeneralName ourselves.
FullName []asn1.RawValue `asn1:"optional,tag:0"`
}
// MakeUserCertsExt returns a critical IssuingDistributionPoint extension
// containing the given URLs and with the OnlyContainsUserCerts boolean set to
// true.
func MakeUserCertsExt(urls []string) (pkix.Extension, error) {
var gns []asn1.RawValue
for _, url := range urls {
gns = append(gns, asn1.RawValue{ // GeneralName
Class: 2, // context-specific
Tag: 6, // uniformResourceIdentifier, IA5String
Bytes: []byte(url),
})
}
val := issuingDistributionPoint{
DistributionPoint: distributionPointName{FullName: gns},
OnlyContainsUserCerts: true,
}
valBytes, err := asn1.Marshal(val)
if err != nil {
return pkix.Extension{}, err
}
return pkix.Extension{
Id: idpOID,
Value: valBytes,
Critical: true,
}, nil
}
// MakeCACertsExt returns a critical IssuingDistributionPoint extension
// asserting the OnlyContainsCACerts boolean.
func MakeCACertsExt() (*pkix.Extension, error) {
val := issuingDistributionPoint{
OnlyContainsCACerts: true,
}
valBytes, err := asn1.Marshal(val)
if err != nil {
return nil, err
}
return &pkix.Extension{
Id: idpOID,
Value: valBytes,
Critical: true,
}, nil
}
// GetIDPURIs returns the URIs contained within the issuingDistributionPoint
// extension, if present, or an error otherwise.
func GetIDPURIs(exts []pkix.Extension) ([]string, error) {
for _, ext := range exts {
if ext.Id.Equal(idpOID) {
val := issuingDistributionPoint{}
rest, err := asn1.Unmarshal(ext.Value, &val)
if err != nil {
return nil, fmt.Errorf("parsing IssuingDistributionPoint extension: %w", err)
}
if len(rest) != 0 {
return nil, fmt.Errorf("parsing IssuingDistributionPoint extension: got %d unexpected trailing bytes", len(rest))
}
var uris []string
for _, generalName := range val.DistributionPoint.FullName {
uris = append(uris, string(generalName.Bytes))
}
return uris, nil
}
}
return nil, errors.New("no IssuingDistributionPoint extension found")
}