-
Notifications
You must be signed in to change notification settings - Fork 2
/
certificate.go
97 lines (83 loc) · 2.59 KB
/
certificate.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
package webauthn
import (
"crypto/x509"
"encoding/asn1"
"errors"
"fmt"
"github.com/pomerium/webauthn/android"
)
// AppleCertPool is the x509 certificate pool used to verify apple attestation.
var AppleCertPool = x509.NewCertPool()
func init() {
if !AppleCertPool.AppendCertsFromPEM(AppleWebAuthnRootCAPEM) {
panic("invalid apple webauthn root ca")
}
}
var (
errInvalidAndroidKey = errors.New("invalid android key")
errInvalidAppleNonce = errors.New("invalid apple nonce")
errMissingAAGUID = errors.New("missing AAGUID")
errMissingAndroidKey = errors.New("missing android key")
errMissingAppleNonce = errors.New("missing apple nonce")
errAAGUIDMarkedCritical = errors.New("AAGUID marked critical")
)
var (
oidAAGUID = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 45724, 1, 1, 4}
oidAIKCertificate = asn1.ObjectIdentifier{2, 23, 133, 8, 3}
oidAndroidKey = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 1, 17}
oidAppleNonce = asn1.ObjectIdentifier{1, 2, 840, 113635, 100, 8, 2}
)
// certificateHasAIK returns true if the certificate has the AIK extended key usage.
func certificateHasAIK(certificate *x509.Certificate) bool {
for _, eku := range certificate.UnknownExtKeyUsage {
if eku.Equal(oidAIKCertificate) {
return true
}
}
return false
}
func getCertificateAAGUID(certificate *x509.Certificate) (AAGUID, error) {
for _, extension := range certificate.Extensions {
if extension.Id.Equal(oidAAGUID) {
if extension.Critical {
return AAGUID{}, errAAGUIDMarkedCritical
}
var aaguid AAGUID
_, err := asn1.Unmarshal(extension.Value, &aaguid)
if err != nil {
return aaguid, nil
}
}
}
return AAGUID{}, errMissingAAGUID
}
func getCertificateAppleNonce(certificate *x509.Certificate) ([]byte, error) {
type appleAnonymousAttestation struct {
Nonce []byte `asn1:"tag:1,explicit"`
}
for _, extension := range certificate.Extensions {
if !extension.Id.Equal(oidAppleNonce) {
continue
}
var value appleAnonymousAttestation
_, err := asn1.Unmarshal(extension.Value, &value)
if err != nil {
return nil, errInvalidAppleNonce
}
return value.Nonce, nil
}
return nil, errMissingAppleNonce
}
func getCertificateAndroidKeyDescription(certificate *x509.Certificate) (*android.KeyDescription, error) {
for _, extension := range certificate.Extensions {
if !extension.Id.Equal(oidAndroidKey) {
continue
}
keyDescription, _, err := android.UnmarshalKeyDescription(extension.Value)
if err != nil {
return nil, fmt.Errorf("%w: %s", errInvalidAndroidKey, err)
}
return keyDescription, nil
}
return nil, errMissingAndroidKey
}