ietf-cms
is now part of the https://github.com/github/smimesign repository.
Please update your dependencies from github.com/github/ietf-cms
to github.com/github/smimesign/ietf-cms
CMS (PKCS#7) library for Go
License: MIT License
ietf-cms
is now part of the https://github.com/github/smimesign repository.
Please update your dependencies from github.com/github/ietf-cms
to github.com/github/smimesign/ietf-cms
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,
}
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
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)
}
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?
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
would you please retag version with prefix 'v'
described in
https://go.googlesource.com/proposal/+/master/design/24301-versioned-go.md#background
so that we can use cms with go mod
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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.