...

Source file src/github.com/digitorus/pkcs7/verify.go

Documentation: github.com/digitorus/pkcs7

     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  
    13  // Verify is a wrapper around VerifyWithChain() that initializes an empty
    14  // trust store, effectively disabling certificate verification when validating
    15  // a signature.
    16  func (p7 *PKCS7) Verify() (err error) {
    17  	return p7.VerifyWithChain(nil)
    18  }
    19  
    20  // VerifyWithChain checks the signatures of a PKCS7 object.
    21  //
    22  // If truststore is not nil, it also verifies the chain of trust of
    23  // the end-entity signer cert to one of the roots in the
    24  // truststore. When the PKCS7 object includes the signing time
    25  // authenticated attr it verifies the chain at that time and UTC now
    26  // otherwise.
    27  func (p7 *PKCS7) VerifyWithChain(truststore *x509.CertPool) (err error) {
    28  	intermediates := x509.NewCertPool()
    29  	for _, cert := range(p7.Certificates) {
    30  		intermediates.AddCert(cert)
    31  	}
    32  
    33  	opts := x509.VerifyOptions{
    34  		Roots: truststore,
    35  		Intermediates: intermediates,
    36  	}
    37  
    38  	return p7.VerifyWithOpts(opts)
    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 *x509.CertPool, currentTime time.Time) (err error) {
    48  	intermediates := x509.NewCertPool()
    49  	for _, cert := range(p7.Certificates) {
    50  		intermediates.AddCert(cert)
    51  	}
    52  
    53  	opts := x509.VerifyOptions{
    54  		Roots: truststore,
    55  		Intermediates: intermediates,
    56  		CurrentTime: currentTime,
    57  	}
    58  
    59  	return p7.VerifyWithOpts(opts)
    60  }
    61  
    62  // VerifyWithOpts checks the signatures of a PKCS7 object.
    63  //
    64  // It accepts x509.VerifyOptions as a parameter.
    65  // This struct contains a root certificate pool, an intermedate certificate pool, 
    66  // an optional list of EKUs, and an optional time that certificates should be
    67  // checked as being valid during.
    68  
    69  // If VerifyOpts.Roots is not nil it verifies the chain of trust of
    70  // the end-entity signer cert to one of the roots in the
    71  // truststore. When the PKCS7 object includes the signing time
    72  // authenticated attr it verifies the chain at that time and UTC now
    73  // otherwise.
    74  func (p7 *PKCS7) VerifyWithOpts(opts x509.VerifyOptions) (err error) {
    75  	// if KeyUsage isn't set, default to ExtKeyUsageAny
    76  	if opts.KeyUsages == nil {
    77  		opts.KeyUsages = []x509.ExtKeyUsage{x509.ExtKeyUsageAny}
    78  	}
    79  
    80  	if len(p7.Signers) == 0 {
    81  		return errors.New("pkcs7: Message has no signers")
    82  	}
    83  
    84  	// if opts.CurrentTime is not set, call verifySignature,
    85  	// which will verify the leaf certificate with the current time
    86  	if opts.CurrentTime.IsZero() {
    87  		for _, signer := range p7.Signers {
    88  			if err := verifySignature(p7, signer, opts); err != nil {
    89  				return err
    90  			}
    91  		}
    92  		return nil
    93  	}
    94  	// if opts.CurrentTime is set, call verifySignatureAtTime,
    95  	// which will verify the leaf certificate with opts.CurrentTime
    96  	for _, signer := range p7.Signers {
    97  		if err := verifySignatureAtTime(p7, signer, opts); err != nil {
    98  			return err
    99  		}
   100  	}
   101  	return nil
   102  }
   103  
   104  func verifySignatureAtTime(p7 *PKCS7, signer signerInfo, opts x509.VerifyOptions) (err error) {
   105  	signedData := p7.Content
   106  	ee := getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber)
   107  	if ee == nil {
   108  		return errors.New("pkcs7: No certificate for signer")
   109  	}
   110  	if len(signer.AuthenticatedAttributes) > 0 {
   111  		// TODO(fullsailor): First check the content type match
   112  		var (
   113  			digest      []byte
   114  			signingTime time.Time
   115  		)
   116  		err := unmarshalAttribute(signer.AuthenticatedAttributes, OIDAttributeMessageDigest, &digest)
   117  		if err != nil {
   118  			return err
   119  		}
   120  		hash, err := getHashForOID(signer.DigestAlgorithm.Algorithm)
   121  		if err != nil {
   122  			return err
   123  		}
   124  		h := hash.New()
   125  		h.Write(p7.Content)
   126  		computed := h.Sum(nil)
   127  		if subtle.ConstantTimeCompare(digest, computed) != 1 {
   128  			return &MessageDigestMismatchError{
   129  				ExpectedDigest: digest,
   130  				ActualDigest:   computed,
   131  			}
   132  		}
   133  		signedData, err = marshalAttributes(signer.AuthenticatedAttributes)
   134  		if err != nil {
   135  			return err
   136  		}
   137  		err = unmarshalAttribute(signer.AuthenticatedAttributes, OIDAttributeSigningTime, &signingTime)
   138  		if err == nil {
   139  			// signing time found, performing validity check
   140  			if signingTime.After(ee.NotAfter) || signingTime.Before(ee.NotBefore) {
   141  				return fmt.Errorf("pkcs7: signing time %q is outside of certificate validity %q to %q",
   142  					signingTime.Format(time.RFC3339),
   143  					ee.NotBefore.Format(time.RFC3339),
   144  					ee.NotAfter.Format(time.RFC3339))
   145  			}
   146  		}
   147  	}
   148  	if opts.Roots != nil {
   149  		_, err = ee.Verify(opts)
   150  		if err != nil {
   151  			return fmt.Errorf("pkcs7: failed to verify certificate chain: %v", err)
   152  		}
   153  	}
   154  	sigalg, err := getSignatureAlgorithm(signer.DigestEncryptionAlgorithm, signer.DigestAlgorithm)
   155  	if err != nil {
   156  		return err
   157  	}
   158  	return ee.CheckSignature(sigalg, signedData, signer.EncryptedDigest)
   159  }
   160  
   161  func verifySignature(p7 *PKCS7, signer signerInfo, opts x509.VerifyOptions) (err error) {
   162  	signedData := p7.Content
   163  	ee := getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber)
   164  	if ee == nil {
   165  		return errors.New("pkcs7: No certificate for signer")
   166  	}
   167  	signingTime := time.Now().UTC()
   168  	if len(signer.AuthenticatedAttributes) > 0 {
   169  		// TODO(fullsailor): First check the content type match
   170  		var digest []byte
   171  		err := unmarshalAttribute(signer.AuthenticatedAttributes, OIDAttributeMessageDigest, &digest)
   172  		if err != nil {
   173  			return err
   174  		}
   175  		hash, err := getHashForOID(signer.DigestAlgorithm.Algorithm)
   176  		if err != nil {
   177  			return err
   178  		}
   179  		h := hash.New()
   180  		h.Write(p7.Content)
   181  		computed := h.Sum(nil)
   182  		if subtle.ConstantTimeCompare(digest, computed) != 1 {
   183  			return &MessageDigestMismatchError{
   184  				ExpectedDigest: digest,
   185  				ActualDigest:   computed,
   186  			}
   187  		}
   188  		signedData, err = marshalAttributes(signer.AuthenticatedAttributes)
   189  		if err != nil {
   190  			return err
   191  		}
   192  		err = unmarshalAttribute(signer.AuthenticatedAttributes, OIDAttributeSigningTime, &signingTime)
   193  		if err == nil {
   194  			// signing time found, performing validity check
   195  			if signingTime.After(ee.NotAfter) || signingTime.Before(ee.NotBefore) {
   196  				return fmt.Errorf("pkcs7: signing time %q is outside of certificate validity %q to %q",
   197  					signingTime.Format(time.RFC3339),
   198  					ee.NotBefore.Format(time.RFC3339),
   199  					ee.NotAfter.Format(time.RFC3339))
   200  			}
   201  		}
   202  	}
   203  	if opts.Roots != nil {
   204  		opts.CurrentTime = signingTime
   205  		_, err = ee.Verify(opts)
   206  		if err != nil {
   207  			return fmt.Errorf("pkcs7: failed to verify certificate chain: %v", err)
   208  		}
   209  	}
   210  	sigalg, err := getSignatureAlgorithm(signer.DigestEncryptionAlgorithm, signer.DigestAlgorithm)
   211  	if err != nil {
   212  		return err
   213  	}
   214  	return ee.CheckSignature(sigalg, signedData, signer.EncryptedDigest)
   215  }
   216  
   217  // GetOnlySigner returns an x509.Certificate for the first signer of the signed
   218  // data payload. If there are more or less than one signer, nil is returned
   219  func (p7 *PKCS7) GetOnlySigner() *x509.Certificate {
   220  	if len(p7.Signers) != 1 {
   221  		return nil
   222  	}
   223  	signer := p7.Signers[0]
   224  	return getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber)
   225  }
   226  
   227  // UnmarshalSignedAttribute decodes a single attribute from the signer info
   228  func (p7 *PKCS7) UnmarshalSignedAttribute(attributeType asn1.ObjectIdentifier, out interface{}) error {
   229  	sd, ok := p7.raw.(signedData)
   230  	if !ok {
   231  		return errors.New("pkcs7: payload is not signedData content")
   232  	}
   233  	if len(sd.SignerInfos) < 1 {
   234  		return errors.New("pkcs7: payload has no signers")
   235  	}
   236  	attributes := sd.SignerInfos[0].AuthenticatedAttributes
   237  	return unmarshalAttribute(attributes, attributeType, out)
   238  }
   239  
   240  func parseSignedData(data []byte) (*PKCS7, error) {
   241  	var sd signedData
   242  	asn1.Unmarshal(data, &sd)
   243  	certs, err := sd.Certificates.Parse()
   244  	if err != nil {
   245  		return nil, err
   246  	}
   247  	// fmt.Printf("--> Signed Data Version %d\n", sd.Version)
   248  
   249  	var compound asn1.RawValue
   250  	var content unsignedData
   251  
   252  	// The Content.Bytes maybe empty on PKI responses.
   253  	if len(sd.ContentInfo.Content.Bytes) > 0 {
   254  		if _, err := asn1.Unmarshal(sd.ContentInfo.Content.Bytes, &compound); err != nil {
   255  			return nil, err
   256  		}
   257  	}
   258  	// Compound octet string
   259  	if compound.IsCompound {
   260  		if compound.Tag == 4 {
   261  			if _, err = asn1.Unmarshal(compound.Bytes, &content); err != nil {
   262  				return nil, err
   263  			}
   264  		} else {
   265  			content = compound.Bytes
   266  		}
   267  	} else {
   268  		// assuming this is tag 04
   269  		content = compound.Bytes
   270  	}
   271  	return &PKCS7{
   272  		Content:      content,
   273  		Certificates: certs,
   274  		CRLs:         sd.CRLs,
   275  		Signers:      sd.SignerInfos,
   276  		raw:          sd}, nil
   277  }
   278  
   279  // MessageDigestMismatchError is returned when the signer data digest does not
   280  // match the computed digest for the contained content
   281  type MessageDigestMismatchError struct {
   282  	ExpectedDigest []byte
   283  	ActualDigest   []byte
   284  }
   285  
   286  func (err *MessageDigestMismatchError) Error() string {
   287  	return fmt.Sprintf("pkcs7: Message digest mismatch\n\tExpected: %X\n\tActual  : %X", err.ExpectedDigest, err.ActualDigest)
   288  }
   289  
   290  func getSignatureAlgorithm(digestEncryption, digest pkix.AlgorithmIdentifier) (x509.SignatureAlgorithm, error) {
   291  	switch {
   292  	case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA1):
   293  		return x509.ECDSAWithSHA1, nil
   294  	case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA256):
   295  		return x509.ECDSAWithSHA256, nil
   296  	case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA384):
   297  		return x509.ECDSAWithSHA384, nil
   298  	case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA512):
   299  		return x509.ECDSAWithSHA512, nil
   300  	case digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSA),
   301  		digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA1),
   302  		digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA256),
   303  		digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA384),
   304  		digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA512):
   305  		switch {
   306  		case digest.Algorithm.Equal(OIDDigestAlgorithmSHA1):
   307  			return x509.SHA1WithRSA, nil
   308  		case digest.Algorithm.Equal(OIDDigestAlgorithmSHA256):
   309  			return x509.SHA256WithRSA, nil
   310  		case digest.Algorithm.Equal(OIDDigestAlgorithmSHA384):
   311  			return x509.SHA384WithRSA, nil
   312  		case digest.Algorithm.Equal(OIDDigestAlgorithmSHA512):
   313  			return x509.SHA512WithRSA, nil
   314  		default:
   315  			return -1, fmt.Errorf("pkcs7: unsupported digest %q for encryption algorithm %q",
   316  				digest.Algorithm.String(), digestEncryption.Algorithm.String())
   317  		}
   318  	case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmDSA),
   319  		digestEncryption.Algorithm.Equal(OIDDigestAlgorithmDSASHA1):
   320  		switch {
   321  		case digest.Algorithm.Equal(OIDDigestAlgorithmSHA1):
   322  			return x509.DSAWithSHA1, nil
   323  		case digest.Algorithm.Equal(OIDDigestAlgorithmSHA256):
   324  			return x509.DSAWithSHA256, nil
   325  		default:
   326  			return -1, fmt.Errorf("pkcs7: unsupported digest %q for encryption algorithm %q",
   327  				digest.Algorithm.String(), digestEncryption.Algorithm.String())
   328  		}
   329  	case digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmECDSAP256),
   330  		digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmECDSAP384),
   331  		digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmECDSAP521):
   332  		switch {
   333  		case digest.Algorithm.Equal(OIDDigestAlgorithmSHA1):
   334  			return x509.ECDSAWithSHA1, nil
   335  		case digest.Algorithm.Equal(OIDDigestAlgorithmSHA256):
   336  			return x509.ECDSAWithSHA256, nil
   337  		case digest.Algorithm.Equal(OIDDigestAlgorithmSHA384):
   338  			return x509.ECDSAWithSHA384, nil
   339  		case digest.Algorithm.Equal(OIDDigestAlgorithmSHA512):
   340  			return x509.ECDSAWithSHA512, nil
   341  		default:
   342  			return -1, fmt.Errorf("pkcs7: unsupported digest %q for encryption algorithm %q",
   343  				digest.Algorithm.String(), digestEncryption.Algorithm.String())
   344  		}
   345  	case digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmEDDSA25519):
   346  		return x509.PureEd25519, nil
   347  	default:
   348  		return -1, fmt.Errorf("pkcs7: unsupported algorithm %q",
   349  			digestEncryption.Algorithm.String())
   350  	}
   351  }
   352  
   353  func getCertFromCertsByIssuerAndSerial(certs []*x509.Certificate, ias issuerAndSerial) *x509.Certificate {
   354  	for _, cert := range certs {
   355  		if isCertMatchForIssuerAndSerial(cert, ias) {
   356  			return cert
   357  		}
   358  	}
   359  	return nil
   360  }
   361  
   362  func unmarshalAttribute(attrs []attribute, attributeType asn1.ObjectIdentifier, out interface{}) error {
   363  	for _, attr := range attrs {
   364  		if attr.Type.Equal(attributeType) {
   365  			_, err := asn1.Unmarshal(attr.Value.Bytes, out)
   366  			return err
   367  		}
   368  	}
   369  	return errors.New("pkcs7: attribute type not in attributes")
   370  }
   371  

View as plain text