github.com/emmansun/gmsm@v0.29.1/pkcs7/sign_test.go (about)

     1  package pkcs7
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/x509"
     6  	"encoding/asn1"
     7  	"encoding/pem"
     8  	"fmt"
     9  	"io/ioutil"
    10  	"log"
    11  	"os"
    12  	"os/exec"
    13  	"testing"
    14  
    15  	"github.com/emmansun/gmsm/smx509"
    16  )
    17  
    18  func testSign(t *testing.T, isSM bool, content []byte, sigalgs []x509.SignatureAlgorithm) {
    19  	for _, sigalgroot := range sigalgs {
    20  		rootCert, err := createTestCertificateByIssuer("PKCS7 Test Root CA", nil, sigalgroot, true)
    21  		if err != nil {
    22  			t.Fatalf("test %s: cannot generate root cert: %s", sigalgroot, err)
    23  		}
    24  		truststore := smx509.NewCertPool()
    25  		truststore.AddCert(rootCert.Certificate)
    26  		for _, sigalginter := range sigalgs {
    27  			interCert, err := createTestCertificateByIssuer("PKCS7 Test Intermediate Cert", rootCert, sigalginter, true)
    28  			if err != nil {
    29  				t.Fatalf("test %s/%s: cannot generate intermediate cert: %s", sigalgroot, sigalginter, err)
    30  			}
    31  			var parents []*smx509.Certificate
    32  			parents = append(parents, interCert.Certificate)
    33  			for _, sigalgsigner := range sigalgs {
    34  				signerCert, err := createTestCertificateByIssuer("PKCS7 Test Signer Cert", interCert, sigalgsigner, false)
    35  				if err != nil {
    36  					t.Fatalf("test %s/%s/%s: cannot generate signer cert: %s", sigalgroot, sigalginter, sigalgsigner, err)
    37  				}
    38  				for _, testDetach := range []bool{false, true} {
    39  					log.Printf("test %s/%s/%s detached %t\n", sigalgroot, sigalginter, sigalgsigner, testDetach)
    40  					var toBeSigned *SignedData
    41  					if isSM {
    42  						toBeSigned, err = NewSMSignedData(content)
    43  					} else {
    44  						toBeSigned, err = NewSignedData(content)
    45  					}
    46  					if err != nil {
    47  						t.Fatalf("test %s/%s/%s: cannot initialize signed data: %s", sigalgroot, sigalginter, sigalgsigner, err)
    48  					}
    49  
    50  					// Set the digest to match the end entity cert
    51  					signerDigest, _ := getDigestOIDForSignatureAlgorithm(sigalgsigner)
    52  					toBeSigned.SetDigestAlgorithm(signerDigest)
    53  
    54  					if err := toBeSigned.AddSignerChain(signerCert.Certificate, *signerCert.PrivateKey, parents, SignerInfoConfig{}); err != nil {
    55  						t.Fatalf("test %s/%s/%s: cannot add signer: %s", sigalgroot, sigalginter, sigalgsigner, err)
    56  					}
    57  					if testDetach {
    58  						toBeSigned.Detach()
    59  					}
    60  					signed, err := toBeSigned.Finish()
    61  					if err != nil {
    62  						t.Fatalf("test %s/%s/%s: cannot finish signing data: %s", sigalgroot, sigalginter, sigalgsigner, err)
    63  					}
    64  					pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: signed})
    65  					p7, err := Parse(signed)
    66  					if err != nil {
    67  						t.Fatalf("test %s/%s/%s: cannot parse signed data: %s", sigalgroot, sigalginter, sigalgsigner, err)
    68  					}
    69  					if testDetach {
    70  						// Detached signature should not contain the content
    71  						// So we should not be able to find the content in the parsed data
    72  						// We should suppliment the content to the parsed data before verifying
    73  						p7.Content = content
    74  					}
    75  					if !bytes.Equal(content, p7.Content) {
    76  						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)
    77  					}
    78  					if err := p7.VerifyWithChain(truststore); err != nil {
    79  						t.Errorf("test %s/%s/%s: cannot verify signed data: %s", sigalgroot, sigalginter, sigalgsigner, err)
    80  					}
    81  					if !signerDigest.Equal(p7.Signers[0].DigestAlgorithm.Algorithm) {
    82  						t.Errorf("test %s/%s/%s: expected digest algorithm %q but got %q",
    83  							sigalgroot, sigalginter, sigalgsigner, signerDigest, p7.Signers[0].DigestAlgorithm.Algorithm)
    84  					}
    85  				}
    86  			}
    87  		}
    88  	}
    89  }
    90  func TestSign(t *testing.T) {
    91  	content := []byte("Hello World")
    92  	sigalgs := []x509.SignatureAlgorithm{
    93  		x509.SHA1WithRSA,
    94  		x509.SHA256WithRSA,
    95  		x509.SHA512WithRSA,
    96  		x509.ECDSAWithSHA1,
    97  		x509.ECDSAWithSHA256,
    98  		x509.ECDSAWithSHA384,
    99  		x509.ECDSAWithSHA512,
   100  		smx509.SM2WithSM3,
   101  	}
   102  	testSign(t, false, content, sigalgs)
   103  }
   104  
   105  func TestSignSM(t *testing.T) {
   106  	content := []byte("Hello World")
   107  	sigalgs := []x509.SignatureAlgorithm{
   108  		smx509.SM2WithSM3,
   109  	}
   110  	testSign(t, true, content, sigalgs)
   111  }
   112  
   113  func ExampleSignedData() {
   114  	// generate a signing cert or load a key pair
   115  	cert, err := createTestCertificate(x509.SHA256WithRSA)
   116  	if err != nil {
   117  		fmt.Printf("Cannot create test certificates: %s", err)
   118  	}
   119  
   120  	// Initialize a SignedData struct with content to be signed
   121  	signedData, err := NewSignedData([]byte("Example data to be signed"))
   122  	if err != nil {
   123  		fmt.Printf("Cannot initialize signed data: %s", err)
   124  	}
   125  
   126  	// Add the signing cert and private key
   127  	if err := signedData.AddSigner(cert.Certificate, cert.PrivateKey, SignerInfoConfig{}); err != nil {
   128  		fmt.Printf("Cannot add signer: %s", err)
   129  	}
   130  
   131  	// Call Detach() is you want to remove content from the signature
   132  	// and generate an S/MIME detached signature
   133  	signedData.Detach()
   134  
   135  	// Finish() to obtain the signature bytes
   136  	detachedSignature, err := signedData.Finish()
   137  	if err != nil {
   138  		fmt.Printf("Cannot finish signing data: %s", err)
   139  	}
   140  	pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: detachedSignature})
   141  }
   142  
   143  func TestUnmarshalSignedAttribute(t *testing.T) {
   144  	cert, err := createTestCertificate(x509.SHA512WithRSA)
   145  	if err != nil {
   146  		t.Fatal(err)
   147  	}
   148  	content := []byte("Hello World")
   149  	toBeSigned, err := NewSignedData(content)
   150  	if err != nil {
   151  		t.Fatalf("Cannot initialize signed data: %s", err)
   152  	}
   153  	oidTest := asn1.ObjectIdentifier{2, 3, 4, 5, 6, 7}
   154  	testValue := "TestValue"
   155  	if err := toBeSigned.AddSigner(cert.Certificate, *cert.PrivateKey, SignerInfoConfig{
   156  		ExtraSignedAttributes: []Attribute{{Type: oidTest, Value: testValue}},
   157  	}); err != nil {
   158  		t.Fatalf("Cannot add signer: %s", err)
   159  	}
   160  	signed, err := toBeSigned.Finish()
   161  	if err != nil {
   162  		t.Fatalf("Cannot finish signing data: %s", err)
   163  	}
   164  	p7, err := Parse(signed)
   165  	if err != nil {
   166  		t.Fatalf("Cannot parse signed data: %v", err)
   167  	}
   168  	var actual string
   169  	err = p7.UnmarshalSignedAttribute(oidTest, &actual)
   170  	if err != nil {
   171  		t.Fatalf("Cannot unmarshal test value: %s", err)
   172  	}
   173  	if testValue != actual {
   174  		t.Errorf("Attribute does not match test value\n\tExpected: %s\n\tActual: %s", testValue, actual)
   175  	}
   176  	err = p7.Verify()
   177  	if err != nil {
   178  		t.Fatal(err)
   179  	}
   180  }
   181  
   182  func TestSkipCertificates(t *testing.T) {
   183  	cert, err := createTestCertificate(x509.SHA512WithRSA)
   184  	if err != nil {
   185  		t.Fatal(err)
   186  	}
   187  	content := []byte("Hello World")
   188  	toBeSigned, err := NewSignedData(content)
   189  	if err != nil {
   190  		t.Fatalf("Cannot initialize signed data: %s", err)
   191  	}
   192  
   193  	if err := toBeSigned.AddSigner(cert.Certificate, *cert.PrivateKey, SignerInfoConfig{}); err != nil {
   194  		t.Fatalf("Cannot add signer: %s", err)
   195  	}
   196  	signed, err := toBeSigned.Finish()
   197  	if err != nil {
   198  		t.Fatalf("Cannot finish signing data: %s", err)
   199  	}
   200  	p7, err := Parse(signed)
   201  	if err != nil {
   202  		t.Fatalf("Cannot parse signed data: %v", err)
   203  	}
   204  	if len(p7.Certificates) == 0 {
   205  		t.Errorf("No certificates")
   206  	}
   207  
   208  	toBeSigned2, err := NewSignedData(content)
   209  	if err != nil {
   210  		t.Fatalf("Cannot initialize signed data: %s", err)
   211  	}
   212  	if err := toBeSigned2.AddSigner(cert.Certificate, *cert.PrivateKey, SignerInfoConfig{SkipCertificates: true}); err != nil {
   213  		t.Fatalf("Cannot add signer: %s", err)
   214  	}
   215  	signed, err = toBeSigned2.Finish()
   216  	if err != nil {
   217  		t.Fatalf("Cannot finish signing data: %s", err)
   218  	}
   219  	p7, err = Parse(signed)
   220  	if err != nil {
   221  		t.Fatalf("Cannot parse signed data: %v", err)
   222  	}
   223  	if len(p7.Certificates) > 0 {
   224  		t.Errorf("Have certificates: %v", p7.Certificates)
   225  	}
   226  	// For skip certificates, we should not be able to verify the signature
   227  	// because the signer certificate is not in the chain
   228  	// we should suppliment the signer certificate to the parsed data before verifying
   229  	p7.Certificates = append(p7.Certificates, cert.Certificate)
   230  	err = p7.Verify()
   231  	if err != nil {
   232  		t.Fatal(err)
   233  	}
   234  }
   235  
   236  func TestDegenerateCertificate(t *testing.T) {
   237  	cert, err := createTestCertificate(x509.SHA1WithRSA)
   238  	if err != nil {
   239  		t.Fatal(err)
   240  	}
   241  	deg, err := DegenerateCertificate(cert.Certificate.Raw)
   242  	if err != nil {
   243  		t.Fatal(err)
   244  	}
   245  	testOpenSSLParse(t, deg)
   246  	pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: deg})
   247  }
   248  
   249  // writes the cert to a temporary file and tests that openssl can read it.
   250  func testOpenSSLParse(t *testing.T, certBytes []byte) {
   251  	tmpCertFile, err := ioutil.TempFile("", "testCertificate")
   252  	if err != nil {
   253  		t.Fatal(err)
   254  	}
   255  	defer os.Remove(tmpCertFile.Name()) // clean up
   256  
   257  	if _, err := tmpCertFile.Write(certBytes); err != nil {
   258  		t.Fatal(err)
   259  	}
   260  
   261  	opensslCMD := exec.Command("openssl", "pkcs7", "-inform", "der", "-in", tmpCertFile.Name())
   262  	_, err = opensslCMD.Output()
   263  	if err != nil {
   264  		t.Fatal(err)
   265  	}
   266  
   267  	if err := tmpCertFile.Close(); err != nil {
   268  		t.Fatal(err)
   269  	}
   270  }
   271  
   272  func TestSignWithoutAttr(t *testing.T) {
   273  	content := []byte("Hello World")
   274  	sigalgs := []struct {
   275  		isSM     bool
   276  		sigAlg   x509.SignatureAlgorithm
   277  		skipCert bool
   278  	}{
   279  		{
   280  			false,
   281  			x509.SHA256WithRSA,
   282  			false,
   283  		},
   284  		{
   285  			true,
   286  			smx509.SM2WithSM3,
   287  			false,
   288  		},
   289  		{
   290  			false,
   291  			x509.SHA256WithRSA,
   292  			true,
   293  		},
   294  		{
   295  			true,
   296  			smx509.SM2WithSM3,
   297  			true,
   298  		},
   299  	}
   300  	for _, sigalg := range sigalgs {
   301  		cert, err := createTestCertificate(sigalg.sigAlg)
   302  		if err != nil {
   303  			t.Fatal(err)
   304  		}
   305  		var toBeSigned *SignedData
   306  		if sigalg.isSM {
   307  			toBeSigned, err = NewSMSignedData(content)
   308  		} else {
   309  			toBeSigned, err = NewSignedData(content)
   310  			signerDigest, _ := getDigestOIDForSignatureAlgorithm(sigalg.sigAlg)
   311  			toBeSigned.SetDigestAlgorithm(signerDigest)
   312  		}
   313  		if err != nil {
   314  			t.Fatalf("Cannot initialize signed data: %s", err)
   315  		}
   316  		if err := toBeSigned.SignWithoutAttr(cert.Certificate, *cert.PrivateKey, SignerInfoConfig{SkipCertificates: sigalg.skipCert}); err != nil {
   317  			t.Fatalf("Cannot add signer: %s", err)
   318  		}
   319  		signed, err := toBeSigned.Finish()
   320  		if err != nil {
   321  			t.Fatalf("Cannot finish signing data: %s", err)
   322  		}
   323  		p7, err := Parse(signed)
   324  		if err != nil {
   325  			t.Fatalf("Cannot parse signed data: %v", err)
   326  		}
   327  		if !sigalg.skipCert {
   328  			if len(p7.Certificates) == 0 {
   329  				t.Errorf("No certificates")
   330  			}
   331  			err = p7.Verify()
   332  			if err != nil {
   333  				t.Fatal(err)
   334  			}
   335  		} else {
   336  			if len(p7.Certificates) > 0 {
   337  				t.Errorf("No certificates expected")
   338  			}
   339  			err = p7.Verify()
   340  			if sigalg.skipCert && err.Error() != "pkcs7: No certificate for signer" {
   341  				t.Fatalf("Expected pkcs7: No certificate for signer")
   342  			}
   343  			p7.Certificates = append(p7.Certificates, cert.Certificate)
   344  			err = p7.Verify()
   345  			if err != nil {
   346  				t.Fatal(err)
   347  			}
   348  		}
   349  	}
   350  }