mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-26 20:26:19 +08:00
pkcs7: improve compatibility with CFCA #270
This commit is contained in:
parent
c9f55b045f
commit
0205d1ae47
@ -19,6 +19,13 @@ type IssuerAndSerial struct {
|
|||||||
SerialNumber *big.Int
|
SerialNumber *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RecipientInfo is a structure that holds the recipient information
|
||||||
|
// supports IssuerAndSerial and SubjectKeyIdentifier.
|
||||||
|
type RecipientInfo struct {
|
||||||
|
IssuerAndSerial
|
||||||
|
SubjectKeyIdentifier []byte
|
||||||
|
}
|
||||||
|
|
||||||
func newIssuerAndSerial(issuerAndSerial issuerAndSerial) IssuerAndSerial {
|
func newIssuerAndSerial(issuerAndSerial issuerAndSerial) IssuerAndSerial {
|
||||||
is := IssuerAndSerial{}
|
is := IssuerAndSerial{}
|
||||||
if len(issuerAndSerial.IssuerName.FullBytes) > 0 {
|
if len(issuerAndSerial.IssuerName.FullBytes) > 0 {
|
||||||
@ -31,6 +38,17 @@ func newIssuerAndSerial(issuerAndSerial issuerAndSerial) IssuerAndSerial {
|
|||||||
return is
|
return is
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newRecipientInfo(recipientInfo recipientInfo) RecipientInfo {
|
||||||
|
ri := RecipientInfo{
|
||||||
|
IssuerAndSerial: newIssuerAndSerial(recipientInfo.IssuerAndSerialNumber),
|
||||||
|
}
|
||||||
|
if len(recipientInfo.SubjectKeyIdentifier.Bytes) > 0 {
|
||||||
|
ri.SubjectKeyIdentifier = append(ri.SubjectKeyIdentifier, recipientInfo.SubjectKeyIdentifier.Bytes...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ri
|
||||||
|
}
|
||||||
|
|
||||||
// ErrUnsupportedAlgorithm tells you when our quick dev assumptions have failed
|
// 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")
|
var ErrUnsupportedAlgorithm = errors.New("pkcs7: cannot decrypt data: only RSA, SM2, DES, DES-EDE3, AES and SM4 supported")
|
||||||
|
|
||||||
@ -42,12 +60,12 @@ var ErrNotEnvelopedData = errors.New("pkcs7: content data is NOT an enveloped da
|
|||||||
|
|
||||||
type decryptable interface {
|
type decryptable interface {
|
||||||
GetRecipient(cert *smx509.Certificate) *recipientInfo
|
GetRecipient(cert *smx509.Certificate) *recipientInfo
|
||||||
GetRecipients() ([]IssuerAndSerial, error)
|
GetRecipients() ([]RecipientInfo, error)
|
||||||
GetEncryptedContentInfo() *encryptedContentInfo
|
GetEncryptedContentInfo() *encryptedContentInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRecipients returns the list of recipients for the enveloped data
|
// GetRecipients returns the list of recipients for the enveloped data
|
||||||
func (p7 *PKCS7) GetRecipients() ([]IssuerAndSerial, error) {
|
func (p7 *PKCS7) GetRecipients() ([]RecipientInfo, error) {
|
||||||
decryptableData, ok := p7.raw.(decryptable)
|
decryptableData, ok := p7.raw.(decryptable)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, ErrNotEnvelopedData
|
return nil, ErrNotEnvelopedData
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package pkcs7
|
package pkcs7
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
|
"crypto/sha1"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
"errors"
|
"errors"
|
||||||
@ -11,6 +13,8 @@ import (
|
|||||||
"github.com/emmansun/gmsm/pkcs"
|
"github.com/emmansun/gmsm/pkcs"
|
||||||
"github.com/emmansun/gmsm/sm2"
|
"github.com/emmansun/gmsm/sm2"
|
||||||
"github.com/emmansun/gmsm/smx509"
|
"github.com/emmansun/gmsm/smx509"
|
||||||
|
"golang.org/x/crypto/cryptobyte"
|
||||||
|
cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
|
||||||
)
|
)
|
||||||
|
|
||||||
type EnvelopedData struct {
|
type EnvelopedData struct {
|
||||||
@ -28,7 +32,8 @@ type envelopedData struct {
|
|||||||
|
|
||||||
type recipientInfo struct {
|
type recipientInfo struct {
|
||||||
Version int
|
Version int
|
||||||
IssuerAndSerialNumber issuerAndSerial
|
IssuerAndSerialNumber issuerAndSerial `asn1:"optional"`
|
||||||
|
SubjectKeyIdentifier asn1.RawValue `asn1:"tag:0,optional"`
|
||||||
KeyEncryptionAlgorithm pkix.AlgorithmIdentifier
|
KeyEncryptionAlgorithm pkix.AlgorithmIdentifier
|
||||||
EncryptedKey []byte
|
EncryptedKey []byte
|
||||||
}
|
}
|
||||||
@ -43,16 +48,39 @@ func (data envelopedData) GetRecipient(cert *smx509.Certificate) *recipientInfo
|
|||||||
for _, recp := range data.RecipientInfos {
|
for _, recp := range data.RecipientInfos {
|
||||||
if isCertMatchForIssuerAndSerial(cert, recp.IssuerAndSerialNumber) {
|
if isCertMatchForIssuerAndSerial(cert, recp.IssuerAndSerialNumber) {
|
||||||
return &recp
|
return &recp
|
||||||
|
} else if len(recp.SubjectKeyIdentifier.Bytes) > 0 {
|
||||||
|
// This is for the case when the recipient is identified by the SubjectKeyId instead of the IssuerAndSerial
|
||||||
|
subjectKeyID := cert.SubjectKeyId
|
||||||
|
// SubjectKeyId is optional, so we need to check if it's set before comparing
|
||||||
|
if len(subjectKeyID) == 0 {
|
||||||
|
var (
|
||||||
|
inner cryptobyte.String
|
||||||
|
pub asn1.BitString
|
||||||
|
)
|
||||||
|
input := cryptobyte.String(cert.RawSubjectPublicKeyInfo)
|
||||||
|
if input.ReadASN1(&inner, cryptobyte_asn1.SEQUENCE) &&
|
||||||
|
input.Empty() &&
|
||||||
|
inner.SkipASN1(cryptobyte_asn1.SEQUENCE) &&
|
||||||
|
inner.ReadASN1BitString(&pub) &&
|
||||||
|
inner.Empty() {
|
||||||
|
h := sha1.Sum(pub.RightAlign())
|
||||||
|
subjectKeyID = h[:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(subjectKeyID) > 0 && bytes.Equal(subjectKeyID, recp.SubjectKeyIdentifier.Bytes) {
|
||||||
|
return &recp
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRecipients returns the list of recipients (READONLY) for the enveloped data
|
// GetRecipients returns the list of recipients (READONLY) for the enveloped data
|
||||||
func (data envelopedData) GetRecipients() ([]IssuerAndSerial, error) {
|
func (data envelopedData) GetRecipients() ([]RecipientInfo, error) {
|
||||||
var recipients []IssuerAndSerial
|
var recipients []RecipientInfo
|
||||||
for _, recp := range data.RecipientInfos {
|
for _, recp := range data.RecipientInfos {
|
||||||
recipients = append(recipients, newIssuerAndSerial(recp.IssuerAndSerialNumber))
|
recipients = append(recipients, newRecipientInfo(recp))
|
||||||
}
|
}
|
||||||
return recipients, nil
|
return recipients, nil
|
||||||
}
|
}
|
||||||
@ -92,7 +120,7 @@ func Encrypt(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificat
|
|||||||
//
|
//
|
||||||
// The algorithm used to perform encryption is determined by the argument cipher
|
// The algorithm used to perform encryption is determined by the argument cipher
|
||||||
func EncryptSM(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate) ([]byte, error) {
|
func EncryptSM(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate) ([]byte, error) {
|
||||||
return encryptSM(cipher, content, recipients, false)
|
return encryptSM(cipher, content, recipients, 1, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncryptCFCA creates and returns an envelope data PKCS7 structure with encrypted
|
// EncryptCFCA creates and returns an envelope data PKCS7 structure with encrypted
|
||||||
@ -101,16 +129,25 @@ func EncryptSM(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certific
|
|||||||
//
|
//
|
||||||
// The algorithm used to perform encryption is determined by the argument cipher
|
// The algorithm used to perform encryption is determined by the argument cipher
|
||||||
func EncryptCFCA(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate) ([]byte, error) {
|
func EncryptCFCA(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate) ([]byte, error) {
|
||||||
return encryptSM(cipher, content, recipients, true)
|
return encryptSM(cipher, content, recipients, 1, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func encryptSM(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate, isLegacyCFCA bool) ([]byte, error) {
|
// EnvelopeMessageCFCA creates and returns an envelope data PKCS7 structure with encrypted
|
||||||
|
// recipient keys for each recipient public key.
|
||||||
|
// The OIDs use GM/T 0010 - 2012 set and the encrypted key uses ASN.1 format.
|
||||||
|
// This function uses recipient's SubjectKeyIdentifier to identify the recipient.
|
||||||
|
// This function is used for CFCA compatibility.
|
||||||
|
func EnvelopeMessageCFCA(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate) ([]byte, error) {
|
||||||
|
return encryptSM(cipher, content, recipients, 2, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func encryptSM(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate, version int, isLegacyCFCA bool) ([]byte, error) {
|
||||||
ed, err := NewSM2EnvelopedData(cipher, content)
|
ed, err := NewSM2EnvelopedData(cipher, content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, recipient := range recipients {
|
for _, recipient := range recipients {
|
||||||
if err := ed.AddRecipient(recipient, 1, func(cert *smx509.Certificate, key []byte) ([]byte, error) {
|
if err := ed.AddRecipient(recipient, version, func(cert *smx509.Certificate, key []byte) ([]byte, error) {
|
||||||
return encryptKey(key, cert, isLegacyCFCA)
|
return encryptKey(key, cert, isLegacyCFCA)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -121,33 +158,16 @@ func encryptSM(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certific
|
|||||||
|
|
||||||
// NewEnvelopedData creates a new EnvelopedData structure with the provided cipher and content.
|
// NewEnvelopedData creates a new EnvelopedData structure with the provided cipher and content.
|
||||||
func NewEnvelopedData(cipher pkcs.Cipher, content []byte) (*EnvelopedData, error) {
|
func NewEnvelopedData(cipher pkcs.Cipher, content []byte) (*EnvelopedData, error) {
|
||||||
var key []byte
|
return newEnvelopedData(cipher, content, OIDEnvelopedData)
|
||||||
var err error
|
|
||||||
|
|
||||||
// Create key
|
|
||||||
key = make([]byte, cipher.KeySize())
|
|
||||||
if _, err = rand.Read(key); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
id, ciphertext, err := cipher.Encrypt(rand.Reader, key, content)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ed := &EnvelopedData{}
|
|
||||||
ed.contentType = OIDEnvelopedData
|
|
||||||
ed.encryptedContentType = OIDData
|
|
||||||
ed.key = key
|
|
||||||
ed.ed = envelopedData{
|
|
||||||
Version: 0,
|
|
||||||
EncryptedContentInfo: newEncryptedContent(ed.encryptedContentType, id, marshalEncryptedContent(ciphertext)),
|
|
||||||
}
|
|
||||||
return ed, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSM2EnvelopedData creates a new EnvelopedData structure with the provided cipher and content.
|
// NewSM2EnvelopedData creates a new EnvelopedData structure with the provided cipher and content.
|
||||||
// The OIDs use GM/T 0010 - 2012 set.
|
// The OIDs use GM/T 0010 - 2012 set.
|
||||||
func NewSM2EnvelopedData(cipher pkcs.Cipher, content []byte) (*EnvelopedData, error) {
|
func NewSM2EnvelopedData(cipher pkcs.Cipher, content []byte) (*EnvelopedData, error) {
|
||||||
|
return newEnvelopedData(cipher, content, SM2OIDEnvelopedData)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newEnvelopedData(cipher pkcs.Cipher, content []byte, contentType asn1.ObjectIdentifier) (*EnvelopedData, error) {
|
||||||
var key []byte
|
var key []byte
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
@ -162,23 +182,30 @@ func NewSM2EnvelopedData(cipher pkcs.Cipher, content []byte) (*EnvelopedData, er
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ed := &EnvelopedData{}
|
ed := &EnvelopedData{}
|
||||||
ed.contentType = SM2OIDEnvelopedData
|
ed.contentType = contentType
|
||||||
|
ed.encryptedContentType = OIDData
|
||||||
|
version := 0
|
||||||
|
if SM2OIDEnvelopedData.Equal(contentType) {
|
||||||
ed.encryptedContentType = SM2OIDData
|
ed.encryptedContentType = SM2OIDData
|
||||||
|
version = 1
|
||||||
|
}
|
||||||
ed.key = key
|
ed.key = key
|
||||||
ed.ed = envelopedData{
|
ed.ed = envelopedData{
|
||||||
Version: 1,
|
Version: version,
|
||||||
EncryptedContentInfo: newEncryptedContent(ed.encryptedContentType, id, marshalEncryptedContent(ciphertext)),
|
EncryptedContentInfo: newEncryptedContent(ed.encryptedContentType, id, marshalEncryptedContent(ciphertext)),
|
||||||
}
|
}
|
||||||
return ed, nil
|
return ed, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddRecipient adds a recipient to the EnvelopedData structure.
|
// AddRecipient adds a recipient to the EnvelopedData structure.
|
||||||
|
// version 0: IssuerAndSerialNumber
|
||||||
|
// version 1: SM2
|
||||||
|
// version 2: SubjectKeyIdentifier
|
||||||
func (ed *EnvelopedData) AddRecipient(cert *smx509.Certificate, version int, encryptKeyFunc func(cert *smx509.Certificate, key []byte) ([]byte, error)) error {
|
func (ed *EnvelopedData) AddRecipient(cert *smx509.Certificate, version int, encryptKeyFunc func(cert *smx509.Certificate, key []byte) ([]byte, error)) error {
|
||||||
encrypted, err := encryptKeyFunc(cert, ed.key)
|
if version < 0 || version > 2 {
|
||||||
if err != nil {
|
return errors.New("pkcs7: invalid recipient version")
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
ias, err := cert2issuerAndSerial(cert)
|
encrypted, err := encryptKeyFunc(cert, ed.key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -189,19 +216,40 @@ func (ed *EnvelopedData) AddRecipient(cert *smx509.Certificate, version int, enc
|
|||||||
|
|
||||||
info := recipientInfo{
|
info := recipientInfo{
|
||||||
Version: version,
|
Version: version,
|
||||||
IssuerAndSerialNumber: ias,
|
|
||||||
KeyEncryptionAlgorithm: pkix.AlgorithmIdentifier{
|
KeyEncryptionAlgorithm: pkix.AlgorithmIdentifier{
|
||||||
Algorithm: keyEncryptionAlgorithm,
|
Algorithm: keyEncryptionAlgorithm,
|
||||||
Parameters: asn1.NullRawValue,
|
Parameters: asn1.NullRawValue,
|
||||||
},
|
},
|
||||||
EncryptedKey: encrypted,
|
EncryptedKey: encrypted,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if version == 2 {
|
||||||
|
if len(cert.SubjectKeyId) == 0 {
|
||||||
|
return errors.New("pkcs7: envelope required certificate extension SubjectKeyIdentifier")
|
||||||
|
}
|
||||||
|
info.SubjectKeyIdentifier = asn1.RawValue{Tag: 0, Class: asn1.ClassContextSpecific, Bytes: cert.SubjectKeyId}
|
||||||
|
} else {
|
||||||
|
ias, err := cert2issuerAndSerial(cert)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
info.IssuerAndSerialNumber = ias
|
||||||
|
}
|
||||||
ed.ed.RecipientInfos = append(ed.ed.RecipientInfos, info)
|
ed.ed.RecipientInfos = append(ed.ed.RecipientInfos, info)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finish creates the final PKCS7 structure.
|
// Finish creates the final PKCS7 structure.
|
||||||
func (ed *EnvelopedData) Finish() ([]byte, error) {
|
func (ed *EnvelopedData) Finish() ([]byte, error) {
|
||||||
|
// Check if we need to upgrade the version to 2
|
||||||
|
for _, recp := range ed.ed.RecipientInfos {
|
||||||
|
if recp.Version == 2 {
|
||||||
|
ed.ed.Version = 2
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
innerContent, err := asn1.Marshal(ed.ed)
|
innerContent, err := asn1.Marshal(ed.ed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -3,14 +3,67 @@ package pkcs7
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"crypto/x509/pkix"
|
||||||
|
"encoding/asn1"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/emmansun/gmsm/pkcs"
|
"github.com/emmansun/gmsm/pkcs"
|
||||||
|
"github.com/emmansun/gmsm/sm2"
|
||||||
"github.com/emmansun/gmsm/smx509"
|
"github.com/emmansun/gmsm/smx509"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestRecipientInfo(t *testing.T) {
|
||||||
|
recipientInfo := recipientInfo{
|
||||||
|
Version: 1,
|
||||||
|
IssuerAndSerialNumber: issuerAndSerial{},
|
||||||
|
SubjectKeyIdentifier: asn1.RawValue{},
|
||||||
|
KeyEncryptionAlgorithm: pkix.AlgorithmIdentifier{
|
||||||
|
Algorithm: OIDEncryptionAlgorithmRSA,
|
||||||
|
Parameters: asn1.NullRawValue,
|
||||||
|
},
|
||||||
|
EncryptedKey: []byte("encrypted key"),
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes, err := asn1.Marshal(recipientInfo)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if hex.EncodeToString(bytes) != "3021020101300d06092a864886f70d0101010500040d656e63727970746564206b6579" {
|
||||||
|
t.Fatal("failed to marshal recipient info, expected: 3021020101300d06092a864886f70d0101010500040d656e63727970746564206b6579, got:", hex.EncodeToString(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
recipientInfo.IssuerAndSerialNumber = issuerAndSerial{
|
||||||
|
IssuerName: asn1.RawValue{},
|
||||||
|
SerialNumber: big.NewInt(123456),
|
||||||
|
}
|
||||||
|
bytes, err = asn1.Marshal(recipientInfo)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if hex.EncodeToString(bytes) != "302a02010130070000020301e240300d06092a864886f70d0101010500040d656e63727970746564206b6579" {
|
||||||
|
t.Fatal("failed to marshal recipient info, expected: 302a02010130070000020301e240300d06092a864886f70d0101010500040d656e63727970746564206b6579, got:", hex.EncodeToString(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
recipientInfo.SubjectKeyIdentifier = asn1.RawValue{
|
||||||
|
Class: asn1.ClassContextSpecific,
|
||||||
|
Tag: 0,
|
||||||
|
IsCompound: false,
|
||||||
|
Bytes: []byte("subject key identifier"),
|
||||||
|
}
|
||||||
|
recipientInfo.IssuerAndSerialNumber.SerialNumber = nil
|
||||||
|
bytes, err = asn1.Marshal(recipientInfo)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if hex.EncodeToString(bytes) != "303902010180167375626a656374206b6579206964656e746966696572300d06092a864886f70d0101010500040d656e63727970746564206b6579" {
|
||||||
|
t.Fatal("failed to marshal recipient info, expected: 303902010180167375626a656374206b6579206964656e746966696572300d06092a864886f70d0101010500040d656e63727970746564206b6579, got:", hex.EncodeToString(bytes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestEncrypt(t *testing.T) {
|
func TestEncrypt(t *testing.T) {
|
||||||
ciphers := []pkcs.Cipher{
|
ciphers := []pkcs.Cipher{
|
||||||
pkcs.DESCBC,
|
pkcs.DESCBC,
|
||||||
@ -33,7 +86,7 @@ func TestEncrypt(t *testing.T) {
|
|||||||
for _, cipher := range ciphers {
|
for _, cipher := range ciphers {
|
||||||
for _, sigalg := range sigalgs {
|
for _, sigalg := range sigalgs {
|
||||||
plaintext := []byte("Hello Secret World!")
|
plaintext := []byte("Hello Secret World!")
|
||||||
cert, err := createTestCertificate(sigalg)
|
cert, err := createTestCertificate(sigalg, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -67,7 +120,7 @@ func TestEncryptSM(t *testing.T) {
|
|||||||
for _, cipher := range ciphers {
|
for _, cipher := range ciphers {
|
||||||
for _, sigalg := range sigalgs {
|
for _, sigalg := range sigalgs {
|
||||||
plaintext := []byte("Hello Secret World!")
|
plaintext := []byte("Hello Secret World!")
|
||||||
cert, err := createTestCertificate(sigalg)
|
cert, err := createTestCertificate(sigalg, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -103,7 +156,7 @@ func TestEncryptCFCA(t *testing.T) {
|
|||||||
for _, cipher := range ciphers {
|
for _, cipher := range ciphers {
|
||||||
for _, sigalg := range sigalgs {
|
for _, sigalg := range sigalgs {
|
||||||
plaintext := []byte("Hello Secret World!")
|
plaintext := []byte("Hello Secret World!")
|
||||||
cert, err := createTestCertificate(sigalg)
|
cert, err := createTestCertificate(sigalg, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -126,3 +179,123 @@ func TestEncryptCFCA(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOpenEnvelopedMessageWithSubjectKeyID(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
cert, pk, envelopedMsg string
|
||||||
|
}{
|
||||||
|
{ // case with recipient_policy_requiredSubjectKeyId
|
||||||
|
cert: `
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBuDCCAV+gAwIBAgIFAJFSEacwCgYIKoEcz1UBg3UwKTEQMA4GA1UEChMHQWNt
|
||||||
|
ZSBDbzEVMBMGA1UEAxMMRWRkYXJkIFN0YXJrMB4XDTI0MTExODA3MzE0NVoXDTI1
|
||||||
|
MTExODA3MzE0NlowJTEQMA4GA1UEChMHQWNtZSBDbzERMA8GA1UEAxMISm9uIFNu
|
||||||
|
b3cwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAASghjdohTwJilIskjwM8cCujIxc
|
||||||
|
aZ4t1PdRE3TSihbfnifJF+q55qR88pC+SJwl6U2Wpr5sz4TOmmrPp6437oazo3gw
|
||||||
|
djAOBgNVHQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwQwDwYDVR0TAQH/
|
||||||
|
BAUwAwEB/zAdBgNVHQ4EFgQU0M8ZE1AABLJjOnDM8sjQ/Z8dsPYwHwYDVR0jBBgw
|
||||||
|
FoAUZOzkEm2S511/1i/JnKEe7DrX1U0wCgYIKoEcz1UBg3UDRwAwRAIgGvXkxK+X
|
||||||
|
Hv1BCzwKwmR598C8TL3ocRWawh3AroRj9eACIAW6aRyqEsv44if5qO9vlfgreODv
|
||||||
|
heM60r948JI2OvMW
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
`,
|
||||||
|
pk: "f043481ce3ba1332cc266ae795f2a41f100e52e47ee560de15d9e014acab35c9",
|
||||||
|
envelopedMsg: `
|
||||||
|
-----BEGIN PKCS7-----
|
||||||
|
MIH9BgoqgRzPVQYBBAIDoIHuMIHrAgECMYGoMIGlAgECgBTQzxkTUAAEsmM6cMzy
|
||||||
|
yND9nx2w9jANBgkqgRzPVQGCLQMFAAR7MHkCIBKzH9XkTn+cOb8SGcXPk//8pRFC
|
||||||
|
n13W+AQiZyb9/R53AiEA5U4c+efh30mWd2sXtE1+MrvUUSg8X4nu+VKRze5Oq3gE
|
||||||
|
IFi6CF7AXjFgt4t7TVxpn0uLMrz3HljWDKkIqsYNOCzsBBB2NSP32EJPrw+rCzO2
|
||||||
|
z408MDsGCiqBHM9VBgEEAgEwGwYHKoEcz1UBaAQQb88RbJjqyynzqbSgUpQMaYAQ
|
||||||
|
rwVyRbByCMGE5zrbo6EwAg==
|
||||||
|
-----END PKCS7-----
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{ // case with recipient_policy_useSubjectKeyIdExt
|
||||||
|
cert: `
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBiDCCAS6gAwIBAgIENWipfDAKBggqgRzPVQGDdTApMRAwDgYDVQQKEwdBY21l
|
||||||
|
IENvMRUwEwYDVQQDEwxFZGRhcmQgU3RhcmswHhcNMjQxMTE5MDIyNzE4WhcNMjUx
|
||||||
|
MTE5MDIyNzE5WjAlMRAwDgYDVQQKEwdBY21lIENvMREwDwYDVQQDEwhKb24gU25v
|
||||||
|
dzBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABJFW5KAFkKFMMdCnRg7B6ntwSqRR
|
||||||
|
rmcyelmENz3ZXGDj0TcGCuScOCgtMQOFZTwGeu7TlLd1L6tRrh6rFStuv+2jSDBG
|
||||||
|
MA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDBDAfBgNVHSMEGDAW
|
||||||
|
gBQVt+9uB19T4yA+R34KmqNXHI4SLTAKBggqgRzPVQGDdQNIADBFAiEA+cvUlTDE
|
||||||
|
Ydqxaqvj1LNNxGpoYBEfAuQlKoK+xuSTVToCIHg8dnm7FTB79Gx4qGK/nCgGNqK4
|
||||||
|
Bz90uNf5gvRXF0mU
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
`,
|
||||||
|
pk: "8f3d7f612401b9fa80ababb603e8e2ae977cc171c75e97b0b103b9db1d7d190e",
|
||||||
|
envelopedMsg: `
|
||||||
|
-----BEGIN PKCS7-----
|
||||||
|
MIH8BgoqgRzPVQYBBAIDoIHtMIHqAgECMYGnMIGkAgECgBS2m2LapHwibk3oObGg
|
||||||
|
5+JRDnDKPDANBgkqgRzPVQGCLQMFAAR6MHgCIFQQZYPJVXnSibUq87DKTMoHcLLM
|
||||||
|
brCBPz3RF/3Vp9AZAiAkETF7Gbyv3cg7vt48qPoPs4HH4TDRjpgiQk+8oPCmqAQg
|
||||||
|
ImgG5JOVBU3aoxeSCotYs3cUwAzWZyEi9pxQY2+3znIEEF0zrswN4wdXae/SelQU
|
||||||
|
RmgwOwYKKoEcz1UGAQQCATAbBgcqgRzPVQFoBBAZJrpOlPlWo4VvWEpHkGfDgBAV
|
||||||
|
4QgsbZcB/rIV1btrG0yq
|
||||||
|
-----END PKCS7-----
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
msgBytes, _ := pem.Decode([]byte(c.envelopedMsg))
|
||||||
|
p7, err := Parse(msgBytes.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot Parse encrypted result: %s", err)
|
||||||
|
}
|
||||||
|
certificate, err := smx509.ParseCertificatePEM([]byte(c.cert))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot Parse certificate: %s", err)
|
||||||
|
}
|
||||||
|
sm2pkBytes, _ := hex.DecodeString(c.pk)
|
||||||
|
sm2pk, err := sm2.NewPrivateKeyFromInt(new(big.Int).SetBytes(sm2pkBytes))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot Parse private key: %s", err)
|
||||||
|
}
|
||||||
|
result, err := p7.Decrypt(certificate, sm2pk)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot Decrypt encrypted result: %s", err)
|
||||||
|
}
|
||||||
|
expected := []byte("Hello World!")
|
||||||
|
if !bytes.Equal(expected, result) {
|
||||||
|
t.Errorf("encrypted data does not match plaintext:\n\tExpected: %s\n\tActual: %s", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnvelopeMessageCFCA(t *testing.T) {
|
||||||
|
ciphers := []pkcs.Cipher{
|
||||||
|
pkcs.SM4,
|
||||||
|
pkcs.SM4CBC,
|
||||||
|
}
|
||||||
|
sigalgs := []x509.SignatureAlgorithm{
|
||||||
|
smx509.SM2WithSM3,
|
||||||
|
}
|
||||||
|
for _, cipher := range ciphers {
|
||||||
|
for _, sigalg := range sigalgs {
|
||||||
|
plaintext := []byte("Hello Secret World!")
|
||||||
|
cert, err := createTestCertificate(sigalg, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
encrypted, err := EnvelopeMessageCFCA(cipher, plaintext, []*smx509.Certificate{cert.Certificate})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: encrypted})
|
||||||
|
p7, err := Parse(encrypted)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot Parse encrypted result: %s", err)
|
||||||
|
}
|
||||||
|
result, err := p7.Decrypt(cert.Certificate, *cert.PrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot Decrypt encrypted result: %s", err)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(plaintext, result) {
|
||||||
|
t.Errorf("encrypted data does not match plaintext:\n\tExpected: %s\n\tActual: %s", plaintext, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -262,7 +262,7 @@ func (raw rawCertificates) Parse() ([]*smx509.Certificate, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func isCertMatchForIssuerAndSerial(cert *smx509.Certificate, ias issuerAndSerial) bool {
|
func isCertMatchForIssuerAndSerial(cert *smx509.Certificate, ias issuerAndSerial) bool {
|
||||||
return cert.SerialNumber.Cmp(ias.SerialNumber) == 0 && bytes.Equal(cert.RawIssuer, ias.IssuerName.FullBytes)
|
return ias.SerialNumber != nil && cert.SerialNumber.Cmp(ias.SerialNumber) == 0 && bytes.Equal(cert.RawIssuer, ias.IssuerName.FullBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attribute represents a key value pair attribute. Value must be marshalable byte
|
// Attribute represents a key value pair attribute. Value must be marshalable byte
|
||||||
|
@ -86,12 +86,12 @@ type certKeyPair struct {
|
|||||||
PrivateKey *crypto.PrivateKey
|
PrivateKey *crypto.PrivateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTestCertificate(sigAlg x509.SignatureAlgorithm) (certKeyPair, error) {
|
func createTestCertificate(sigAlg x509.SignatureAlgorithm, allCA bool) (certKeyPair, error) {
|
||||||
signer, err := createTestCertificateByIssuer("Eddard Stark", nil, sigAlg, true)
|
signer, err := createTestCertificateByIssuer("Eddard Stark", nil, sigAlg, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return certKeyPair{}, err
|
return certKeyPair{}, err
|
||||||
}
|
}
|
||||||
pair, err := createTestCertificateByIssuer("Jon Snow", signer, sigAlg, false)
|
pair, err := createTestCertificateByIssuer("Jon Snow", signer, sigAlg, allCA)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return certKeyPair{}, err
|
return certKeyPair{}, err
|
||||||
}
|
}
|
||||||
|
@ -35,10 +35,10 @@ func (data signedEnvelopedData) GetRecipient(cert *smx509.Certificate) *recipien
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetRecipients returns the list of recipients (READONLY) for the enveloped data
|
// GetRecipients returns the list of recipients (READONLY) for the enveloped data
|
||||||
func (data signedEnvelopedData) GetRecipients() ([]IssuerAndSerial, error) {
|
func (data signedEnvelopedData) GetRecipients() ([]RecipientInfo, error) {
|
||||||
var recipients []IssuerAndSerial
|
var recipients []RecipientInfo
|
||||||
for _, recp := range data.RecipientInfos {
|
for _, recp := range data.RecipientInfos {
|
||||||
recipients = append(recipients, newIssuerAndSerial(recp.IssuerAndSerialNumber))
|
recipients = append(recipients, newRecipientInfo(recp))
|
||||||
}
|
}
|
||||||
return recipients, nil
|
return recipients, nil
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,7 @@ func TestSignSM(t *testing.T) {
|
|||||||
|
|
||||||
func ExampleSignedData() {
|
func ExampleSignedData() {
|
||||||
// generate a signing cert or load a key pair
|
// generate a signing cert or load a key pair
|
||||||
cert, err := createTestCertificate(x509.SHA256WithRSA)
|
cert, err := createTestCertificate(x509.SHA256WithRSA, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Cannot create test certificates: %s", err)
|
fmt.Printf("Cannot create test certificates: %s", err)
|
||||||
}
|
}
|
||||||
@ -141,7 +141,7 @@ func ExampleSignedData() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshalSignedAttribute(t *testing.T) {
|
func TestUnmarshalSignedAttribute(t *testing.T) {
|
||||||
cert, err := createTestCertificate(x509.SHA512WithRSA)
|
cert, err := createTestCertificate(x509.SHA512WithRSA, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -180,7 +180,7 @@ func TestUnmarshalSignedAttribute(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSkipCertificates(t *testing.T) {
|
func TestSkipCertificates(t *testing.T) {
|
||||||
cert, err := createTestCertificate(x509.SHA512WithRSA)
|
cert, err := createTestCertificate(x509.SHA512WithRSA, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -234,7 +234,7 @@ func TestSkipCertificates(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDegenerateCertificate(t *testing.T) {
|
func TestDegenerateCertificate(t *testing.T) {
|
||||||
cert, err := createTestCertificate(x509.SHA1WithRSA)
|
cert, err := createTestCertificate(x509.SHA1WithRSA, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -298,7 +298,7 @@ func TestSignWithoutAttr(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, sigalg := range sigalgs {
|
for _, sigalg := range sigalgs {
|
||||||
cert, err := createTestCertificate(sigalg.sigAlg)
|
cert, err := createTestCertificate(sigalg.sigAlg, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user