diff --git a/ber.go b/ber.go index bf3e804..1a0d8c0 100644 --- a/ber.go +++ b/ber.go @@ -240,7 +240,7 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) { } func isIndefiniteTermination(ber []byte, offset int) (bool, error) { - if len(ber) - offset < 2 { + if len(ber)-offset < 2 { return false, errors.New("ber2der: Invalid BER format") } diff --git a/internal/x509util/x509util.go b/internal/x509util/x509util.go index 5eca640..f4f4f11 100644 --- a/internal/x509util/x509util.go +++ b/internal/x509util/x509util.go @@ -55,6 +55,30 @@ func SignatureAlgorithmDetailsForOid(oid asn1.ObjectIdentifier) (x509.SignatureA fmt.Errorf("could not find SignatureAlgorithm details for oid: %s", oid) } +// SignatureAlgorithmDetailsForOid returns a matching SignatureAlgorithm and +// crypto.Hash function from a provided oid. +func SignatureAlgorithmDetailsForOidPair(oidSig, oidEnc asn1.ObjectIdentifier) (x509.SignatureAlgorithm, crypto.Hash, error) { + algo, hash, err := SignatureAlgorithmDetailsForOid(oidSig) + if err == nil { + return algo, hash, err + } + + switch { + case oidEnc.Equal(oidRSA): + switch { + case oidSig.Equal(oidSHA256): + return x509.SHA256WithRSA, crypto.SHA256, nil + case oidSig.Equal(oidSHA384): + return x509.SHA384WithRSA, crypto.SHA384, nil + case oidSig.Equal(oidSHA512): + return x509.SHA512WithRSA, crypto.SHA512, nil + } + } + + return x509.UnknownSignatureAlgorithm, crypto.Hash(0), + fmt.Errorf("could not find SignatureAlgorithm details for oids: %s, %s", oidSig, oidEnc) +} + // SigningParamsForPublicKey returns the parameters to use for signing. // If requestedSigAlgo is not zero then it overrides the default // signature algorithm. @@ -139,6 +163,8 @@ var ( oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3} oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4} + oidRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} + oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1} oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2} oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3} diff --git a/pkcs7.go b/pkcs7.go index 8a96146..197a19c 100644 --- a/pkcs7.go +++ b/pkcs7.go @@ -121,6 +121,10 @@ type signerInfo struct { UnauthenticatedAttributes []attribute `asn1:"optional,tag:1"` } +func (si *signerInfo) SignatureAlgorithmDetails() (x509.SignatureAlgorithm, crypto.Hash, error) { + return x509util.SignatureAlgorithmDetailsForOidPair(si.DigestAlgorithm.Algorithm, si.DigestEncryptionAlgorithm.Algorithm) +} + // Parse decodes a DER encoded PKCS7 package func Parse(data []byte) (p7 *PKCS7, err error) { if len(data) == 0 { @@ -225,6 +229,22 @@ func (p7 *PKCS7) Verify() (err error) { func verifySignature(p7 *PKCS7, signer signerInfo) error { signedData := p7.Content + + var algo x509.SignatureAlgorithm + var hash crypto.Hash + var err error + + oid := signer.DigestAlgorithm.Algorithm + if oid.Equal(oidDigestAlgorithmSHA1) || oid.Equal(oidISOSignatureSHA1WithRSA) { + algo = x509.SHA1WithRSA + hash = crypto.SHA1 + } else { + algo, hash, err = signer.SignatureAlgorithmDetails() + if err != nil { + return err + } + } + if len(signer.AuthenticatedAttributes) > 0 { // TODO(fullsailor): First check the content type match var digest []byte @@ -232,10 +252,6 @@ func verifySignature(p7 *PKCS7, signer signerInfo) error { if err != nil { return err } - hash, err := getHashForOID(signer.DigestAlgorithm.Algorithm) - if err != nil { - return err - } h := hash.New() if _, err := h.Write(p7.Content); err != nil { return err @@ -254,23 +270,12 @@ func verifySignature(p7 *PKCS7, signer signerInfo) error { return err } } + cert := getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber) if cert == nil { return errors.New("pkcs7: No certificate for signer") } - oid := signer.DigestAlgorithm.Algorithm - var algo x509.SignatureAlgorithm - switch { - case oid.Equal(oidDigestAlgorithmSHA1): - algo = x509.SHA1WithRSA - default: - var err error - algo, _, err = x509util.SignatureAlgorithmDetailsForOid(oid) - if err != nil { - return err - } - } return cert.CheckSignature(algo, signedData, signer.EncryptedDigest) }