1 package pkcs7
2
3 import (
4 "bytes"
5 "crypto"
6 "crypto/dsa"
7 "crypto/x509"
8 "encoding/asn1"
9 "encoding/pem"
10 "fmt"
11 "io/ioutil"
12 "math/big"
13 "os"
14 "os/exec"
15 "testing"
16 )
17
18 func TestSign(t *testing.T) {
19 content := []byte("Hello World")
20 sigalgs := []x509.SignatureAlgorithm{
21 x509.SHA1WithRSA,
22 x509.SHA256WithRSA,
23 x509.SHA512WithRSA,
24 x509.ECDSAWithSHA1,
25 x509.ECDSAWithSHA256,
26 x509.ECDSAWithSHA384,
27 x509.ECDSAWithSHA512,
28 x509.PureEd25519,
29 }
30 for _, sigalgroot := range sigalgs {
31 rootCert, err := createTestCertificateByIssuer("PKCS7 Test Root CA", nil, sigalgroot, true)
32 if err != nil {
33 t.Fatalf("test %s: cannot generate root cert: %s", sigalgroot, err)
34 }
35 truststore := x509.NewCertPool()
36 truststore.AddCert(rootCert.Certificate)
37 for _, sigalginter := range sigalgs {
38 interCert, err := createTestCertificateByIssuer("PKCS7 Test Intermediate Cert", rootCert, sigalginter, true)
39 if err != nil {
40 t.Fatalf("test %s/%s: cannot generate intermediate cert: %s", sigalgroot, sigalginter, err)
41 }
42 var parents []*x509.Certificate
43 parents = append(parents, interCert.Certificate)
44 for _, sigalgsigner := range sigalgs {
45 signerCert, err := createTestCertificateByIssuer("PKCS7 Test Signer Cert", interCert, sigalgsigner, false)
46 if err != nil {
47 t.Fatalf("test %s/%s/%s: cannot generate signer cert: %s", sigalgroot, sigalginter, sigalgsigner, err)
48 }
49 for _, testDetach := range []bool{false, true} {
50 toBeSigned, err := NewSignedData(content)
51 if err != nil {
52 t.Fatalf("test %s/%s/%s: cannot initialize signed data: %s", sigalgroot, sigalginter, sigalgsigner, err)
53 }
54
55
56 signerDigest, _ := GetDigestOIDForSignatureAlgorithm(signerCert.Certificate.SignatureAlgorithm)
57 toBeSigned.SetDigestAlgorithm(signerDigest)
58
59 if err := toBeSigned.AddSignerChain(signerCert.Certificate, *signerCert.PrivateKey, parents, SignerInfoConfig{}); err != nil {
60 t.Fatalf("test %s/%s/%s: cannot add signer: %s", sigalgroot, sigalginter, sigalgsigner, err)
61 }
62 if testDetach {
63 toBeSigned.Detach()
64 }
65 signed, err := toBeSigned.Finish()
66 if err != nil {
67 t.Fatalf("test %s/%s/%s: cannot finish signing data: %s", sigalgroot, sigalginter, sigalgsigner, err)
68 }
69 p7, err := Parse(signed)
70 if err != nil {
71 t.Fatalf("test %s/%s/%s: cannot parse signed data: %s", sigalgroot, sigalginter, sigalgsigner, err)
72 }
73 if testDetach {
74 p7.Content = content
75 }
76 if !bytes.Equal(content, p7.Content) {
77 t.Errorf("test %s/%s/%s: content was not found in the parsed data:\n\tExpected: %s\n\tActual: %s", sigalgroot, sigalginter, sigalgsigner, content, p7.Content)
78 }
79 if err := p7.VerifyWithChain(truststore); err != nil {
80 t.Errorf("test %s/%s/%s: cannot verify signed data: %s", sigalgroot, sigalginter, sigalgsigner, err)
81 }
82 if !signerDigest.Equal(p7.Signers[0].DigestAlgorithm.Algorithm) {
83 t.Errorf("test %s/%s/%s: expected digest algorithm %q but got %q",
84 sigalgroot, sigalginter, sigalgsigner, signerDigest, p7.Signers[0].DigestAlgorithm.Algorithm)
85 }
86 }
87 }
88 }
89 }
90 }
91
92 func TestDSASignAndVerifyWithOpenSSL(t *testing.T) {
93 content := []byte("Hello World")
94
95 tmpContentFile, err := ioutil.TempFile("", "TestDSASignAndVerifyWithOpenSSL_content")
96 if err != nil {
97 t.Fatal(err)
98 }
99 ioutil.WriteFile(tmpContentFile.Name(), content, 0755)
100
101 block, _ := pem.Decode([]byte(dsaPublicCert))
102 if block == nil {
103 t.Fatal("failed to parse certificate PEM")
104 }
105 signerCert, err := x509.ParseCertificate(block.Bytes)
106 if err != nil {
107 t.Fatal("failed to parse certificate: " + err.Error())
108 }
109
110
111 tmpSignerCertFile, err := ioutil.TempFile("", "TestDSASignAndVerifyWithOpenSSL_signer")
112 if err != nil {
113 t.Fatal(err)
114 }
115 ioutil.WriteFile(tmpSignerCertFile.Name(), dsaPublicCert, 0755)
116
117 priv := dsa.PrivateKey{
118 PublicKey: dsa.PublicKey{Parameters: dsa.Parameters{P: fromHex("fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7"),
119 Q: fromHex("9760508F15230BCCB292B982A2EB840BF0581CF5"),
120 G: fromHex("F7E1A085D69B3DDECBBCAB5C36B857B97994AFBBFA3AEA82F9574C0B3D0782675159578EBAD4594FE67107108180B449167123E84C281613B7CF09328CC8A6E13C167A8B547C8D28E0A3AE1E2BB3A675916EA37F0BFA213562F1FB627A01243BCCA4F1BEA8519089A883DFE15AE59F06928B665E807B552564014C3BFECF492A"),
121 },
122 },
123 X: fromHex("7D6E1A3DD4019FD809669D8AB8DA73807CEF7EC1"),
124 }
125 toBeSigned, err := NewSignedData(content)
126 if err != nil {
127 t.Fatalf("test case: cannot initialize signed data: %s", err)
128 }
129 if err := toBeSigned.SignWithoutAttr(signerCert, &priv, SignerInfoConfig{}); err != nil {
130 t.Fatalf("Cannot add signer: %s", err)
131 }
132 toBeSigned.Detach()
133 signed, err := toBeSigned.Finish()
134 if err != nil {
135 t.Fatalf("test case: cannot finish signing data: %s", err)
136 }
137
138
139 tmpSignatureFile, err := ioutil.TempFile("", "TestDSASignAndVerifyWithOpenSSL_signature")
140 if err != nil {
141 t.Fatal(err)
142 }
143 ioutil.WriteFile(tmpSignatureFile.Name(), pem.EncodeToMemory(&pem.Block{Type: "PKCS7", Bytes: signed}), 0755)
144
145
146 opensslCMD := exec.Command("openssl", "smime", "-verify", "-noverify",
147 "-in", tmpSignatureFile.Name(), "-inform", "PEM",
148 "-content", tmpContentFile.Name())
149 out, err := opensslCMD.CombinedOutput()
150 if err != nil {
151 t.Fatalf("test case: openssl command failed with %s: %s", err, out)
152 }
153 os.Remove(tmpSignatureFile.Name())
154 os.Remove(tmpContentFile.Name())
155 os.Remove(tmpSignerCertFile.Name())
156 }
157
158 func TestSignWithoutAttributes(t *testing.T) {
159 content := []byte("Hello World")
160 sigalgs := []x509.SignatureAlgorithm{
161 x509.SHA1WithRSA,
162 x509.SHA256WithRSA,
163 x509.SHA512WithRSA,
164 x509.ECDSAWithSHA1,
165 x509.ECDSAWithSHA256,
166 x509.ECDSAWithSHA384,
167 x509.ECDSAWithSHA512,
168 x509.PureEd25519,
169 }
170 for _, sigalgroot := range sigalgs {
171 rootCert, err := createTestCertificateByIssuer("PKCS7 Test Root CA", nil, sigalgroot, true)
172 if err != nil {
173 t.Fatalf("test %s: cannot generate root cert: %s", sigalgroot, err)
174 }
175 truststore := x509.NewCertPool()
176 truststore.AddCert(rootCert.Certificate)
177 for _, sigalgsigner := range sigalgs {
178 signerCert, err := createTestCertificateByIssuer("PKCS7 Test Signer Cert", rootCert, sigalgsigner, false)
179 if err != nil {
180 t.Fatalf("test %s/%s: cannot generate signer cert: %s", sigalgroot, sigalgsigner, err)
181 }
182 for _, testDetach := range []bool{false, true} {
183 toBeSigned, err := NewSignedData(content)
184 if err != nil {
185 t.Fatalf("test %s/%s: cannot initialize signed data: %s", sigalgroot, sigalgsigner, err)
186 }
187
188
189 signerDigest, _ := GetDigestOIDForSignatureAlgorithm(signerCert.Certificate.SignatureAlgorithm)
190 toBeSigned.SetDigestAlgorithm(signerDigest)
191
192 if err := toBeSigned.SignWithoutAttr(signerCert.Certificate, (*signerCert.PrivateKey).(crypto.Signer), SignerInfoConfig{}); err != nil {
193 t.Fatalf("test %s/%s: cannot add signer: %s", sigalgroot, sigalgsigner, err)
194 }
195 if testDetach {
196 toBeSigned.Detach()
197 }
198 signed, err := toBeSigned.Finish()
199 if err != nil {
200 t.Fatalf("test %s/%s: cannot finish signing data: %s", sigalgroot, sigalgsigner, err)
201 }
202 p7, err := Parse(signed)
203 if err != nil {
204 t.Fatalf("test %s/%s: cannot parse signed data: %s", sigalgroot, sigalgsigner, err)
205 }
206 if testDetach {
207 p7.Content = content
208 }
209 if !bytes.Equal(content, p7.Content) {
210 t.Errorf("test %s/%s: content was not found in the parsed data:\n\tExpected: %s\n\tActual: %s", sigalgroot, sigalgsigner, content, p7.Content)
211 }
212 if err := p7.VerifyWithChain(truststore); err != nil {
213 t.Errorf("test %s/%s: cannot verify signed data: %s", sigalgroot, sigalgsigner, err)
214 }
215 if !signerDigest.Equal(p7.Signers[0].DigestAlgorithm.Algorithm) {
216 t.Errorf("test %s/%s: expected digest algorithm %q but got %q",
217 sigalgroot, sigalgsigner, signerDigest, p7.Signers[0].DigestAlgorithm.Algorithm)
218 }
219 }
220 }
221 }
222 }
223
224 func ExampleSignedData() {
225
226 cert, err := createTestCertificate(x509.SHA256WithRSA)
227 if err != nil {
228 fmt.Printf("Cannot create test certificates: %s", err)
229 }
230
231
232 signedData, err := NewSignedData([]byte("Example data to be signed"))
233 if err != nil {
234 fmt.Printf("Cannot initialize signed data: %s", err)
235 }
236
237
238 if err := signedData.AddSigner(cert.Certificate, cert.PrivateKey, SignerInfoConfig{}); err != nil {
239 fmt.Printf("Cannot add signer: %s", err)
240 }
241
242
243
244 signedData.Detach()
245
246
247 _, err = signedData.Finish()
248 if err != nil {
249 fmt.Printf("Cannot finish signing data: %s", err)
250 }
251 }
252
253 func TestSetContentType(t *testing.T) {
254 cert, err := createTestCertificate(x509.SHA256WithRSA)
255 if err != nil {
256 t.Fatalf("Cannot create test certificates: %s", err)
257 }
258
259 signedData, err := NewSignedData([]byte("Example data to be signed"))
260 if err != nil {
261 t.Fatalf("Cannot initialize signed data: %s", err)
262 }
263
264 idctTSTInfo := asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 1, 4}
265 signedData.SetContentType(idctTSTInfo)
266
267 if err := signedData.AddSigner(cert.Certificate, *cert.PrivateKey, SignerInfoConfig{}); err != nil {
268 t.Fatalf("Cannot add signer: %s", err)
269 }
270
271 _, err = signedData.Finish()
272 if err != nil {
273 t.Fatalf("Cannot finish signing data: %s", err)
274 }
275
276 sd := signedData.GetSignedData()
277 if !sd.ContentInfo.ContentType.Equal(idctTSTInfo) {
278 t.Fatalf("Unexpected content type: %s", err)
279 }
280 }
281
282 func TestUnmarshalSignedAttribute(t *testing.T) {
283 cert, err := createTestCertificate(x509.SHA512WithRSA)
284 if err != nil {
285 t.Fatal(err)
286 }
287 content := []byte("Hello World")
288 toBeSigned, err := NewSignedData(content)
289 if err != nil {
290 t.Fatalf("Cannot initialize signed data: %s", err)
291 }
292 oidTest := asn1.ObjectIdentifier{2, 3, 4, 5, 6, 7}
293 testValue := "TestValue"
294 if err := toBeSigned.AddSigner(cert.Certificate, *cert.PrivateKey, SignerInfoConfig{
295 ExtraSignedAttributes: []Attribute{Attribute{Type: oidTest, Value: testValue}},
296 }); err != nil {
297 t.Fatalf("Cannot add signer: %s", err)
298 }
299 signed, err := toBeSigned.Finish()
300 if err != nil {
301 t.Fatalf("Cannot finish signing data: %s", err)
302 }
303 p7, err := Parse(signed)
304 if err != nil {
305 t.Fatalf("Cannot parse signed data: %v", err)
306 }
307 var actual string
308 err = p7.UnmarshalSignedAttribute(oidTest, &actual)
309 if err != nil {
310 t.Fatalf("Cannot unmarshal test value: %s", err)
311 }
312 if testValue != actual {
313 t.Errorf("Attribute does not match test value\n\tExpected: %s\n\tActual: %s", testValue, actual)
314 }
315 }
316
317 func TestDegenerateCertificate(t *testing.T) {
318 cert, err := createTestCertificate(x509.SHA1WithRSA)
319 if err != nil {
320 t.Fatal(err)
321 }
322 deg, err := DegenerateCertificate(cert.Certificate.Raw)
323 if err != nil {
324 t.Fatal(err)
325 }
326 testOpenSSLParse(t, deg)
327 }
328
329 func TestSkipCertificates(t *testing.T) {
330 cert, err := createTestCertificate(x509.SHA512WithRSA)
331 if err != nil {
332 t.Fatal(err)
333 }
334 content := []byte("Hello World")
335 toBeSigned, err := NewSignedData(content)
336 if err != nil {
337 t.Fatalf("Cannot initialize signed data: %s", err)
338 }
339 if err := toBeSigned.AddSigner(cert.Certificate, *cert.PrivateKey, SignerInfoConfig{
340 SkipCertificates: true,
341 }); err != nil {
342 t.Fatalf("Cannot add signer: %s", err)
343 }
344 signed, err := toBeSigned.Finish()
345 if err != nil {
346 t.Fatalf("Cannot finish signing data: %s", err)
347 }
348 p7, err := Parse(signed)
349 if err != nil {
350 t.Fatalf("Cannot parse signed data: %v", err)
351 }
352 if len(p7.Certificates) > 0 {
353 t.Fatalf("Got %d certificate(s), exected none", len(p7.Certificates))
354 }
355 }
356
357
358 func testOpenSSLParse(t *testing.T, certBytes []byte) {
359 tmpCertFile, err := ioutil.TempFile("", "testCertificate")
360 if err != nil {
361 t.Fatal(err)
362 }
363 defer os.Remove(tmpCertFile.Name())
364
365 if _, err := tmpCertFile.Write(certBytes); err != nil {
366 t.Fatal(err)
367 }
368
369 opensslCMD := exec.Command("openssl", "pkcs7", "-inform", "der", "-in", tmpCertFile.Name())
370 _, err = opensslCMD.Output()
371 if err != nil {
372 t.Fatal(err)
373 }
374
375 if err := tmpCertFile.Close(); err != nil {
376 t.Fatal(err)
377 }
378
379 }
380 func fromHex(s string) *big.Int {
381 result, ok := new(big.Int).SetString(s, 16)
382 if !ok {
383 panic(s)
384 }
385 return result
386 }
387
View as plain text