-
Notifications
You must be signed in to change notification settings - Fork 1
/
license.go
161 lines (137 loc) · 4.59 KB
/
license.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
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package license
import (
"crypto"
"encoding/asn1"
"errors"
"time"
)
// License godoc.
type License struct {
ProductName string `json:"product"`
SerialNumber string `json:"serial"`
Customer Customer `json:"customer"`
ValidFrom time.Time `json:"valid_from,omitempty"`
ValidUntil time.Time `json:"valid_until,omitempty"`
MinVersion Version `json:"min_version,omitempty"`
MaxVersion Version `json:"max_version,omitempty"`
Features []Feature `json:"features"`
}
// ValidateSN godoc.
type ValidateSN func(product, serial string, validFrom, validUntil, minVersion, maxVersion int64) error
type asnSignedLicense struct {
Raw asn1.RawContent
ProductName string `asn1:"optional,application,tag:0"`
SerialNumber string `asn1:"optional,application,tag:1"`
Customer Customer `asn1:"optional,private,omitempty"`
ValidFrom int64 `asn1:"optional,default:0"`
ValidUntil int64 `asn1:"optional,default:0"`
MinVersion int64 `asn1:"optional,default:0"`
MaxVersion int64 `asn1:"optional,default:0"`
Features []Feature `asn1:"optional,omitempty"`
AuthorityKeyID []byte
SignatureAlgorithm asn1.ObjectIdentifier
}
type asnSignature struct {
AlgorithmIdentifier asn1.ObjectIdentifier
Value asn1.BitString
}
type asnLicense struct {
License asnSignedLicense
Signature asnSignature
}
const (
byteSize = 8
)
// CreateLicense generate a license using a private key.
func CreateLicense(template *License, key crypto.Signer) ([]byte, error) {
if key == nil {
return nil, errors.New("license: private key is nil")
}
authorityKeyID, hashFunc, signatureAlgorithm, err := authorityHashFromPublicKey(key.Public())
if err != nil {
return nil, err
}
tbsLicense := asnSignedLicense{
ProductName: template.ProductName,
SerialNumber: template.SerialNumber,
Customer: Customer{
Name: template.Customer.Name,
Country: template.Customer.Country,
City: template.Customer.City,
Organization: template.Customer.Organization,
OrganizationalUnit: template.Customer.OrganizationalUnit,
},
ValidFrom: template.ValidFrom.Unix(),
ValidUntil: template.ValidUntil.Unix(),
MinVersion: int64(template.MinVersion),
MaxVersion: int64(template.MaxVersion),
AuthorityKeyID: authorityKeyID,
Features: template.Features,
SignatureAlgorithm: signatureAlgorithm,
}
signature, err := signAsnObject(tbsLicense, key, hashFunc)
if err != nil {
return nil, err
}
licObject := asnLicense{
License: tbsLicense,
Signature: asnSignature{
AlgorithmIdentifier: tbsLicense.SignatureAlgorithm,
Value: asn1.BitString{Bytes: signature, BitLength: len(signature) * byteSize},
},
}
return asn1.Marshal(licObject)
}
// Load a license from asn encoded byte data.
func Load(asn1Data []byte, publicKey interface{}, validator ValidateSN) (*License, error) {
var licObject asnLicense
rest, err := asn1.Unmarshal(asn1Data, &licObject)
if err != nil || len(rest) != 0 {
return nil, errors.New("license: malformed data")
}
digest, hashFunc, err := authorityHashFromAlgorithm(publicKey, licObject.License)
if err != nil {
return nil, err
}
err = checkSignature(digest, licObject.Signature.Value.Bytes, hashFunc, publicKey)
if err != nil {
return nil, err
}
return setLicenseDetails(licObject.License, validator)
}
func setLicenseDetails(license asnSignedLicense, validator ValidateSN) (*License, error) {
if validator != nil {
err := validator(license.ProductName, license.SerialNumber,
license.ValidFrom, license.ValidUntil, license.MinVersion, license.MaxVersion)
if err != nil {
return nil, err
}
}
l := License{
ProductName: license.ProductName,
SerialNumber: license.SerialNumber,
ValidFrom: time.Time{},
ValidUntil: time.Time{},
MinVersion: Version(license.MinVersion),
MaxVersion: Version(license.MaxVersion),
Customer: Customer{
Name: license.Customer.Name,
Country: license.Customer.Country,
City: license.Customer.City,
Organization: license.Customer.Organization,
OrganizationalUnit: license.Customer.OrganizationalUnit,
},
Features: []Feature{},
}
if license.ValidFrom > 0 {
l.ValidFrom = time.Unix(license.ValidFrom, 0)
}
if license.ValidUntil > 0 {
l.ValidUntil = time.Unix(license.ValidUntil, 0)
}
// Set features info
for _, feature := range license.Features {
l.Features = append(l.Features, Feature{Oid: feature.Oid, Limit: feature.Limit})
}
return &l, nil
}