Git Product home page Git Product logo

ietf-cms's Introduction

ietf-cms's People

Contributors

addie9000 avatar antonioma avatar bluestealth avatar btoews avatar davrux avatar ddz avatar fullsailor avatar groob avatar hryx avatar josephlr avatar jvehent avatar lgarron avatar mastahyeti avatar matthias50 avatar pranavraja avatar vcsjones avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

ietf-cms's Issues

Signature verification fails when timestamp is present and x509.VerifyOptions has key usage

Sample code to verify CMS with Code Signing

	opts := x509.VerifyOptions{
		Roots: roots,
		KeyUsages: []x509.ExtKeyUsage{
			x509.ExtKeyUsageCodeSigning,
		},
	}

	chains, err := sd.VerifyDetached(msg, opts)

The opts is propagated way down to verify Timestamp signature, but for timestamp the options should be explicit, and contain only ExtKeyUsageTimeStamping

	opts := x509.VerifyOptions{
		KeyUsages:     []x509.ExtKeyUsage{x509.ExtKeyUsageTimeStamping},
		Roots:         roots,
	}

Timestamp verification fail

in the the function func (sd *SignedData) verify
there is a loop

for _, si := range sd.psd.SignerInfos {

		algo := si.X509SignatureAlgorithm()
		if algo == x509.UnknownSignatureAlgorithm {
			return nil, protocol.ErrUnsupported
		}

The line 123 fails, for RSAWithSHA1 signature: OID 1.2.840.113549.1.1.11

The following map is wrong when your code deals with external Timestamp servers.

// SignatureAlgorithms maps digest and signature OIDs to
// x509.SignatureAlgorithm values.
var SignatureAlgorithms = map[string]map[string]x509.SignatureAlgorithm{
	SignatureAlgorithmRSA.String(): map[string]x509.SignatureAlgorithm{
		DigestAlgorithmSHA1.String():   x509.SHA1WithRSA,
		DigestAlgorithmMD5.String():    x509.MD5WithRSA,
		DigestAlgorithmSHA256.String(): x509.SHA256WithRSA,
		DigestAlgorithmSHA384.String(): x509.SHA384WithRSA,
		DigestAlgorithmSHA512.String(): x509.SHA512WithRSA,
	},
	SignatureAlgorithmECDSA.String(): map[string]x509.SignatureAlgorithm{
		DigestAlgorithmSHA1.String():   x509.ECDSAWithSHA1,
		DigestAlgorithmSHA256.String(): x509.ECDSAWithSHA256,
		DigestAlgorithmSHA384.String(): x509.ECDSAWithSHA384,
		DigestAlgorithmSHA512.String(): x509.ECDSAWithSHA512,
	},
}

// X509SignatureAlgorithm gets the x509.SignatureAlgorithm that should be used
// for verifying this SignerInfo's signature.
func (si SignerInfo) X509SignatureAlgorithm() x509.SignatureAlgorithm {
	var (
		sigOID    = si.SignatureAlgorithm.Algorithm.String()
		digestOID = si.DigestAlgorithm.Algorithm.String()
	)

	return oid.SignatureAlgorithms[sigOID][digestOID]
}

You should support the following mappings from SignerInfos:

oid: "1.2.840.113549.1.1.5" => RSAWithSHA1
oid: "1.2.840.113549.1.1.11" => RSAWithSHA256
oid: "1.2.840.113549.1.1.12" => RSAWithSHA384
oid: "1.2.840.113549.1.1.13" => RSAWithSHA512
oid: "1.2.840.10045.4.1" => ECDSAWithSHA1
oid: "2.16.840.1.101.4.3.2" => ECDSAWithSHA256
oid: "2.16.840.1.101.4.3.3" => ECDSAWithSHA384
oid: "2.16.840.1.101.4.3.4" => ECDSAWithSHA512

VerifySignature is hardcoded for RSA

This method panics for ECDSA signatures

// VerifySignature verifies that the given certificate signed the TSTInfo
func (sd *SignedData) VerifySignature(cert *x509.Certificate) error {
       ...

	// Unpack the public key
	pub := cert.PublicKey.(*rsa.PublicKey)

	// Verify the signature
	err = rsa.VerifyPKCS1v15(pub, hashAlgo.Hash, digest, signer.Signature)
	if err != nil {
		return errors.Trace(errVerificationError)
	}

Trouble importing github.com/github/cms

I had to import this repository as github.com/mastahyeti/cms instead of github.com/github/cms because of how the module is defined in go.mod.

I think this wasn't intended, but the result of a username change or change of owner. Not a blocker, but it can be improved. Changing it to github.com/github/cms looks like a solution, but is this repository part of GitHub?

issues validating signed data in go1.15

This golang commit golang/go@f0cea84 causes detached signatures generated by previous versions of go using this library to fail validation due to the change in ordering of signed attributes.

Not sure of exactly the best way of fixing this, but one way would update the upstream encoding/asn1 to allow fallback to old encoding behavior, and try both encodings, as shown below.

diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go
index d809dde278..98df4d4ee4 100644
--- a/src/encoding/asn1/asn1.go
+++ b/src/encoding/asn1/asn1.go
@@ -805,7 +805,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
                universalTag = TagGeneralizedTime
        }
 
-       if params.set {
+       if params.set || params.setOrdered {
                universalTag = TagSet
        }
 
diff --git a/src/encoding/asn1/common.go b/src/encoding/asn1/common.go
index e2aa8bd9c5..b05fdd8b92 100644
--- a/src/encoding/asn1/common.go
+++ b/src/encoding/asn1/common.go
@@ -82,6 +82,7 @@ type fieldParameters struct {
        stringType   int    // the string tag to use when marshaling.
        timeType     int    // the time tag to use when marshaling.
        set          bool   // true iff this should be encoded as a SET
+       setOrdered   bool   // true iff this should be encoded as a sequence with a SET tag
        omitEmpty    bool   // true iff this should be omitted if empty when marshaling.
 
        // Invariants:
@@ -127,6 +128,8 @@ func parseFieldParameters(str string) (ret fieldParameters) {
                        }
                case part == "set":
                        ret.set = true
+               case part == "set_ordered":
+                       ret.setOrdered = true
                case part == "application":
                        ret.application = true
                        if ret.tag == nil {
diff --git a/src/encoding/asn1/marshal.go b/src/encoding/asn1/marshal.go
index 0d34d5aa1e..a8c05f3fb2 100644
--- a/src/encoding/asn1/marshal.go
+++ b/src/encoding/asn1/marshal.go
@@ -658,7 +658,7 @@ func makeField(v reflect.Value, params fieldParameters) (e encoder, err error) {
                }
        }
 
-       if params.set {
+       if params.set || params.setOrdered {
                if tag != TagSequence {
                        return nil, StructuralError{"non sequence tagged as set"}
                }
@@ -670,7 +670,7 @@ func makeField(v reflect.Value, params fieldParameters) (e encoder, err error) {
        // with the SET type name suffix. In this case getUniversalType returns
        // TagSet, but makeBody doesn't know about that so will treat the slice
        // as a sequence. To work around this we set params.set.
-       if tag == TagSet && !params.set {
+       if tag == TagSet && !params.set && !params.setOrdered {
                params.set = true
        }

diff --git a/go.mod b/go.mod
index c1b43ec..797e14c 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
 module github.com/github/ietf-cms
 
-go 1.12
+go 1.15
 
 require (
        github.com/github/fakeca v0.1.0

diff --git a/protocol/protocol.go b/protocol/protocol.go
index 6a83d70..1b6b0e0 100644
--- a/protocol/protocol.go
+++ b/protocol/protocol.go
@@ -256,7 +256,33 @@ func (attrs Attributes) MarshaledForSigning() ([]byte, error) {
        seq, err := asn1.Marshal(struct {
                Attributes `asn1:"set"`
        }{attrs})
+       if err != nil {
+               return nil, err
+       }
+
+       // unwrap the outer SEQUENCE
+       var raw asn1.RawValue
+       if _, err = asn1.Unmarshal(seq, &raw); err != nil {
+               return nil, err
+       }
+
+       return raw.Bytes, nil
+}
 
+// MarshaledOrderedSetForSigning DER encodes the Attributes as needed for signing
+// SignedAttributes. Encodes as an sequence with a SET tag to comply with previous
+// golang asn1 behavior.
+//   RFC5652 explains this encoding:
+//   A separate encoding of the signedAttrs field is performed for message
+//   digest calculation. The IMPLICIT [0] tag in the signedAttrs is not used for
+//   the DER encoding, rather an EXPLICIT SET OF tag is used.  That is, the DER
+//   encoding of the EXPLICIT SET OF tag, rather than of the IMPLICIT [0] tag,
+//   MUST be included in the message digest calculation along with the length
+//   and content octets of the SignedAttributes value.
+func (attrs Attributes) MarshaledOrderedSetForSigning() ([]byte, error) {
+       seq, err := asn1.Marshal(struct {
+               Attributes `asn1:"set_ordered"`
+       }{attrs})
        if err != nil {
                return nil, err
        }
diff --git a/verify.go b/verify.go
index 3e61500..526c139 100644
--- a/verify.go
+++ b/verify.go
@@ -67,7 +67,7 @@ func (sd *SignedData) verify(econtent []byte, opts x509.VerifyOptions) ([][][]*x
        chains := make([][][]*x509.Certificate, 0, len(sd.psd.SignerInfos))
 
        for _, si := range sd.psd.SignerInfos {
-               var signedMessage []byte
+               var signedMessage, signedMessageOrdered []byte
 
                // SignedAttrs is optional if EncapContentInfo eContentType isn't id-data.
                if si.SignedAttrs == nil {
@@ -118,6 +118,10 @@ func (sd *SignedData) verify(econtent []byte, opts x509.VerifyOptions) ([][][]*x
                        if signedMessage, err = si.SignedAttrs.MarshaledForSigning(); err != nil {
                                return nil, err
                        }
+
+                       if signedMessageOrdered, err = si.SignedAttrs.MarshaledOrderedSetForSigning(); err != nil {
+                               return nil, err
+                       }
                }
 
                cert, err := si.FindCertificate(certs)
@@ -131,7 +135,13 @@ func (sd *SignedData) verify(econtent []byte, opts x509.VerifyOptions) ([][][]*x
                }
 
                if err := cert.CheckSignature(algo, signedMessage, si.Signature); err != nil {
-                       return nil, err
+                       if len(signedMessageOrdered) != 0 {
+                               if err := cert.CheckSignature(algo, signedMessageOrdered, si.Signature); err != nil {
+                                       return nil, err
+                               }
+                       } else {
+                               return nil, err
+                       }
                }
 
                // If the caller didn't specify the signature time, we'll use the verified

Conflict with go crypto/x509

Hi

I'm trying out your library and stumbled upon a problem:

../../../../mastahyeti/cms/verify.go:151:86: unknown field 'Detail' in struct literal of type x509.CertificateInvalidError

Seems if you'd just remove the "Detail", it would work.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.