forked from 9elements/converged-security-suite
/
signature.go
189 lines (173 loc) · 5.38 KB
/
signature.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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
//go:generate manifestcodegen
package manifest
import (
"crypto"
"crypto/rand"
"fmt"
"math/big"
)
var (
// RandReader exports the rand.Reader
RandReader = rand.Reader
)
// Signature exports the Signature structure
type Signature struct {
SigScheme Algorithm `json:"sigScheme"`
Version uint8 `require:"0x10" json:"sigVersion,omitempty"`
KeySize BitSize `json:"sigKeysize,omitempty"`
HashAlg Algorithm `json:"sigHashAlg"`
Data []byte `countValue:"KeySize.InBytes()" prettyValue:"dataPrettyValue()" json:"sigData"`
}
func (m Signature) dataPrettyValue() interface{} {
r, _ := m.SignatureData()
return r
}
// SignatureData parses field Data and returns the signature as one of these types:
// * SignatureRSAPSS
// * SignatureRSAASA
// * SignatureECDSA
// * SignatureSM2
func (m Signature) SignatureData() (SignatureDataInterface, error) {
switch m.SigScheme {
case AlgRSAPSS:
return SignatureRSAPSS(m.Data), nil
case AlgRSASSA:
return SignatureRSAASA(m.Data), nil
case AlgECDSA:
if len(m.Data) != 64 && len(m.Data) != 96 {
return nil, fmt.Errorf("invalid length of the signature data: %d (expected 64 or 96)", len(m.Data))
}
return SignatureECDSA{
R: new(big.Int).SetBytes(reverseBytes(m.Data[:len(m.Data)/2])),
S: new(big.Int).SetBytes(reverseBytes(m.Data[len(m.Data)/2:])),
}, nil
case AlgSM2:
if len(m.Data) != 64 && len(m.Data) != 96 {
return nil, fmt.Errorf("invalid length of the signature data: %d (expected 64 or 96)", len(m.Data))
}
return SignatureSM2{
R: new(big.Int).SetBytes(reverseBytes(m.Data[:len(m.Data)/2])),
S: new(big.Int).SetBytes(reverseBytes(m.Data[len(m.Data)/2:])),
}, nil
}
return nil, fmt.Errorf("unexpected signature scheme: %s", m.SigScheme)
}
// SetSignatureByData sets all the fields of the structure Signature by
// accepting one of these types as the input argument `sig`:
// * SignatureRSAPSS
// * SignatureRSAASA
// * SignatureECDSA
// * SignatureSM2
func (m *Signature) SetSignatureByData(sig SignatureDataInterface, hashAlgo Algorithm) error {
err := m.SetSignatureData(sig)
if err != nil {
return err
}
switch sig := sig.(type) {
case SignatureRSAPSS:
m.SigScheme = AlgRSAPSS
if hashAlgo.IsNull() {
m.HashAlg = AlgSHA256
} else {
m.HashAlg = hashAlgo
}
m.KeySize.SetInBytes(uint16(len(m.Data)))
case SignatureRSAASA:
m.SigScheme = AlgRSASSA
if hashAlgo.IsNull() {
m.HashAlg = AlgSHA256
} else {
m.HashAlg = hashAlgo
}
m.KeySize.SetInBytes(uint16(len(m.Data)))
case SignatureECDSA:
m.SigScheme = AlgECDSA
if hashAlgo.IsNull() {
m.HashAlg = AlgSHA512
} else {
m.HashAlg = hashAlgo
}
m.KeySize.SetInBits(uint16(sig.R.BitLen()))
case SignatureSM2:
m.SigScheme = AlgSM2
if hashAlgo.IsNull() {
m.HashAlg = AlgSM3
} else {
m.HashAlg = hashAlgo
}
m.KeySize.SetInBits(uint16(sig.R.BitLen()))
default:
return fmt.Errorf("unexpected signature type: %T", sig)
}
return nil
}
// SetSignatureData sets the value of the field Data by accepting one of these
// types as the input argument `sig`:
// * SignatureRSAPSS
// * SignatureRSAASA
// * SignatureECDSA
// * SignatureSM2
func (m *Signature) SetSignatureData(sig SignatureDataInterface) error {
switch sig := sig.(type) {
case SignatureRSAPSS:
m.Data = sig
case SignatureRSAASA:
m.Data = sig
case SignatureECDSA, SignatureSM2:
var r, s *big.Int
switch sig := sig.(type) {
case SignatureECDSA:
r, s = sig.R, sig.S
case SignatureSM2:
r, s = sig.R, sig.S
default:
return fmt.Errorf("internal error")
}
if r.BitLen() != s.BitLen() {
return fmt.Errorf("the length of component R (%d) is not equal to the length of component S (%d)", r.BitLen(), s.BitLen())
}
if r.BitLen() != 256 && r.BitLen() != 384 {
return fmt.Errorf("component R (or S) size should be 256 or 384 bites (not %d)", r.BitLen())
}
m.Data = make([]byte, r.BitLen()/8+s.BitLen()/8)
copy(m.Data[:], reverseBytes(r.Bytes()))
copy(m.Data[r.BitLen()/8:], reverseBytes(s.Bytes()))
default:
return fmt.Errorf("unexpected signature type: %T", sig)
}
return nil
}
// SetSignature calculates the signature accordingly to arguments signAlgo,
// privKey and signedData; and sets all the fields of the structure Signature.
//
// if signAlgo is zero then it is detected automatically, based on the type
// of the provided private key.
func (m *Signature) SetSignature(signAlgo Algorithm, privKey crypto.Signer, signedData []byte) error {
m.Version = 0x10
signData, err := NewSignatureData(signAlgo, privKey, signedData)
if err != nil {
return fmt.Errorf("unable to construct the signature data: %w", err)
}
err = m.SetSignatureByData(signData, AlgNull)
if err != nil {
return fmt.Errorf("unable to set the signature: %w", err)
}
return nil
}
// FillSignature sets the signature accordingly to arguments signAlgo,
// pubKey and signedData; and sets all the fields of the structure Signature.
//
// if signAlgo is zero then it is detected automatically, based on the type
// of the provided private key.
func (m *Signature) FillSignature(signAlgo Algorithm, pubKey crypto.PublicKey, signedData []byte, hashAlgo Algorithm) error {
m.Version = 0x10
signData, err := NewSignatureByData(signAlgo, pubKey, signedData)
if err != nil {
return fmt.Errorf("unable to construct the signature data: %w", err)
}
err = m.SetSignatureByData(signData, hashAlgo)
if err != nil {
return fmt.Errorf("unable to set the signature: %w", err)
}
return nil
}