Skip to content

Commit

Permalink
pkcs7: sync with upstream
Browse files Browse the repository at this point in the history
  • Loading branch information
emmansun authored Jan 16, 2025
1 parent cf6e203 commit cb51b36
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 15 deletions.
9 changes: 0 additions & 9 deletions pkcs7/ber.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import (
"errors"
)

var encodeIndent = 0

type asn1Object interface {
EncodeTo(writer *bytes.Buffer) error
}
Expand All @@ -17,16 +15,13 @@ 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)
if err != nil {
return err
}
}
encodeIndent--
out.Write(s.tagBytes)
encodeLength(out, inner.Len())
out.Write(inner.Bytes())
Expand All @@ -47,18 +42,14 @@ 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
}

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)
Expand Down
4 changes: 4 additions & 0 deletions pkcs7/ber_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -40,6 +41,7 @@ func TestBer2Der(t *testing.T) {
}

func TestBer2Der_Negatives(t *testing.T) {
t.Parallel()
fixtures := []struct {
Input []byte
ErrorContains string
Expand All @@ -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}
Expand Down Expand Up @@ -101,6 +104,7 @@ func TestBer2Der_NestedMultipleIndefinite(t *testing.T) {
}

func TestVerifyIndefiniteLengthBer(t *testing.T) {
t.Parallel()
decoded := mustDecodePEM([]byte(testPKCS7))

_, err := ber2der(decoded)
Expand Down
2 changes: 0 additions & 2 deletions pkcs7/pkcs7_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"log"
"math/big"
"os"
"time"
Expand Down Expand Up @@ -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)
Expand Down
24 changes: 20 additions & 4 deletions pkcs7/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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,
}
}
}
}
Expand Down
101 changes: 101 additions & 0 deletions pkcs7/verify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ package pkcs7
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/base64"
"encoding/pem"
"io/ioutil"
"math/big"
"os"
"os/exec"
"testing"
Expand All @@ -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
Expand Down

0 comments on commit cb51b36

Please sign in to comment.