From cb51b3657a95a54f99fc7e5c192ca362b2d10eb7 Mon Sep 17 00:00:00 2001 From: Sun Yimin Date: Thu, 16 Jan 2025 16:04:45 +0800 Subject: [PATCH] pkcs7: sync with upstream --- pkcs7/ber.go | 9 ---- pkcs7/ber_test.go | 4 ++ pkcs7/pkcs7_test.go | 2 - pkcs7/verify.go | 24 ++++++++-- pkcs7/verify_test.go | 101 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 125 insertions(+), 15 deletions(-) diff --git a/pkcs7/ber.go b/pkcs7/ber.go index b53e1cb5..8565e4c3 100644 --- a/pkcs7/ber.go +++ b/pkcs7/ber.go @@ -5,8 +5,6 @@ import ( "errors" ) -var encodeIndent = 0 - type asn1Object interface { EncodeTo(writer *bytes.Buffer) error } @@ -17,8 +15,6 @@ type asn1Structured struct { } func (s asn1Structured) EncodeTo(out *bytes.Buffer) error { - //fmt.Printf("%s--> tag: % X\n", strings.Repeat("| ", encodeIndent), s.tagBytes) - encodeIndent++ inner := new(bytes.Buffer) for _, obj := range s.content { err := obj.EncodeTo(inner) @@ -26,7 +22,6 @@ func (s asn1Structured) EncodeTo(out *bytes.Buffer) error { return err } } - encodeIndent-- out.Write(s.tagBytes) encodeLength(out, inner.Len()) out.Write(inner.Bytes()) @@ -47,10 +42,7 @@ func (p asn1Primitive) EncodeTo(out *bytes.Buffer) error { if err = encodeLength(out, p.length); err != nil { return err } - //fmt.Printf("%s--> tag: % X length: %d\n", strings.Repeat("| ", encodeIndent), p.tagBytes, p.length) - //fmt.Printf("%s--> content length: %d\n", strings.Repeat("| ", encodeIndent), len(p.content)) out.Write(p.content) - return nil } @@ -58,7 +50,6 @@ func ber2der(ber []byte) ([]byte, error) { if len(ber) == 0 { return nil, errors.New("ber2der: input ber is empty") } - //fmt.Printf("--> ber2der: Transcoding %d bytes\n", len(ber)) out := new(bytes.Buffer) obj, _, err := readObject(ber, 0) diff --git a/pkcs7/ber_test.go b/pkcs7/ber_test.go index 8462b32d..cf8ad049 100644 --- a/pkcs7/ber_test.go +++ b/pkcs7/ber_test.go @@ -10,6 +10,7 @@ import ( ) func TestBer2Der(t *testing.T) { + t.Parallel() // indefinite length fixture ber := []byte{0x30, 0x80, 0x02, 0x01, 0x01, 0x00, 0x00} expected := []byte{0x30, 0x03, 0x02, 0x01, 0x01} @@ -40,6 +41,7 @@ func TestBer2Der(t *testing.T) { } func TestBer2Der_Negatives(t *testing.T) { + t.Parallel() fixtures := []struct { Input []byte ErrorContains string @@ -65,6 +67,7 @@ func TestBer2Der_Negatives(t *testing.T) { } func TestBer2Der_NestedMultipleIndefinite(t *testing.T) { + t.Parallel() // indefinite length fixture ber := []byte{0x30, 0x80, 0x30, 0x80, 0x02, 0x01, 0x01, 0x00, 0x00, 0x30, 0x80, 0x02, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00} expected := []byte{0x30, 0x0A, 0x30, 0x03, 0x02, 0x01, 0x01, 0x30, 0x03, 0x02, 0x01, 0x02} @@ -101,6 +104,7 @@ func TestBer2Der_NestedMultipleIndefinite(t *testing.T) { } func TestVerifyIndefiniteLengthBer(t *testing.T) { + t.Parallel() decoded := mustDecodePEM([]byte(testPKCS7)) _, err := ber2der(decoded) diff --git a/pkcs7/pkcs7_test.go b/pkcs7/pkcs7_test.go index ec707d67..02b80f16 100644 --- a/pkcs7/pkcs7_test.go +++ b/pkcs7/pkcs7_test.go @@ -11,7 +11,6 @@ import ( "crypto/x509/pkix" "encoding/pem" "fmt" - "log" "math/big" "os" "time" @@ -262,7 +261,6 @@ func createTestCertificateByIssuer(name string, issuer *certKeyPair, sigAlg x509 issuerKey = priv } - log.Println("creating cert", name, "issued by", issuerCert.Subject.CommonName, "with sigalg", sigAlg) switch pkey := priv.(type) { case *rsa.PrivateKey: derCert, err = smx509.CreateCertificate(rand.Reader, &template, (*x509.Certificate)(issuerCert), pkey.Public(), issuerKey) diff --git a/pkcs7/verify.go b/pkcs7/verify.go index 3436a45b..11304194 100644 --- a/pkcs7/verify.go +++ b/pkcs7/verify.go @@ -76,6 +76,21 @@ func (p7 *PKCS7) verifyWithChainAtTime(truststore *smx509.CertPool, currentTime return nil } +// InvalidSigningTimeError is returned when the signing time attribute +// falls outside of the signer certificate validity. +type InvalidSigningTimeError struct { + SigningTime time.Time + NotBefore time.Time // NotBefore of signer + NotAfter time.Time // NotAfter of signer +} + +func (e *InvalidSigningTimeError) Error() string { + return fmt.Sprintf("pkcs7: signing time %q is outside of certificate validity %q to %q", + e.SigningTime.Format(time.RFC3339), + e.NotBefore.Format(time.RFC3339), + e.NotAfter.Format(time.RFC3339)) +} + func verifySignature(p7 *PKCS7, signer signerInfo, truststore *smx509.CertPool, currentTime *time.Time, isDigest bool) (err error) { signedData := p7.Content ee := getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber) @@ -118,10 +133,11 @@ func verifySignature(p7 *PKCS7, signer signerInfo, truststore *smx509.CertPool, if err == nil { // signing time found, performing validity check if signingTime.After(ee.NotAfter) || signingTime.Before(ee.NotBefore) { - return fmt.Errorf("pkcs7: signing time %q is outside of certificate validity %q to %q", - signingTime.Format(time.RFC3339), - ee.NotBefore.Format(time.RFC3339), - ee.NotAfter.Format(time.RFC3339)) + return &InvalidSigningTimeError{ + SigningTime: signingTime, + NotBefore: ee.NotBefore, + NotAfter: ee.NotAfter, + } } } } diff --git a/pkcs7/verify_test.go b/pkcs7/verify_test.go index 44a3bad3..751c14a0 100644 --- a/pkcs7/verify_test.go +++ b/pkcs7/verify_test.go @@ -3,6 +3,8 @@ package pkcs7 import ( "bytes" "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" @@ -10,6 +12,7 @@ import ( "encoding/base64" "encoding/pem" "io/ioutil" + "math/big" "os" "os/exec" "testing" @@ -35,6 +38,104 @@ func TestVerify(t *testing.T) { } } +func TestInvalidSigningTime(t *testing.T) { + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatalf("failed generating ECDSA key: %v", err) + } + + // define certificate validity to a timeframe in the past, so that + // the certificate itself is not valid at the time of signing. + notBefore := time.Now().UTC().Round(time.Minute).Add(-2 * time.Hour) + notAfter := time.Now().UTC().Round(time.Minute).Add(-1 * time.Hour) + template := &x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + CommonName: "TestInvalidSigningtime", + }, + NotBefore: notBefore, + NotAfter: notAfter, + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageEmailProtection}, + } + + der, err := smx509.CreateCertificate(rand.Reader, template, template, key.Public(), key) + if err != nil { + t.Fatalf("failed creating certificate: %v", err) + } + + cert, err := smx509.ParseCertificate(der) + if err != nil { + t.Fatalf("failed parsing certificate: %v", err) + } + + toBeSignedData, err := NewSignedData([]byte("test-invalid-signing-time")) + if err != nil { + t.Fatalf("failed creating signed data: %v", err) + } + + // add the signer cert, and add attributes, including the signing + // time attribute, containing the current time + if err := toBeSignedData.AddSigner(cert, key, SignerInfoConfig{}); err != nil { + t.Fatalf("failed adding signer: %v", err) + } + + // finalizes the signed data + signedData, err := toBeSignedData.Finish() + if err != nil { + t.Fatalf("failed signing data: %v", err) + } + + p7, err := Parse(signedData) + if err != nil { + t.Fatalf("failed parsing signed data: %v", err) + } + + signerCert := p7.GetOnlySigner() + if !bytes.Equal(cert.Signature, signerCert.Signature) { + t.Fatal("unexpected signer certificate obtained from P7 data") + } + + // verify without a chain (self-signed cert), at time.Now() + now := time.Now() + err = p7.VerifyWithChainAtTime(nil, &now) + if err == nil { + t.Fatal("expected verification error, but got nil") + } + + signingTimeErr, ok := err.(*InvalidSigningTimeError) + if !ok { + t.Fatalf("expected *InvalidSigningTimeError, but got %T", err) + } + + if signingTimeErr.NotBefore != notBefore { + t.Errorf("expected notBefore to be %q, but got %q", notBefore, signingTimeErr.NotBefore) + } + + if signingTimeErr.NotAfter != notAfter { + t.Errorf("expected notAfter to be %q, but got %q", notAfter, signingTimeErr.NotAfter) + } + + // verify without a chain (self-signed cert), but without specifying the time + err = p7.VerifyWithChain(nil) + if err == nil { + t.Fatal("expected verification error, but got nil") + } + + signingTimeErr, ok = err.(*InvalidSigningTimeError) + if !ok { + t.Fatalf("expected *InvalidSigningTimeError, but got %T", err) + } + + if signingTimeErr.NotBefore != notBefore { + t.Errorf("expected notBefore to be %q, but got %q", notBefore, signingTimeErr.NotBefore) + } + + if signingTimeErr.NotAfter != notAfter { + t.Errorf("expected notAfter to be %q, but got %q", notAfter, signingTimeErr.NotAfter) + } +} + var SignedTestFixture = ` -----BEGIN PKCS7----- MIIDVgYJKoZIhvcNAQcCoIIDRzCCA0MCAQExCTAHBgUrDgMCGjAcBgkqhkiG9w0B