1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package x509tools
18
19 import (
20 "crypto"
21 "crypto/ecdsa"
22 "crypto/rsa"
23 "crypto/x509"
24 "crypto/x509/pkix"
25 "encoding/asn1"
26 "errors"
27 "fmt"
28 )
29
30 var (
31
32 OidPublicKeyRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
33 OidPublicKeyDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1}
34 OidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
35
36 oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
37 oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
38 oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
39 oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
40 oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
41 oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
42 oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
43 oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2}
44 oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
45 oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
46 oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
47 oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
48 oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29}
49
50
51 OidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8}
52 OidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10}
53
54 Asn1TagBMPString = 30
55 )
56
57 type sigAlgInfo struct {
58 oid asn1.ObjectIdentifier
59 pubKeyAlgo x509.PublicKeyAlgorithm
60 hash crypto.Hash
61 }
62
63 var sigAlgInfos = []sigAlgInfo{
64
65 {OidPublicKeyRSA, x509.RSA, 0},
66 {OidSignatureRSAPSS, x509.RSA, 0},
67 {OidPublicKeyDSA, x509.DSA, 0},
68 {OidPublicKeyECDSA, x509.ECDSA, 0},
69
70 {oidSignatureMD5WithRSA, x509.RSA, crypto.MD5},
71 {oidSignatureSHA1WithRSA, x509.RSA, crypto.SHA1},
72 {oidISOSignatureSHA1WithRSA, x509.RSA, crypto.SHA1},
73 {oidSignatureSHA256WithRSA, x509.RSA, crypto.SHA256},
74 {oidSignatureSHA384WithRSA, x509.RSA, crypto.SHA384},
75 {oidSignatureSHA512WithRSA, x509.RSA, crypto.SHA512},
76 {oidSignatureDSAWithSHA1, x509.DSA, crypto.SHA1},
77 {oidSignatureDSAWithSHA256, x509.DSA, crypto.SHA256},
78 {oidSignatureECDSAWithSHA1, x509.ECDSA, crypto.SHA1},
79 {oidSignatureECDSAWithSHA256, x509.ECDSA, crypto.SHA256},
80 {oidSignatureECDSAWithSHA384, x509.ECDSA, crypto.SHA384},
81 {oidSignatureECDSAWithSHA512, x509.ECDSA, crypto.SHA512},
82 }
83
84
85 func PkixAlgorithms(pub crypto.PublicKey, opts crypto.SignerOpts) (digestAlg, sigAlg pkix.AlgorithmIdentifier, err error) {
86 digestAlg, ok := PkixDigestAlgorithm(opts.HashFunc())
87 if !ok {
88 err = errors.New("unsupported digest algorithm")
89 return
90 }
91 if pss, ok := opts.(*rsa.PSSOptions); ok {
92 rsapub, ok := pub.(*rsa.PublicKey)
93 if !ok {
94 err = errors.New("RSA-PSS is only valid for RSA keys")
95 return
96 }
97 var params asn1.RawValue
98 params, err = MarshalRSAPSSParameters(rsapub, pss)
99 if err != nil {
100 return
101 }
102 sigAlg = pkix.AlgorithmIdentifier{
103 Algorithm: OidSignatureRSAPSS,
104 Parameters: params,
105 }
106 return
107 }
108 switch pub.(type) {
109 case *rsa.PublicKey:
110 sigAlg.Algorithm = OidPublicKeyRSA
111 case *ecdsa.PublicKey:
112 sigAlg.Algorithm = OidPublicKeyECDSA
113 default:
114 err = errors.New("unsupported public key algorithm")
115 return
116 }
117 sigAlg.Parameters = asn1.NullRawValue
118 return
119 }
120
121
122 func PkixDigestAlgorithm(hash crypto.Hash) (alg pkix.AlgorithmIdentifier, ok bool) {
123 if oid, ok2 := HashOids[hash]; ok2 {
124 alg.Algorithm = oid
125 alg.Parameters = asn1.NullRawValue
126 ok = true
127 }
128 return
129 }
130
131
132 func PkixDigestToHash(alg pkix.AlgorithmIdentifier) (hash crypto.Hash, ok bool) {
133 for hash, oid := range HashOids {
134 if alg.Algorithm.Equal(oid) {
135 return hash, true
136 }
137 }
138 return 0, false
139 }
140
141
142 func PkixDigestToHashE(alg pkix.AlgorithmIdentifier) (hash crypto.Hash, err error) {
143 hash, ok := PkixDigestToHash(alg)
144 if ok && hash.Available() {
145 return hash, nil
146 }
147 return 0, UnknownDigestError{Algorithm: alg.Algorithm}
148 }
149
150
151 func PkixPublicKeyAlgorithm(pub crypto.PublicKey) (alg pkix.AlgorithmIdentifier, ok bool) {
152 _, alg, err := PkixAlgorithms(pub, nil)
153 return alg, err == nil
154 }
155
156
157 func PkixVerify(pub crypto.PublicKey, digestAlg, sigAlg pkix.AlgorithmIdentifier, digest, sig []byte) error {
158 hash, err := PkixDigestToHashE(digestAlg)
159 if err != nil {
160 return err
161 }
162 var info sigAlgInfo
163 for _, a := range sigAlgInfos {
164 if sigAlg.Algorithm.Equal(a.oid) {
165 info = a
166 }
167 }
168 if info.hash != 0 && info.hash != hash {
169 return errors.New("signature type does not match digest type")
170 }
171 switch info.pubKeyAlgo {
172 case x509.RSA:
173 key, ok := pub.(*rsa.PublicKey)
174 if !ok {
175 return errors.New("incorrect key type for signature")
176 }
177 if sigAlg.Algorithm.Equal(OidSignatureRSAPSS) {
178 opts, err := UnmarshalRSAPSSParameters(hash, sigAlg.Parameters)
179 if err != nil {
180 return err
181 }
182 return rsa.VerifyPSS(key, hash, digest, sig, opts)
183 }
184 return rsa.VerifyPKCS1v15(key, hash, digest, sig)
185 case x509.ECDSA:
186 key, ok := pub.(*ecdsa.PublicKey)
187 if !ok {
188 return errors.New("incorrect key type for signature")
189 }
190 esig, err := UnmarshalEcdsaSignature(sig)
191 if err != nil {
192 return err
193 }
194 if !ecdsa.Verify(key, digest, esig.R, esig.S) {
195 return errors.New("ECDSA verification failed")
196 }
197 return nil
198 default:
199 return errors.New("unsupported public key algorithm")
200 }
201 }
202
203 type UnknownDigestError struct {
204 Algorithm asn1.ObjectIdentifier
205 }
206
207 func (e UnknownDigestError) Error() string {
208 return fmt.Sprintf("unsupported hash algorithm %s", e.Algorithm)
209 }
210
View as plain text