pkcs7: support GetRecipients #252

This commit is contained in:
Sun Yimin 2024-09-30 08:26:42 +08:00 committed by GitHub
parent 3968b9d8b5
commit ff59b79d60
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 92 additions and 0 deletions

View File

@ -6,23 +6,55 @@ import (
"crypto/rand"
"encoding/asn1"
"errors"
"math/big"
"github.com/emmansun/gmsm/pkcs"
"github.com/emmansun/gmsm/sm2"
"github.com/emmansun/gmsm/smx509"
)
// IssuerAndSerial is a structure that holds the issuer name and serial number
type IssuerAndSerial struct {
RawIssuer []byte
SerialNumber *big.Int
}
func newIssuerAndSerial(issuerAndSerial issuerAndSerial) IssuerAndSerial {
is := IssuerAndSerial{}
if len(issuerAndSerial.IssuerName.FullBytes) > 0 {
is.RawIssuer = make([]byte, len(issuerAndSerial.IssuerName.FullBytes))
copy(is.RawIssuer, issuerAndSerial.IssuerName.FullBytes)
}
if issuerAndSerial.SerialNumber != nil {
is.SerialNumber = new(big.Int).Set(issuerAndSerial.SerialNumber)
}
return is
}
// ErrUnsupportedAlgorithm tells you when our quick dev assumptions have failed
var ErrUnsupportedAlgorithm = errors.New("pkcs7: cannot decrypt data: only RSA, SM2, DES, DES-EDE3, AES and SM4 supported")
// ErrNotEncryptedContent is returned when attempting to Decrypt data that is not encrypted data
var ErrNotEncryptedContent = errors.New("pkcs7: content data is NOT a decryptable data type")
// ErrNotEnvelopedData is returned when attempting to Decrypt data that is not enveloped data
var ErrNotEnvelopedData = errors.New("pkcs7: content data is NOT an enveloped data type")
type decryptable interface {
GetRecipient(cert *smx509.Certificate) *recipientInfo
GetRecipients() ([]IssuerAndSerial, error)
GetEncryptedContentInfo() *encryptedContentInfo
}
// GetRecipients returns the list of recipients for the enveloped data
func (p7 *PKCS7) GetRecipients() ([]IssuerAndSerial, error) {
decryptableData, ok := p7.raw.(decryptable)
if !ok {
return nil, ErrNotEnvelopedData
}
return decryptableData.GetRecipients()
}
// Decrypt decrypts encrypted content info for recipient cert and private key
func (p7 *PKCS7) Decrypt(cert *smx509.Certificate, pkey crypto.PrivateKey) ([]byte, error) {
return p7.decrypt(cert, pkey, false)

View File

@ -11,6 +11,19 @@ func TestDecrypt(t *testing.T) {
if err != nil {
t.Fatal(err)
}
recipents, err := p7.GetRecipients()
if err != nil {
t.Fatal(err)
}
if len(recipents) != 1 {
t.Errorf("Expected 1 recipient, got %d", len(recipents))
}
if recipents[0].SerialNumber.Cmp(fixture.Certificate.SerialNumber) != 0 {
t.Errorf("Recipient serial number does not match.\n\tExpected:%s\n\tActual:%s", fixture.Certificate.SerialNumber, recipents[0].SerialNumber)
}
if !bytes.Equal(recipents[0].RawIssuer, fixture.Certificate.RawIssuer) {
t.Errorf("Recipient issuer name does not match.\n\tExpected:%x\n\tActual:%x", fixture.Certificate.RawIssuer, recipents[0].RawIssuer)
}
content, err := p7.Decrypt(fixture.Certificate, fixture.PrivateKey)
if err != nil {
t.Errorf("Cannot Decrypt with error: %v", err)

View File

@ -30,6 +30,10 @@ func TestEncryptUsingPSK(t *testing.T) {
}
p7, _ := Parse(ciphertext)
_, err = p7.GetRecipients()
if err != ErrNotEnvelopedData {
t.Errorf("expected ErrNotEnvelopedData, got %v", err)
}
result, err := p7.DecryptUsingPSK(key)
if err != nil {
t.Fatalf("cannot Decrypt encrypted result: %s", err)

View File

@ -48,6 +48,15 @@ func (data envelopedData) GetRecipient(cert *smx509.Certificate) *recipientInfo
return nil
}
// GetRecipients returns the list of recipients (READONLY) for the enveloped data
func (data envelopedData) GetRecipients() ([]IssuerAndSerial, error) {
var recipients []IssuerAndSerial
for _, recp := range data.RecipientInfos {
recipients = append(recipients, newIssuerAndSerial(recp.IssuerAndSerialNumber))
}
return recipients, nil
}
func (data envelopedData) GetEncryptedContentInfo() *encryptedContentInfo {
return &data.EncryptedContentInfo
}

View File

@ -34,6 +34,15 @@ func (data signedEnvelopedData) GetRecipient(cert *smx509.Certificate) *recipien
return nil
}
// GetRecipients returns the list of recipients (READONLY) for the enveloped data
func (data signedEnvelopedData) GetRecipients() ([]IssuerAndSerial, error) {
var recipients []IssuerAndSerial
for _, recp := range data.RecipientInfos {
recipients = append(recipients, newIssuerAndSerial(recp.IssuerAndSerialNumber))
}
return recipients, nil
}
func (data signedEnvelopedData) GetEncryptedContentInfo() *encryptedContentInfo {
return &data.EncryptedContentInfo
}

View File

@ -103,6 +103,14 @@ func TestParseSignedEvnvelopedData(t *testing.T) {
t.Fatal("should only one certificate")
}
recipients, err := p7Data.GetRecipients()
if err != nil {
t.Fatal(err)
}
if len(recipients) != 1 {
t.Fatal("should only one recipient")
}
block, rest = pem.Decode([]byte(signKey))
if len(rest) != 0 {
t.Fatal("unexpected remaining PEM block during decode")
@ -263,6 +271,23 @@ func TestCreateSignedEvnvelopedData(t *testing.T) {
if err != nil {
t.Fatal(err)
}
recipients, err := p7Data.GetRecipients()
if err != nil {
t.Fatal(err)
}
if len(recipients) != 1 {
t.Fatal("should only one recipient")
}
if recipients[0].SerialNumber.Cmp(recipient.Certificate.SerialNumber) != 0 {
t.Errorf("Recipient serial number does not match.\n\tExpected:%s\n\tActual:%s", recipient.Certificate.SerialNumber, recipients[0].SerialNumber)
}
if !bytes.Equal(recipients[0].RawIssuer, recipient.Certificate.RawIssuer) {
t.Errorf("Recipient issuer name does not match.\n\tExpected:%x\n\tActual:%x", recipient.Certificate.RawIssuer, recipients[0].RawIssuer)
}
encKeyBytes, err := p7Data.DecryptAndVerify(recipient.Certificate, *recipient.PrivateKey, func() error {
return p7Data.Verify()
})