summaryrefslogtreecommitdiff
path: root/vendor/go.mozilla.org/pkcs7/verify.go
diff options
context:
space:
mode:
authorTomSweeneyRedHat <tsweeney@redhat.com>2020-08-03 14:34:20 -0400
committerTomSweeneyRedHat <tsweeney@redhat.com>2020-08-03 14:34:24 -0400
commit47c91097f7b93045e9c099b52870c35577f80734 (patch)
treefd63e9de155376c5f6f8ac021045a258cf491994 /vendor/go.mozilla.org/pkcs7/verify.go
parent1709335cf04e947117d4ae4dca72f24f4095511b (diff)
downloadpodman-47c91097f7b93045e9c099b52870c35577f80734.tar.gz
podman-47c91097f7b93045e9c099b52870c35577f80734.tar.bz2
podman-47c91097f7b93045e9c099b52870c35577f80734.zip
Bump to Buildah 1.16.0-dev in upstream
Bump Buildah to v1.16.0-dev in the upstream branch of Podman. This will allow us to get a number of new issues into the upstream branch for use. The version of Buildah will need to be bumped to v1.16.0 and then vendored into Podman before we release Podman v2.0 Signed-off-by: TomSweeneyRedHat <tsweeney@redhat.com>
Diffstat (limited to 'vendor/go.mozilla.org/pkcs7/verify.go')
-rw-r--r--vendor/go.mozilla.org/pkcs7/verify.go264
1 files changed, 264 insertions, 0 deletions
diff --git a/vendor/go.mozilla.org/pkcs7/verify.go b/vendor/go.mozilla.org/pkcs7/verify.go
new file mode 100644
index 000000000..c8ead2362
--- /dev/null
+++ b/vendor/go.mozilla.org/pkcs7/verify.go
@@ -0,0 +1,264 @@
+package pkcs7
+
+import (
+ "crypto/subtle"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/asn1"
+ "errors"
+ "fmt"
+ "time"
+)
+
+// Verify is a wrapper around VerifyWithChain() that initializes an empty
+// trust store, effectively disabling certificate verification when validating
+// a signature.
+func (p7 *PKCS7) Verify() (err error) {
+ return p7.VerifyWithChain(nil)
+}
+
+// VerifyWithChain checks the signatures of a PKCS7 object.
+// If truststore is not nil, it also verifies the chain of trust of the end-entity
+// signer cert to one of the root in the truststore.
+func (p7 *PKCS7) VerifyWithChain(truststore *x509.CertPool) (err error) {
+ if len(p7.Signers) == 0 {
+ return errors.New("pkcs7: Message has no signers")
+ }
+ for _, signer := range p7.Signers {
+ if err := verifySignature(p7, signer, truststore); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func verifySignature(p7 *PKCS7, signer signerInfo, truststore *x509.CertPool) (err error) {
+ signedData := p7.Content
+ ee := getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber)
+ if ee == nil {
+ return errors.New("pkcs7: No certificate for signer")
+ }
+ signingTime := time.Now().UTC()
+ if len(signer.AuthenticatedAttributes) > 0 {
+ // TODO(fullsailor): First check the content type match
+ var digest []byte
+ err := unmarshalAttribute(signer.AuthenticatedAttributes, OIDAttributeMessageDigest, &digest)
+ if err != nil {
+ return err
+ }
+ hash, err := getHashForOID(signer.DigestAlgorithm.Algorithm)
+ if err != nil {
+ return err
+ }
+ h := hash.New()
+ h.Write(p7.Content)
+ computed := h.Sum(nil)
+ if subtle.ConstantTimeCompare(digest, computed) != 1 {
+ return &MessageDigestMismatchError{
+ ExpectedDigest: digest,
+ ActualDigest: computed,
+ }
+ }
+ signedData, err = marshalAttributes(signer.AuthenticatedAttributes)
+ if err != nil {
+ return err
+ }
+ err = unmarshalAttribute(signer.AuthenticatedAttributes, OIDAttributeSigningTime, &signingTime)
+ 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.NotBefore.Format(time.RFC3339))
+ }
+ }
+ }
+ if truststore != nil {
+ _, err = verifyCertChain(ee, p7.Certificates, truststore, signingTime)
+ if err != nil {
+ return err
+ }
+ }
+ sigalg, err := getSignatureAlgorithm(signer.DigestEncryptionAlgorithm, signer.DigestAlgorithm)
+ if err != nil {
+ return err
+ }
+ return ee.CheckSignature(sigalg, signedData, signer.EncryptedDigest)
+}
+
+// GetOnlySigner returns an x509.Certificate for the first signer of the signed
+// data payload. If there are more or less than one signer, nil is returned
+func (p7 *PKCS7) GetOnlySigner() *x509.Certificate {
+ if len(p7.Signers) != 1 {
+ return nil
+ }
+ signer := p7.Signers[0]
+ return getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber)
+}
+
+// UnmarshalSignedAttribute decodes a single attribute from the signer info
+func (p7 *PKCS7) UnmarshalSignedAttribute(attributeType asn1.ObjectIdentifier, out interface{}) error {
+ sd, ok := p7.raw.(signedData)
+ if !ok {
+ return errors.New("pkcs7: payload is not signedData content")
+ }
+ if len(sd.SignerInfos) < 1 {
+ return errors.New("pkcs7: payload has no signers")
+ }
+ attributes := sd.SignerInfos[0].AuthenticatedAttributes
+ return unmarshalAttribute(attributes, attributeType, out)
+}
+
+func parseSignedData(data []byte) (*PKCS7, error) {
+ var sd signedData
+ asn1.Unmarshal(data, &sd)
+ certs, err := sd.Certificates.Parse()
+ if err != nil {
+ return nil, err
+ }
+ // fmt.Printf("--> Signed Data Version %d\n", sd.Version)
+
+ var compound asn1.RawValue
+ var content unsignedData
+
+ // The Content.Bytes maybe empty on PKI responses.
+ if len(sd.ContentInfo.Content.Bytes) > 0 {
+ if _, err := asn1.Unmarshal(sd.ContentInfo.Content.Bytes, &compound); err != nil {
+ return nil, err
+ }
+ }
+ // Compound octet string
+ if compound.IsCompound {
+ if compound.Tag == 4 {
+ if _, err = asn1.Unmarshal(compound.Bytes, &content); err != nil {
+ return nil, err
+ }
+ } else {
+ content = compound.Bytes
+ }
+ } else {
+ // assuming this is tag 04
+ content = compound.Bytes
+ }
+ return &PKCS7{
+ Content: content,
+ Certificates: certs,
+ CRLs: sd.CRLs,
+ Signers: sd.SignerInfos,
+ raw: sd}, nil
+}
+
+// verifyCertChain takes an end-entity certs, a list of potential intermediates and a
+// truststore, and built all potential chains between the EE and a trusted root.
+//
+// When verifying chains that may have expired, currentTime can be set to a past date
+// to allow the verification to pass. If unset, currentTime is set to the current UTC time.
+func verifyCertChain(ee *x509.Certificate, certs []*x509.Certificate, truststore *x509.CertPool, currentTime time.Time) (chains [][]*x509.Certificate, err error) {
+ intermediates := x509.NewCertPool()
+ for _, intermediate := range certs {
+ intermediates.AddCert(intermediate)
+ }
+ verifyOptions := x509.VerifyOptions{
+ Roots: truststore,
+ Intermediates: intermediates,
+ KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
+ CurrentTime: currentTime,
+ }
+ chains, err = ee.Verify(verifyOptions)
+ if err != nil {
+ return chains, fmt.Errorf("pkcs7: failed to verify certificate chain: %v", err)
+ }
+ return
+}
+
+// MessageDigestMismatchError is returned when the signer data digest does not
+// match the computed digest for the contained content
+type MessageDigestMismatchError struct {
+ ExpectedDigest []byte
+ ActualDigest []byte
+}
+
+func (err *MessageDigestMismatchError) Error() string {
+ return fmt.Sprintf("pkcs7: Message digest mismatch\n\tExpected: %X\n\tActual : %X", err.ExpectedDigest, err.ActualDigest)
+}
+
+func getSignatureAlgorithm(digestEncryption, digest pkix.AlgorithmIdentifier) (x509.SignatureAlgorithm, error) {
+ switch {
+ case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA1):
+ return x509.ECDSAWithSHA1, nil
+ case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA256):
+ return x509.ECDSAWithSHA256, nil
+ case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA384):
+ return x509.ECDSAWithSHA384, nil
+ case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA512):
+ return x509.ECDSAWithSHA512, nil
+ case digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSA),
+ digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA1),
+ digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA256),
+ digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA384),
+ digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA512):
+ switch {
+ case digest.Algorithm.Equal(OIDDigestAlgorithmSHA1):
+ return x509.SHA1WithRSA, nil
+ case digest.Algorithm.Equal(OIDDigestAlgorithmSHA256):
+ return x509.SHA256WithRSA, nil
+ case digest.Algorithm.Equal(OIDDigestAlgorithmSHA384):
+ return x509.SHA384WithRSA, nil
+ case digest.Algorithm.Equal(OIDDigestAlgorithmSHA512):
+ return x509.SHA512WithRSA, nil
+ default:
+ return -1, fmt.Errorf("pkcs7: unsupported digest %q for encryption algorithm %q",
+ digest.Algorithm.String(), digestEncryption.Algorithm.String())
+ }
+ case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmDSA),
+ digestEncryption.Algorithm.Equal(OIDDigestAlgorithmDSASHA1):
+ switch {
+ case digest.Algorithm.Equal(OIDDigestAlgorithmSHA1):
+ return x509.DSAWithSHA1, nil
+ case digest.Algorithm.Equal(OIDDigestAlgorithmSHA256):
+ return x509.DSAWithSHA256, nil
+ default:
+ return -1, fmt.Errorf("pkcs7: unsupported digest %q for encryption algorithm %q",
+ digest.Algorithm.String(), digestEncryption.Algorithm.String())
+ }
+ case digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmECDSAP256),
+ digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmECDSAP384),
+ digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmECDSAP521):
+ switch {
+ case digest.Algorithm.Equal(OIDDigestAlgorithmSHA1):
+ return x509.ECDSAWithSHA1, nil
+ case digest.Algorithm.Equal(OIDDigestAlgorithmSHA256):
+ return x509.ECDSAWithSHA256, nil
+ case digest.Algorithm.Equal(OIDDigestAlgorithmSHA384):
+ return x509.ECDSAWithSHA384, nil
+ case digest.Algorithm.Equal(OIDDigestAlgorithmSHA512):
+ return x509.ECDSAWithSHA512, nil
+ default:
+ return -1, fmt.Errorf("pkcs7: unsupported digest %q for encryption algorithm %q",
+ digest.Algorithm.String(), digestEncryption.Algorithm.String())
+ }
+ default:
+ return -1, fmt.Errorf("pkcs7: unsupported algorithm %q",
+ digestEncryption.Algorithm.String())
+ }
+}
+
+func getCertFromCertsByIssuerAndSerial(certs []*x509.Certificate, ias issuerAndSerial) *x509.Certificate {
+ for _, cert := range certs {
+ if isCertMatchForIssuerAndSerial(cert, ias) {
+ return cert
+ }
+ }
+ return nil
+}
+
+func unmarshalAttribute(attrs []attribute, attributeType asn1.ObjectIdentifier, out interface{}) error {
+ for _, attr := range attrs {
+ if attr.Type.Equal(attributeType) {
+ _, err := asn1.Unmarshal(attr.Value.Bytes, out)
+ return err
+ }
+ }
+ return errors.New("pkcs7: attribute type not in attributes")
+}