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

     1  package pkcs7
     2  
     3  import (
     4  	"crypto/subtle"
     5  	"crypto/x509"
     6  	"crypto/x509/pkix"
     7  	"encoding/asn1"
     8  	"errors"
     9  	"fmt"
    10  	"time"
    11  
    12  	"github.com/emmansun/gmsm/smx509"
    13  )
    14  
    15  // Verify is a wrapper around VerifyWithChain() that initializes an empty
    16  // trust store, effectively disabling certificate verification when validating
    17  // a signature.
    18  func (p7 *PKCS7) Verify() (err error) {
    19  	return p7.VerifyWithChain(nil)
    20  }
    21  
    22  // VerifyWithChain checks the signatures of a PKCS7 object.
    23  //
    24  // If truststore is not nil, it also verifies the chain of trust of
    25  // the end-entity signer cert to one of the roots in the
    26  // truststore. When the PKCS7 object includes the signing time
    27  // authenticated attr verifies the chain at that time and UTC now
    28  // otherwise.
    29  func (p7 *PKCS7) VerifyWithChain(truststore *smx509.CertPool) (err error) {
    30  	if len(p7.Signers) == 0 {
    31  		return errors.New("pkcs7: Message has no signers")
    32  	}
    33  	for _, signer := range p7.Signers {
    34  		if err := verifySignature(p7, signer, truststore, nil); err != nil {
    35  			return err
    36  		}
    37  	}
    38  	return nil
    39  }
    40  
    41  // VerifyWithChainAtTime checks the signatures of a PKCS7 object.
    42  //
    43  // If truststore is not nil, it also verifies the chain of trust of
    44  // the end-entity signer cert to a root in the truststore at
    45  // currentTime. It does not use the signing time authenticated
    46  // attribute.
    47  func (p7 *PKCS7) VerifyWithChainAtTime(truststore *smx509.CertPool, currentTime *time.Time) (err error) {
    48  	if len(p7.Signers) == 0 {
    49  		return errors.New("pkcs7: Message has no signers")
    50  	}
    51  	for _, signer := range p7.Signers {
    52  		if err := verifySignature(p7, signer, truststore, currentTime); err != nil {
    53  			return err
    54  		}
    55  	}
    56  	return nil
    57  }
    58  
    59  func verifySignature(p7 *PKCS7, signer signerInfo, truststore *smx509.CertPool, currentTime *time.Time) (err error) {
    60  	signedData := p7.Content
    61  	ee := getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber)
    62  	if ee == nil {
    63  		return errors.New("pkcs7: No certificate for signer")
    64  	}
    65  	signingTime := time.Now().UTC()
    66  	if len(signer.AuthenticatedAttributes) > 0 {
    67  		// TODO(fullsailor): First check the content type match
    68  		var digest []byte
    69  		err := unmarshalAttribute(signer.AuthenticatedAttributes, OIDAttributeMessageDigest, &digest)
    70  		if err != nil {
    71  			return err
    72  		}
    73  		hasher, err := getHashForOID(signer.DigestAlgorithm.Algorithm)
    74  		if err != nil {
    75  			return err
    76  		}
    77  		h := newHash(hasher, signer.DigestAlgorithm.Algorithm)
    78  		h.Write(p7.Content)
    79  		computed := h.Sum(nil)
    80  		if subtle.ConstantTimeCompare(digest, computed) != 1 {
    81  			return &MessageDigestMismatchError{
    82  				ExpectedDigest: digest,
    83  				ActualDigest:   computed,
    84  			}
    85  		}
    86  		signedData, err = marshalAttributes(signer.AuthenticatedAttributes)
    87  		if err != nil {
    88  			return err
    89  		}
    90  		err = unmarshalAttribute(signer.AuthenticatedAttributes, OIDAttributeSigningTime, &signingTime)
    91  		if err == nil {
    92  			// signing time found, performing validity check
    93  			if signingTime.After(ee.NotAfter) || signingTime.Before(ee.NotBefore) {
    94  				return fmt.Errorf("pkcs7: signing time %q is outside of certificate validity %q to %q",
    95  					signingTime.Format(time.RFC3339),
    96  					ee.NotBefore.Format(time.RFC3339),
    97  					ee.NotAfter.Format(time.RFC3339))
    98  			}
    99  		}
   100  	}
   101  	if truststore != nil {
   102  		if currentTime != nil {
   103  			signingTime = *currentTime
   104  		}
   105  		_, err = verifyCertChain(ee, p7.Certificates, truststore, signingTime)
   106  		if err != nil {
   107  			return err
   108  		}
   109  	}
   110  	sigalg, err := getSignatureAlgorithm(signer.DigestEncryptionAlgorithm, signer.DigestAlgorithm)
   111  	if err != nil {
   112  		return err
   113  	}
   114  	return ee.CheckSignature(sigalg, signedData, signer.EncryptedDigest)
   115  }
   116  
   117  // GetOnlySigner returns an x509.Certificate for the first signer of the signed
   118  // data payload. If there are more or less than one signer, nil is returned
   119  func (p7 *PKCS7) GetOnlySigner() *smx509.Certificate {
   120  	if len(p7.Signers) != 1 {
   121  		return nil
   122  	}
   123  	signer := p7.Signers[0]
   124  	return getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber)
   125  }
   126  
   127  // UnmarshalSignedAttribute decodes a single attribute from the signer info
   128  func (p7 *PKCS7) UnmarshalSignedAttribute(attributeType asn1.ObjectIdentifier, out any) error {
   129  	sd, ok := p7.raw.(signedData)
   130  	if !ok {
   131  		return errors.New("pkcs7: payload is not signedData content")
   132  	}
   133  	if len(sd.SignerInfos) < 1 {
   134  		return errors.New("pkcs7: payload has no signers")
   135  	}
   136  	attributes := sd.SignerInfos[0].AuthenticatedAttributes
   137  	return unmarshalAttribute(attributes, attributeType, out)
   138  }
   139  
   140  func parseSignedData(data []byte) (*PKCS7, error) {
   141  	var sd signedData
   142  	asn1.Unmarshal(data, &sd)
   143  	certs, err := sd.Certificates.Parse()
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  	// fmt.Printf("--> Signed Data Version %d\n", sd.Version)
   148  
   149  	var compound asn1.RawValue
   150  	var content unsignedData
   151  
   152  	// The Content.Bytes maybe empty on PKI responses.
   153  	if len(sd.ContentInfo.Content.Bytes) > 0 {
   154  		if _, err := asn1.Unmarshal(sd.ContentInfo.Content.Bytes, &compound); err != nil {
   155  			return nil, err
   156  		}
   157  	}
   158  	// Compound octet string
   159  	if compound.IsCompound && compound.Tag == 4 {
   160  		if _, err = asn1.Unmarshal(compound.Bytes, &content); err != nil {
   161  			return nil, err
   162  		}
   163  	} else {
   164  		// assuming this is tag 04
   165  		content = compound.Bytes
   166  	}
   167  	return &PKCS7{
   168  		Content:      content,
   169  		Certificates: certs,
   170  		CRLs:         sd.CRLs,
   171  		Signers:      sd.SignerInfos,
   172  		raw:          sd}, nil
   173  }
   174  
   175  // verifyCertChain takes an end-entity certs, a list of potential intermediates and a
   176  // truststore, and built all potential chains between the EE and a trusted root.
   177  //
   178  // When verifying chains that may have expired, currentTime can be set to a past date
   179  // to allow the verification to pass. If unset, currentTime is set to the current UTC time.
   180  func verifyCertChain(ee *smx509.Certificate, certs []*smx509.Certificate, truststore *smx509.CertPool, currentTime time.Time) (chains [][]*smx509.Certificate, err error) {
   181  	intermediates := smx509.NewCertPool()
   182  	for _, intermediate := range certs {
   183  		intermediates.AddCert(intermediate)
   184  	}
   185  	verifyOptions := smx509.VerifyOptions{
   186  		Roots:         truststore,
   187  		Intermediates: intermediates,
   188  		KeyUsages:     []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
   189  		CurrentTime:   currentTime,
   190  	}
   191  	chains, err = ee.Verify(verifyOptions)
   192  	if err != nil {
   193  		return chains, fmt.Errorf("pkcs7: failed to verify certificate chain: %v", err)
   194  	}
   195  	return
   196  }
   197  
   198  // MessageDigestMismatchError is returned when the signer data digest does not
   199  // match the computed digest for the contained content
   200  type MessageDigestMismatchError struct {
   201  	ExpectedDigest []byte
   202  	ActualDigest   []byte
   203  }
   204  
   205  func (err *MessageDigestMismatchError) Error() string {
   206  	return fmt.Sprintf("pkcs7: Message digest mismatch\n\tExpected: %X\n\tActual  : %X", err.ExpectedDigest, err.ActualDigest)
   207  }
   208  
   209  func getSignatureAlgorithm(digestEncryption, digest pkix.AlgorithmIdentifier) (x509.SignatureAlgorithm, error) {
   210  	switch {
   211  	case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA1):
   212  		return x509.ECDSAWithSHA1, nil
   213  	case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA256):
   214  		return x509.ECDSAWithSHA256, nil
   215  	case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA384):
   216  		return x509.ECDSAWithSHA384, nil
   217  	case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA512):
   218  		return x509.ECDSAWithSHA512, nil
   219  	case digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSA),
   220  		digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA1),
   221  		digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA256),
   222  		digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA384),
   223  		digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA512):
   224  		switch {
   225  		case digest.Algorithm.Equal(OIDDigestAlgorithmSHA1):
   226  			return x509.SHA1WithRSA, nil
   227  		case digest.Algorithm.Equal(OIDDigestAlgorithmSHA256):
   228  			return x509.SHA256WithRSA, nil
   229  		case digest.Algorithm.Equal(OIDDigestAlgorithmSHA384):
   230  			return x509.SHA384WithRSA, nil
   231  		case digest.Algorithm.Equal(OIDDigestAlgorithmSHA512):
   232  			return x509.SHA512WithRSA, nil
   233  		default:
   234  			return -1, fmt.Errorf("pkcs7: unsupported digest %q for encryption algorithm %q",
   235  				digest.Algorithm.String(), digestEncryption.Algorithm.String())
   236  		}
   237  	case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmDSA),
   238  		digestEncryption.Algorithm.Equal(OIDDigestAlgorithmDSASHA1):
   239  		switch {
   240  		case digest.Algorithm.Equal(OIDDigestAlgorithmSHA1):
   241  			return x509.DSAWithSHA1, nil
   242  		case digest.Algorithm.Equal(OIDDigestAlgorithmSHA256):
   243  			return x509.DSAWithSHA256, nil
   244  		default:
   245  			return -1, fmt.Errorf("pkcs7: unsupported digest %q for encryption algorithm %q",
   246  				digest.Algorithm.String(), digestEncryption.Algorithm.String())
   247  		}
   248  	case digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmECDSAP256),
   249  		digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmECDSAP384),
   250  		digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmECDSAP521):
   251  		switch {
   252  		case digest.Algorithm.Equal(OIDDigestAlgorithmSHA1):
   253  			return x509.ECDSAWithSHA1, nil
   254  		case digest.Algorithm.Equal(OIDDigestAlgorithmSHA256):
   255  			return x509.ECDSAWithSHA256, nil
   256  		case digest.Algorithm.Equal(OIDDigestAlgorithmSHA384):
   257  			return x509.ECDSAWithSHA384, nil
   258  		case digest.Algorithm.Equal(OIDDigestAlgorithmSHA512):
   259  			return x509.ECDSAWithSHA512, nil
   260  		default:
   261  			return -1, fmt.Errorf("pkcs7: unsupported digest %q for encryption algorithm %q",
   262  				digest.Algorithm.String(), digestEncryption.Algorithm.String())
   263  		}
   264  	case digestEncryption.Algorithm.Equal(OIDDigestEncryptionAlgorithmSM2):
   265  		return smx509.SM2WithSM3, nil
   266  	default:
   267  		return -1, fmt.Errorf("pkcs7: unsupported algorithm %q",
   268  			digestEncryption.Algorithm.String())
   269  	}
   270  }
   271  
   272  func getCertFromCertsByIssuerAndSerial(certs []*smx509.Certificate, ias issuerAndSerial) *smx509.Certificate {
   273  	for _, cert := range certs {
   274  		if isCertMatchForIssuerAndSerial(cert, ias) {
   275  			return cert
   276  		}
   277  	}
   278  	return nil
   279  }
   280  
   281  func unmarshalAttribute(attrs []attribute, attributeType asn1.ObjectIdentifier, out any) error {
   282  	for _, attr := range attrs {
   283  		if attr.Type.Equal(attributeType) {
   284  			_, err := asn1.Unmarshal(attr.Value.Bytes, out)
   285  			return err
   286  		}
   287  	}
   288  	return errors.New("pkcs7: attribute type not in attributes")
   289  }