aboutsummaryrefslogtreecommitdiffstats
path: root/kube2msb/src/kube2msb/vendor/github.com/coreos/go-oidc/jose/jwk.go
blob: b7a8e235583ac0bc5a659e3f7df523dd36a72856 (plain)
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package jose

import (
	"bytes"
	"encoding/base64"
	"encoding/binary"
	"encoding/json"
	"math/big"
	"strings"
)

// JSON Web Key
// https://tools.ietf.org/html/draft-ietf-jose-json-web-key-36#page-5
type JWK struct {
	ID       string
	Type     string
	Alg      string
	Use      string
	Exponent int
	Modulus  *big.Int
	Secret   []byte
}

type jwkJSON struct {
	ID       string `json:"kid"`
	Type     string `json:"kty"`
	Alg      string `json:"alg"`
	Use      string `json:"use"`
	Exponent string `json:"e"`
	Modulus  string `json:"n"`
}

func (j *JWK) MarshalJSON() ([]byte, error) {
	t := jwkJSON{
		ID:       j.ID,
		Type:     j.Type,
		Alg:      j.Alg,
		Use:      j.Use,
		Exponent: encodeExponent(j.Exponent),
		Modulus:  encodeModulus(j.Modulus),
	}

	return json.Marshal(&t)
}

func (j *JWK) UnmarshalJSON(data []byte) error {
	var t jwkJSON
	err := json.Unmarshal(data, &t)
	if err != nil {
		return err
	}

	e, err := decodeExponent(t.Exponent)
	if err != nil {
		return err
	}

	n, err := decodeModulus(t.Modulus)
	if err != nil {
		return err
	}

	j.ID = t.ID
	j.Type = t.Type
	j.Alg = t.Alg
	j.Use = t.Use
	j.Exponent = e
	j.Modulus = n

	return nil
}

type JWKSet struct {
	Keys []JWK `json:"keys"`
}

func decodeExponent(e string) (int, error) {
	decE, err := decodeBase64URLPaddingOptional(e)
	if err != nil {
		return 0, err
	}
	var eBytes []byte
	if len(decE) < 8 {
		eBytes = make([]byte, 8-len(decE), 8)
		eBytes = append(eBytes, decE...)
	} else {
		eBytes = decE
	}
	eReader := bytes.NewReader(eBytes)
	var E uint64
	err = binary.Read(eReader, binary.BigEndian, &E)
	if err != nil {
		return 0, err
	}
	return int(E), nil
}

func encodeExponent(e int) string {
	b := make([]byte, 8)
	binary.BigEndian.PutUint64(b, uint64(e))
	var idx int
	for ; idx < 8; idx++ {
		if b[idx] != 0x0 {
			break
		}
	}
	return base64.URLEncoding.EncodeToString(b[idx:])
}

// Turns a URL encoded modulus of a key into a big int.
func decodeModulus(n string) (*big.Int, error) {
	decN, err := decodeBase64URLPaddingOptional(n)
	if err != nil {
		return nil, err
	}
	N := big.NewInt(0)
	N.SetBytes(decN)
	return N, nil
}

func encodeModulus(n *big.Int) string {
	return base64.URLEncoding.EncodeToString(n.Bytes())
}

// decodeBase64URLPaddingOptional decodes Base64 whether there is padding or not.
// The stdlib version currently doesn't handle this.
// We can get rid of this is if this bug:
//   https://github.com/golang/go/issues/4237
// ever closes.
func decodeBase64URLPaddingOptional(e string) ([]byte, error) {
	if m := len(e) % 4; m != 0 {
		e += strings.Repeat("=", 4-m)
	}
	return base64.URLEncoding.DecodeString(e)
}